Overall Statistics |
Total Trades 19 Average Win 3.30% Average Loss -3.46% Compounding Annual Return 9.631% Drawdown 9.400% Expectancy 0.085 Net Profit 9.659% Sharpe Ratio 0.525 Probabilistic Sharpe Ratio 28.912% Loss Rate 44% Win Rate 56% Profit-Loss Ratio 0.95 Alpha 0.083 Beta 0.071 Annual Standard Deviation 0.185 Annual Variance 0.034 Information Ratio -0.313 Tracking Error 0.336 Treynor Ratio 1.376 Total Fees $34.41 Estimated Strategy Capacity $890000000.00 |
from collections import deque class AdaptableSkyBlueHornet(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 1, 1) self.SetEndDate(2021, 1, 1) self.SetCash(100000) self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol # self.sma = self.SMA(self.spy, 30, Resolution.Daily) # History warm up for shortcut helper SMA indicator # closing_prices = self.History(self.spy, 30, Resolution.Daily)["close"] # for time, price in closing_prices.loc[self.spy].items(): # self.sma.Update(time, price) # Custom SMA indicator self.sma = CustomSimpleMovingAverage("CustomSMA", 30) self.RegisterIndicator(self.spy, self.sma, Resolution.Daily) def OnData(self, data): if not self.sma.IsReady: return # Save high, low, and current price hist = self.History(self.spy, timedelta(365), Resolution.Daily) low = min(hist["low"]) high = max(hist["high"]) price = self.Securities[self.spy].Price # Go long if near high and uptrending if price * 1.05 >= high and self.sma.Current.Value < price: if not self.Portfolio[self.spy].IsLong: self.SetHoldings(self.spy, 1) # Go short if near low and downtrending elif price * 0.95 <= low and self.sma.Current.Value > price: if not self.Portfolio[self.spy].IsShort: self.SetHoldings(self.spy, -1) # Otherwise, go flat else: self.Liquidate() self.Plot("Benchmark", "52w-High", high) self.Plot("Benchmark", "52w-Low", low) self.Plot("Benchmark", "SMA", self.sma.Current.Value) class CustomSimpleMovingAverage(PythonIndicator): def __init__(self, name, period): self.Name = name self.Time = datetime.min self.Value = 0 self.queue = deque(maxlen=period) def Update(self, input): self.queue.appendleft(input.Close) self.Time = input.EndTime count = len(self.queue) self.Value = sum(self.queue) / count # returns true if ready return (count == self.queue.maxlen)