| Overall Statistics |
|
Total Trades 59 Average Win 3.83% Average Loss -8.10% Compounding Annual Return 7.746% Drawdown 34.200% Expectancy 0.168 Net Profit 50.793% Sharpe Ratio 0.475 Probabilistic Sharpe Ratio 8.375% Loss Rate 21% Win Rate 79% Profit-Loss Ratio 0.47 Alpha 0.095 Beta -0.158 Annual Standard Deviation 0.163 Annual Variance 0.027 Information Ratio -0.134 Tracking Error 0.254 Treynor Ratio -0.49 Total Fees $150.14 |
from statsmodels.regression.linear_model import OLS
import numpy as np
class DynamicModulatedCoreWave(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2015, 2, 27) # Set Start Date
self.SetCash(100000) # Set Strategy Cash
self.sym = self.AddEquity('SPY', Resolution.Daily).Symbol
self.nth_trading_day = 0
self.day = RollingWindow[int](50)
self.data = RollingWindow[float](50)
self.model = None
self.SetWarmup(50)
def OnData(self, data):
if not data.ContainsKey(self.sym) or data[self.sym] is None:
return
close = data[self.sym].Close
self.nth_trading_day += 1
if self.model is not None and not self.Portfolio.Invested:
# Making it explicit with kwargs so I don't screw up the function call
if self.model.is_hold(y=close, x=self.nth_trading_day):
self.SetHoldings(self.sym, 1)
else:
self.reset()
elif self.model is not None and self.Portfolio.Invested:
if not self.model.is_hold(y=close, x=self.nth_trading_day):
self.reset()
self.day.Add(self.nth_trading_day)
self.data.Add(close)
if not self.day.IsReady or not self.data.IsReady:
return
if self.model is None:
model = Model(list(self.data)[::-1], list(self.day)[::-1])
if model.useable():
self.model = model
def reset(self):
self.Liquidate()
self.nth_trading_day = 0
self.model = None
class Model:
def __init__(self, y, x):
model = OLS(y, x)
self.ols = model.fit()
self.slope = self.ols.params[0]
self.r2 = self.ols.rsquared
self.mean_resid = np.abs(self.ols.resid).mean()
def useable(self, r2=.7):
return self.r2 > r2 and self.slope > 0
def is_hold(self, y, x):
return y + self.mean_resid > self.ols.predict(x)[0]