| Overall Statistics |
|
Total Trades 100 Average Win 4.23% Average Loss -2.56% Compounding Annual Return 44.875% Drawdown 44.000% Expectancy 0.191 Net Profit 45.022% Sharpe Ratio 0.954 Probabilistic Sharpe Ratio 40.172% Loss Rate 55% Win Rate 45% Profit-Loss Ratio 1.65 Alpha 0.512 Beta -0.503 Annual Standard Deviation 0.448 Annual Variance 0.201 Information Ratio 0.436 Tracking Error 0.597 Treynor Ratio -0.85 Total Fees $539.07 Estimated Strategy Capacity $980000.00 Lowest Capacity Asset OIH V2LT3QH97TYD |
class SmoothBlueGuanaco(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 1, 1) # Set Start Date
self.SetEndDate(2021,1,1)
self.SetCash(100000) # Set Strategy Cash
self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol
self.data = {}
self.closingPrices = {}
self.symbols = ["SPY", "IGV", "XLE", "VNQ", "XLF", "XME", "XHB", "TBT", "KWEB", "OIH","XBI"]
for symbol in self.symbols:
self.AddEquity(symbol, Resolution.Daily)
self.data[symbol] = self.MOM(symbol, 30, Resolution.Daily)
self.closingPrices[symbol] = self.Identity(symbol, Resolution.Daily, Field.Close)
self.Log("{} symbol:{} closingPrice:{}".format(self.Time, symbol, self.closingPrices[symbol]))
self.Schedule.On(self.DateRules.Every(DayOfWeek.Friday), self.TimeRules.AfterMarketOpen("SPY",180), self.Rebalance) # Rebalances at 12:30 EST
self.Schedule.On(self.DateRules.On(2022, 5, 31), self.TimeRules.AfterMarketOpen("SPY", 150), self.Rebalance)
self.Settings.FreePortfolioValuePercentage=0
self.Leverage=1.4
self.assetsToHoldLong=2 # number of assets to hold long in portfolio
self.assetsToHoldShort=2 # number of assets to hold short in portfolio
def OnData(self, data: Slice):
if self.IsWarmingUp: return
#self.Debug("{} Entered OnData".format(self.Time))
for symbol in self.symbols:
if data.Bars.ContainsKey(symbol) and data.Bars[symbol] is not None:
self.closingPrices[symbol] = data.Bars[symbol].Close
for symbol in self.symbols:
self.Plot('closingPrices', symbol, self.closingPrices[symbol])
def Rebalance(self):
topLong = pd.Series(self.data).sort_values(ascending = False)[:self.assetsToHoldLong]
topShort = pd.Series(self.data).sort_values(ascending = True)[:self.assetsToHoldShort]
#self.Debug("{} Entering Rebalance with topLong:{}".format(self.Time, topLong ))
#self.Debug("{} Entering Rebalance with topShort:{}".format(self.Time, topShort ))
for kvp in self.Portfolio:
security_key = kvp.Key
security_hold = kvp.Value
# liquidate the security which is no longer in the top3 momentum list
if security_hold.Invested and self.Portfolio[security_key].Quantity > 1 :
# For longs, liquidate position if momentum drops below 1
#self.Debug("Entered long")
if (security_hold.Symbol.Value not in topLong.index or (security_hold.Invested and self.data[security_hold.Symbol.Value].Current.Value < 2)):
#self.Debug("{} Elim Long pos {} @{} Qty:{} MOM:{}".format(self.Time, security_hold, self.closingPrices.get(security_hold.Symbol, "None"),self.Portfolio[security_key].Quantity, self.data[security_hold.Symbol.Value].Current.Value))
self.Liquidate(security_hold.Symbol)
elif security_hold.Invested and self.Portfolio[security_key].Quantity < 1 :
#self.Debug("Entered Short")
if security_hold.Symbol.Value not in topShort.index or (security_hold.Invested and (self.data[security_hold.Symbol.Value].Current.Value > -2)):
# For longs, liquidate position if momentum drops below 1
#self.Debug("{} Elim Short pos {} @{} Qty:{} MOM:{}".format(self.Time, security_hold, self.closingPrices.get(security_hold.Symbol, "None"), self.Portfolio[security_key].Quantity, self.data[security_hold.Symbol.Value].Current.Value))
self.Liquidate(security_hold.Symbol)
# Buy top long stocks
added_symbolsLong = []
for symbol in topLong.index:
self.Debug("{} TOP LONG Symbol:{} Mom:{} Close:{}".format(self.Time, symbol, self.data[symbol].Current.Value, self.closingPrices[symbol]))
if not self.Portfolio[symbol].Invested and self.data[symbol].Current.Value > 1:
added_symbolsLong.append(symbol)
# Sell top short stocks
added_symbolsShort = []
for symbol in topShort.index:
self.Debug("{} TOP SHORT Symbol:{} Mom:{} Close:{}".format(self.Time, symbol, self.data[symbol].Current.Value, self.closingPrices[symbol]))
if not self.Portfolio[symbol].Invested and self.data[symbol].Current.Value < -1:
added_symbolsShort.append(symbol)
added_symbols = added_symbolsLong+added_symbolsShort
count = 0
for added in added_symbolsLong:
lastPrice = self.closingPrices[added]
if not self.closingPrices[added] ==0:
sharesToBuy= (self.Portfolio.MarginRemaining*self.Leverage) / (len(added_symbols)-count) // lastPrice
self.Debug("{} Shares to buy Symbol:{} Close:{} RemMargin:{:.2f} shares:{}"
.format(self.Time, added, lastPrice , self.Portfolio.MarginRemaining, sharesToBuy))
self.MarketOrder(added, sharesToBuy)
count =+1
for added in added_symbolsShort:
lastPrice = self.closingPrices[added]
sharesToBuy= - (self.Portfolio.MarginRemaining*self.Leverage) / (len(added_symbols)-count) // lastPrice
self.Debug("{} Shares to sell Symbol:{} Close:{} RemMargin:{:.2f} shares:{}"
.format(self.Time, added, lastPrice , self.Portfolio.MarginRemaining, sharesToBuy))
self.MarketOrder(added, sharesToBuy)