| Overall Statistics |
|
Total Orders 5165 Average Win 0.66% Average Loss -0.37% Compounding Annual Return 53.415% Drawdown 20.700% Expectancy 0.402 Start Equity 1000000 End Equity 48062947.29 Net Profit 4706.295% Sharpe Ratio 1.781 Sortino Ratio 2.223 Probabilistic Sharpe Ratio 99.383% Loss Rate 50% Win Rate 50% Profit-Loss Ratio 1.79 Alpha 0.278 Beta 0.707 Annual Standard Deviation 0.191 Annual Variance 0.036 Information Ratio 1.55 Tracking Error 0.163 Treynor Ratio 0.48 Total Fees $1457542.85 Estimated Strategy Capacity $420000.00 Lowest Capacity Asset UVXY V0H08FY38ZFP Portfolio Turnover 40.85% Drawdown Recovery 301 |
from AlgorithmImports import *
from QuantConnect.Indicators import CommodityChannelIndex
STOCK = "UVXY"
HEDGE = "TQQQ"
PERIOD = 270
PERIOD2 = 6
PERIOD4 = 70
class IntradayVolatilityRegimeHarvester(QCAlgorithm):
UVXY_WEIGHT = 0.745
SIGNAL_CODES = {
"TRADE_1_LONG": 1,
"TRADE_2_EXIT": 2,
"TRADE_3_LONG": 3,
"TRADE_4_FLATTEN": -4,
"TRADE_4_EXIT": 4,
"TRADE_5_LONG": 5,
"TRADE_6_LONG": 6,
"TRADE_7_FORCED_EXIT": 9
}
def Initialize(self):
self.SetStartDate(2017, 1, 1)
self.SetCash(1000000)
self.uvxy = self.AddEquity(STOCK, Resolution.Minute).Symbol
self.tqqq = self.AddEquity(HEDGE, Resolution.Minute).Symbol
self.tqqq_w_default = 0.25
self.tqqq_w_trade3 = 0.15
self.tqqq_w_trade5 = 0.05
self.tqqq_w_trade6 = 0.25
self.max_high = self.MAX(self.uvxy, PERIOD, Resolution.Minute, Field.High)
self.min_low = self.MIN(self.uvxy, PERIOD, Resolution.Minute, Field.Low)
self.min_open = self.MIN(self.uvxy, PERIOD, Resolution.Minute, Field.Open)
self.min_close = self.MIN(self.uvxy, PERIOD, Resolution.Minute, Field.Close)
self.max_high_short = self.MAX(self.uvxy, PERIOD2, Resolution.Minute, Field.High)
self.min_low_short = self.MIN(self.uvxy, PERIOD2, Resolution.Minute, Field.Low)
self.cci = CommodityChannelIndex(PERIOD4)
self.RegisterIndicator(self.uvxy, self.cci, Resolution.Minute)
self.SetWarmUp(PERIOD, Resolution.Minute)
self.SetPortfolioConstruction(InsightWeightingPortfolioConstructionModel(lambda _: None))
self.SetExecution(ImmediateExecutionModel())
self.AddChart(Chart("Signals"))
self.Schedule.On(self.DateRules.EveryDay(self.uvxy), self.TimeRules.AfterMarketOpen(self.uvxy, 7), self.trade_1)
self.Schedule.On(self.DateRules.EveryDay(self.uvxy), self.TimeRules.AfterMarketOpen(self.uvxy, 44), self.trade_2_exit)
self.Schedule.On(self.DateRules.EveryDay(self.uvxy), self.TimeRules.AfterMarketOpen(self.uvxy, 60), self.trade_3)
self.Schedule.On(self.DateRules.EveryDay(self.uvxy), self.TimeRules.AfterMarketOpen(self.uvxy, 100), self.trade_4_flatten)
self.Schedule.On(self.DateRules.EveryDay(self.uvxy), self.TimeRules.AfterMarketOpen(self.uvxy, 255), self.trade_4_exit)
self.Schedule.On(self.DateRules.EveryDay(self.uvxy), self.TimeRules.AfterMarketOpen(self.uvxy, 255), self.trade_5)
self.Schedule.On(self.DateRules.EveryDay(self.uvxy), self.TimeRules.BeforeMarketClose(self.uvxy, 55), self.trade_6)
self.Schedule.On(self.DateRules.EveryDay(self.uvxy), self.TimeRules.BeforeMarketClose(self.uvxy, 1), self.trade_7_forced_exit)
self.SetRiskManagement(MaximumUnrealizedProfitPercentPerSecurity(0.067))
def _log(self, tag, uvxy_weight, tqqq_weight):
self.Log(f"{self.Time} | {tag} | UVXY_w={uvxy_weight} | TQQQ_w={tqqq_weight}")
self.Plot("Signals", "code", self.SIGNAL_CODES[tag])
def _set_alloc(self, uvxy_weight, tqqq_weight):
if uvxy_weight == 0:
self.Liquidate(STOCK)
else:
self.SetHoldings(STOCK, uvxy_weight)
self.SetHoldings(HEDGE, tqqq_weight)
def trade_1(self):
if (self.max_high.Current.Value > self.min_low.Current.Value * 1.0845 and
self.max_high.Current.Value / self.min_low.Current.Value < 1.25 and
self.min_open.Current.Value * 0.998 < self.min_low_short.Current.Value):
self._log("TRADE_1_LONG", self.UVXY_WEIGHT, self.tqqq_w_default)
self._set_alloc(self.UVXY_WEIGHT, self.tqqq_w_default)
def trade_2_exit(self):
if self.Portfolio[STOCK].Invested:
self._log("TRADE_2_EXIT", 0, self.tqqq_w_default)
self._set_alloc(0, self.tqqq_w_default)
def trade_3(self):
if (self.max_high.Current.Value > self.min_low.Current.Value * 1.22 and
self.max_high.Current.Value / self.min_low.Current.Value < 1.2625 and
self.min_open.Current.Value * 1.005 < self.min_low_short.Current.Value):
self._log("TRADE_3_LONG", self.UVXY_WEIGHT, self.tqqq_w_trade3)
self._set_alloc(self.UVXY_WEIGHT, self.tqqq_w_trade3)
def trade_4_flatten(self):
if (self.max_high.Current.Value < self.min_low.Current.Value * 1.0253 and
self.min_close.Current.Value < self.min_low_short.Current.Value and
self.cci.Current.Value < 70):
if self.Portfolio[STOCK].Invested:
self._log("TRADE_4_FLATTEN", 0, self.tqqq_w_default)
self._set_alloc(0, self.tqqq_w_default)
def trade_4_exit(self):
if self.Portfolio[STOCK].Invested:
self._log("TRADE_4_EXIT", 0, self.tqqq_w_default)
self._set_alloc(0, self.tqqq_w_default)
def trade_5(self):
if (self.max_high.Current.Value > self.min_low.Current.Value * 1.22 and
self.max_high.Current.Value / self.min_low.Current.Value < 1.255 and
self.cci.Current.Value > -80):
self._log("TRADE_5_LONG", self.UVXY_WEIGHT, self.tqqq_w_trade5)
self._set_alloc(self.UVXY_WEIGHT, self.tqqq_w_trade5)
def trade_6(self):
if (self.max_high.Current.Value < self.min_low.Current.Value * 1.0275 and
self.min_open.Current.Value < self.min_low_short.Current.Value and
self.Securities[self.uvxy].Price < self.max_high.Current.Value and
self.cci.Current.Value > -150):
self._log("TRADE_6_LONG", self.UVXY_WEIGHT, self.tqqq_w_trade6)
self._set_alloc(self.UVXY_WEIGHT, self.tqqq_w_trade6)
def trade_7_forced_exit(self):
if self.Portfolio[STOCK].Invested:
self._log("TRADE_7_FORCED_EXIT", 0, self.tqqq_w_default)
self._set_alloc(0, self.tqqq_w_default)