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]