| 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)