Overall Statistics
Total Orders
75651
Average Win
0.02%
Average Loss
-0.02%
Compounding Annual Return
17.894%
Drawdown
6.600%
Expectancy
0.292
Start Equity
1000000
End Equity
6273642.12
Net Profit
527.364%
Sharpe Ratio
1.224
Sortino Ratio
1.869
Probabilistic Sharpe Ratio
98.547%
Loss Rate
38%
Win Rate
62%
Profit-Loss Ratio
1.09
Alpha
0.08
Beta
0.246
Annual Standard Deviation
0.08
Annual Variance
0.006
Information Ratio
0.169
Tracking Error
0.132
Treynor Ratio
0.401
Total Fees
$107860.60
Estimated Strategy Capacity
$920000.00
Lowest Capacity Asset
UVXY V0H08FY38ZFP
Portfolio Turnover
25.03%
Drawdown Recovery
350
from AlgorithmImports import *
from datetime import timedelta
from collections import deque

class Algo(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2015, 1, 1)
        self.SetCash(1000000)

        self.uvxy = self.AddEquity("UVXY", Resolution.Minute).Symbol
        self.qqq  = self.AddEquity("QQQ",  Resolution.Minute).Symbol

        self.SetBenchmark("SPY")
        self.benchmark_symbol = self.qqq

        self.uvxy_daily_window = deque(maxlen=2)
        self.Consolidate(self.uvxy, Resolution.Daily, self.UvxyDailyHandler)

        self.qqq_sma_fast = self.SMA(self.qqq, 11, Resolution.Daily)
        self.qqq_sma_slow = self.SMA(self.qqq, 160, Resolution.Daily)

        self.mod_bull = 1.10
        self.mod_bear = 0.80

        self.SetPortfolioConstruction(InsightWeightingPortfolioConstructionModel())
        self.SetExecution(StandardDeviationExecutionModel(4.0, 1.5, Resolution.Minute))
        self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.0332))

        self.Schedule.On(
            self.DateRules.EveryDay(self.uvxy),
            self.TimeRules.AfterMarketOpen(self.uvxy, 10),
            self.ExitPositions
        )

        self.SetWarmUp(160, Resolution.Daily)
        self.started = False


    def OnData(self, data: Slice):

        if len(self.uvxy_daily_window) < 2:
            return

        if self.Time.hour != 9 or self.Time.minute != 31:
            return

        if not data.ContainsKey(self.uvxy):
            return

        if not (self.qqq_sma_fast.IsReady and self.qqq_sma_slow.IsReady):
            return

        uvxy_bar = data[self.uvxy]
        prev_daily_close = float(self.uvxy_daily_window[-1].Close)

        modifier = self.mod_bull if self.qqq_sma_fast.Current.Value > self.qqq_sma_slow.Current.Value else self.mod_bear

        short_w = -0.75 * modifier
        long_w  =  0.30 * modifier

        short_w = max(-0.99, min(-0.01, short_w))
        long_w  = max( 0.01, min( 0.99, long_w))

        if uvxy_bar.Open >= 1.093 * prev_daily_close:
            self.SetHoldings(self.uvxy, short_w)
        elif uvxy_bar.Open <= 0.982 * prev_daily_close:
            self.SetHoldings(self.uvxy, long_w)

        if not self.Portfolio.Invested:
            self.EmitInsights(
                Insight.Price(self.benchmark_symbol, timedelta(days=3),
                              InsightDirection.Up, weight=0.5, tag="rebalance")
            )

        if (not self.started) and (not self.IsWarmingUp) and (len(data.Bars) > 0):
            self.started = True


    def UvxyDailyHandler(self, bar: TradeBar):
        self.uvxy_daily_window.append(bar)


    def ExitPositions(self):
        self.Liquidate(self.uvxy, tag="Morning exit")