| Overall Statistics |
|
Total Trades 235 Average Win 0.51% Average Loss -1.09% Compounding Annual Return 10.825% Drawdown 19.100% Expectancy -0.076 Net Profit 10.825% Sharpe Ratio 0.506 Probabilistic Sharpe Ratio 28.262% Loss Rate 37% Win Rate 63% Profit-Loss Ratio 0.47 Alpha 0.145 Beta -0.107 Annual Standard Deviation 0.232 Annual Variance 0.054 Information Ratio -0.531 Tracking Error 0.263 Treynor Ratio -1.1 Total Fees $1318.32 |
import pandas as pd
class HighDebtUniverse(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019, 1, 1)
self.SetEndDate(2020, 1, 1)
self.SetCash(100000)
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.CoarseSelectionFunction, self.SelectFine)
self.SetBrokerageModel(InteractiveBrokersBrokerageModel())
self.SetExecution(ImmediateExecutionModel())
self.AddEquity("SPY",Resolution.Daily).Symbol
self.Fast = SimpleMovingAverage("SPY",10)
self.Slow = SimpleMovingAverage("SPY", 100)
self.stops = {} # Keep track of stop loss orders so we can update them
self.stoplevel=0.70
self.FirstFilter = 60
self.SecondFilter = 5
self.WeekDay = 3
self.numberOfSymbolsCoarse = 4000
self.numberOfSymbolsFine = 3000
self.dollarVolumeBySymbol = {}
def CoarseSelectionFunction(self, coarse):
selected = []
if datetime.weekday(self.Time) != self.WeekDay:
return Universe.Unchanged
sortedByDollarVolume = sorted([x for x in coarse if x.HasFundamentalData and x.DollarVolume > 3000000 and x.Price >0],
key = lambda x: x.DollarVolume, reverse=True)[:self.numberOfSymbolsCoarse]
self.dollarVolumeBySymbol = {x.Symbol:x.DollarVolume for x in sortedByDollarVolume}
return list(self.dollarVolumeBySymbol.keys())
def SelectFine(self, fine):
if datetime.weekday(self.Time) != self.WeekDay:
return Universe.Unchanged
DERatio = lambda x: x.OperationRatios.LongTermDebtEquityRatio.ThreeMonths
fine = ([x for x in fine if DERatio(x) and x.CompanyReference.CountryId == "USA"
and x.CompanyReference.PrimaryExchangeID in ["NYS","NAS"]
and (self.Time - x.SecurityReference.IPODate).days > 180 and x.MarketCap > 3e8])
if len(fine) == 0:
return Universe.Unchanged
sortedByDEratio = sorted(fine, key=DERatio, reverse=True)[:self.FirstFilter]
symbols = [x.Symbol for x in sortedByDEratio]
averages = dict()
history = self.History(symbols, 200, Resolution.Daily).close.unstack(0)
for symbol in symbols:
if symbol in history:
df = history[symbol].dropna()
if df.empty or len(df)<130:
continue
mom=df[:-2].pct_change(126) .iloc[-1]
if pd.notnull(mom):
averages[symbol] = mom
sortedbyMomentum = sorted(averages.items(), key=lambda x: x[1], reverse=True)
#for x, mom in sortedbyMomentum[:5]:
#self.Log('Post -sort: symbol' + " " + str(x.Value) +" "'mom' + " " + str(mom))
return [x[0] for x in sortedbyMomentum[:self.SecondFilter]]
def OnSecuritiesChanged(self, changes):
if datetime.weekday(self.Time) != self.WeekDay:
return Universe.Unchanged
result = {}
history = self.History(["SPY"], 110, Resolution.Daily)
for time, row in history.loc["SPY"].iterrows():
self.Fast.Update(time, row["close"])
self.Slow.Update(time, row["close"])
trend = self.Fast.Current.Value >= self.Slow.Current.Value
count = self.SecondFilter
percent = 0 if count == 0 else 1 / (count)
for instrument in changes.AddedSecurities:
#self.Log('AddedSecurities' + " " + str(instrument)+ " " + str(instrument.Symbol.Value))
if(trend) and (not instrument.Symbol.Value == "SPY"):
result[instrument.Symbol] = percent
#if (not self.Portfolio[security.Symbol].Invested) and not trend:
else:
result[instrument.Symbol]=0
invested = [ x.Symbol for x in self.Portfolio.Values if x.Invested]
test = [x for x in self.Portfolio.Values]
for stock in invested:
#self.Log('Invested' + " " + str(stock)+ " " + str(stock.Value))
a=self.Portfolio[stock].HoldingsValue
b=self.Portfolio.TotalPortfolioValue
exisiting_pcnt=a/b
#result[stock] = exisiting_pcnt
result[stock] = percent
for share in changes.RemovedSecurities:
#self.Log('RemovedSecurities' + " " + str(share)+ " " + str(share.Symbol.Value))
result.pop(share.Symbol, None)
if share.Invested:
self.Liquidate(share.Symbol)
if sum(result.values())>1:
stocks_norm = 1/sum(result.values())
for key, val in result.items():
new_val = val * stocks_norm
result[key]= new_val
#for key, val in result.items():
#self.Log('result' + " " + str(key)+ " " + str(val))
#for security in changes.RemovedSecurities:
#if security.Invested:
#CancelledOrders = self.Transactions.CancelOpenOrders(security.Symbol, "Weekly Liquidation")
#self.Liquidate(security.Symbol)
#self.Transactions.CancelOpenOrders()
for security in result:
self.SetHoldings(security, result[security])
#if trend:
#self.SetHoldings(security, 0.20)
# Set stop loss
#quantity = self.CalculateOrderQuantity(security, 0.2)
#if quantity>1:
#self.stops[security] = self.StopMarketOrder(security, -quantity, self.Portfolio[security].Price * self.stoplevel)
#updateSettings = UpdateOrderFields()
#updateSettings.Tag = "stopped out"
#self.stops[security].Update(updateSettings)
#else:
#self.SetHoldings(security, 0.00)