| Overall Statistics |
|
Total Trades 260 Average Win 2.30% Average Loss -1.23% Compounding Annual Return 47.275% Drawdown 31.600% Expectancy 0.313 Net Profit 66.903% Sharpe Ratio 1.36 Probabilistic Sharpe Ratio 55.938% Loss Rate 54% Win Rate 46% Profit-Loss Ratio 1.88 Alpha 0.496 Beta -0.157 Annual Standard Deviation 0.337 Annual Variance 0.114 Information Ratio 0.479 Tracking Error 0.459 Treynor Ratio -2.926 Total Fees $351.39 Estimated Strategy Capacity $19000000.00 |
import math
class NadionHorizontalFlange(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 1, 1)
#Cash to invest
self.SetCash(100000)
self.SetWarmUp(45)
self.totalTradable = 5
self.positionSize = 1/self.totalTradable
self.symbolDataBySymbol = {}
self.washTimer = {}
self.sellTimer = {}
self.buyPrice = {}
self.atrAtPurchase = {}
self.lastMonth = -1
self.AddUniverse(self.Coarse, self.Fine)
self.UniverseSettings.Resolution = Resolution.Daily
self.Schedule.On(self.DateRules.EveryDay(),
self.TimeRules.At(0, 0),
self.reduceWash)
self.Schedule.On(self.DateRules.EveryDay(),
self.TimeRules.At(0, 0),
self.reduceSellTimer)
def Coarse(self, coarse):
if self.Time.month == self.lastMonth:
return Universe.Unchanged
self.lastMonth = self.Time.month
sortedByVolume = sorted([x for x in coarse if x.Price > 5], key = lambda x: x.DollarVolume, reverse = True)
return [x.Symbol for x in sortedByVolume]
def Fine(self, fine):
sortedBySector = sorted([x for x in fine if x.CompanyReference.CountryId == "USA"
and x.CompanyReference.PrimaryExchangeID in ["NYS","NAS"]
and (self.Time - x.SecurityReference.IPODate).days > 180
and x.MarketCap > 3e8],
key = lambda x: x.CompanyReference.IndustryTemplateCode)
sortedBySector = sorted([x for x in sortedBySector], key = lambda x: x.MarketCap, reverse = True)[:50]
return [x.Symbol for x in sortedBySector]
def OnSecuritiesChanged(self, changes):
for x in changes.AddedSecurities:
symbol = x.Symbol
smaFast = self.SMA(symbol, 10, Resolution.Daily)
smaSlow = self.SMA(symbol, 20, Resolution.Daily)
atr = self.ATR(symbol, 45, Resolution.Daily)
history = self.History(symbol, 45, Resolution.Daily)
for tuple in history.loc[symbol].itertuples():
smaFast.Update(tuple.Index, tuple.close)
smaSlow.Update(tuple.Index, tuple.close)
symbolData = SymbolData(symbol, smaFast, smaSlow, atr)
self.symbolDataBySymbol[symbol] = symbolData
self.washTimer[symbol] = 0
self.sellTimer[symbol] = 0
def OnData(self, data):
if self.IsWarmingUp:
return
for symbol, symbolData in self.symbolDataBySymbol.items():
if self.washTimer[symbol] > 0:
continue
smaFast = symbolData.SMAFast
smaSlow = symbolData.SMASlow
atr = symbolData.ATR
if not self.Portfolio[symbol].Invested:
if smaFast.Current.Value > smaSlow.Current.Value:
self.SetHoldings(symbol, self.positionSize)
self.sellTimer[symbol] = 150
self.buyPrice[symbol] = self.Securities[symbol].Close
self.atrAtPurchase[symbol] = atr.Current.Value
if self.Portfolio[symbol].Invested:
if self.sellTimer[symbol] <= 0:
if (self.Portfolio[symbol].UnrealizedProfit < 0):
self.washTimer[symbol] = 31
self.Liquidate(symbol)
elif self.Securities[symbol].Close >= (self.buyPrice[symbol] + (4 * self.atrAtPurchase[symbol])):
if (self.Portfolio[symbol].UnrealizedProfit < 0):
self.washTimer[symbol] = 31
self.Liquidate(symbol)
elif self.Securities[symbol].Close <= (self.buyPrice[symbol] - (2 * self.atrAtPurchase[symbol])):
if (self.Portfolio[symbol].UnrealizedProfit < 0):
self.washTimer[symbol] = 31
self.Liquidate(symbol)
def reduceWash(self):
for symbol, count in self.washTimer.items():
if count > 0:
self.washTimer[symbol] -= 1
def reduceSellTimer(self):
for symbol, count in self.sellTimer.items():
if count > 0:
self.sellTimer[symbol] -= 1
class SymbolData:
def __init__(self, symbol, smaFast, smaSlow, atr):
self.SMAFast = smaFast
self.SMASlow = smaSlow
self.ATR = atr