| Overall Statistics |
|
Total Trades 525 Average Win 0.21% Average Loss -0.29% Compounding Annual Return 70.073% Drawdown 24.900% Expectancy -0.143 Net Profit 24.479% Sharpe Ratio 1.615 Probabilistic Sharpe Ratio 55.890% Loss Rate 50% Win Rate 50% Profit-Loss Ratio 0.70 Alpha 0 Beta 0 Annual Standard Deviation 0.449 Annual Variance 0.202 Information Ratio 1.615 Tracking Error 0.449 Treynor Ratio 0 Total Fees $525.00 Estimated Strategy Capacity $3400000.00 |
class TrialHighalgorithm(QCAlgorithm):
class SymbolData(object):
def __init__(self, symbol, algorithm):
self.Symbol = symbol
self.algorithm = algorithm # reference to the algorithm object so we can make a history call
# this is the buy property that we will use in OnData to filter the symbols that meet our criteria
self.buy = False
self.symbolSma = SimpleMovingAverage(200)
# init windows, most recent value is self.highs[0], second most recent is self.highs[1], etc...
self.highs = RollingWindow[float](252)
self.opens = RollingWindow[float](252)
self.closes = RollingWindow[float](252)
history = algorithm.History(symbol, 252, Resolution.Daily)
for index, row in history.loc[symbol].iterrows():
self.update(index, row["high"], row["open"], row["close"])
# update windows, sma
def update(self, time, high, opn, close):
self.highs.Add(high)
self.opens.Add(opn)
self.closes.Add(close)
self.symbolSma.Update(time, close)
# add [0] just so that list is not empty during initializing phase
self.buy = (max((list(self.highs) + [0])[1:]) < self.highs[0]) & (self.closes[0] > self.opens[0])
def Initialize(self):
self.SetStartDate(2020, 11, 1)
#self.SetEndDate(2020, 11, 11)
self.SetCash(10000)
self.numberOfSymbols = 200
self.res = Resolution.Daily
self.averages = {}
self.symbols = []
self.sma = {}
self.universe = {}
self.selectedSymbols = []
self.SPY = self.AddEquity('SPY', self.res).Symbol
self.SetTimeZone(TimeZones.HongKong)
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.AddUniverse(self.CoarseSelectionFunction)
self.UniverseSettings.Resolution = self.res
def CoarseSelectionFunction(self, coarse):
filtered = [ x for x in coarse if (x.HasFundamentalData) and (x.Price > 1) and ( x.Volume > 500000) and (x.DollarVolume > 100000) ]
filtered.sort(key=lambda x: x.DollarVolume, reverse=True)
symbols = [ x.Symbol for x in filtered[:self.numberOfSymbols] ]
for symbol in symbols:
if symbol not in self.universe:
self.universe[symbol] = TrialHighalgorithm.SymbolData(symbol, self)
self.sma[symbol] = self.universe[symbol].symbolSma
return list(self.universe.keys())
# this is called daily because our resolution is Resolution.Daily
def OnData(self, data):
# update all the securities in our universe using the latest hihg, open, close data
for symbol in self.universe.keys():
# make sure we have data, because sometimes we dont
if self.Securities.ContainsKey(symbol) and self.Securities[symbol] != None:
time = self.Time
high = self.Securities[symbol].High
opn = self.Securities[symbol].Open
close = self.Securities[symbol].Close
# update function
self.universe[symbol].update(time, high, opn, close)
# now select all the symbols that meet the buy criteria (this is the 'buy' property of our symboldata object)
self.selectedSymbols = [x for x in self.universe.keys() if self.universe[x].buy ]
for x in self.selectedSymbols:
self.SetHoldings(x, 0.01)