| Overall Statistics |
|
Total Orders 47981 Average Win 0.02% Average Loss -0.01% Compounding Annual Return 32.954% Drawdown 24.700% Expectancy 0.522 Start Equity 1000000 End Equity 23102628.85 Net Profit 2210.263% Sharpe Ratio 1.136 Sortino Ratio 1.046 Probabilistic Sharpe Ratio 71.778% Loss Rate 30% Win Rate 70% Profit-Loss Ratio 1.17 Alpha 0.159 Beta 0.693 Annual Standard Deviation 0.188 Annual Variance 0.035 Information Ratio 0.822 Tracking Error 0.165 Treynor Ratio 0.309 Total Fees $442593.74 Estimated Strategy Capacity $140000.00 Lowest Capacity Asset QLD TJNNZWL5I4IT Portfolio Turnover 10.09% Drawdown Recovery 628 |
from AlgorithmImports import *
from datetime import timedelta
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import *
import numpy as np
from Risk.TrailingStopRiskManagementModel import TrailingStopRiskManagementModel
from Execution.StandardDeviationExecutionModel import StandardDeviationExecutionModel
class Two_2Algorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2015, 1, 1)
self.SetCash(1_000_000)
self.SetBrokerageModel(AlphaStreamsBrokerageModel())
self.SetTimeZone("America/New_York")
self.tickers = ["QLD", "PSQ", "QID"]
self.symbols = []
self._benchmark_symbol = self.AddEquity("SPY", Resolution.Minute).Symbol
self.reference = self.AddEquity("SQQQ", Resolution.Minute).Symbol
self.lookback = 18
for t in self.tickers:
s = self.AddEquity(t, Resolution.Minute).Symbol
self.symbols.append(s)
if t == "QLD":
self.qld = s
self.park_ticker = "JPST"
self.park = self.AddEquity(self.park_ticker, Resolution.Minute).Symbol
self.Schedule.On(
self.DateRules.WeekStart(self._benchmark_symbol),
self.TimeRules.AfterMarketOpen(self._benchmark_symbol, 10),
self.Rebalance
)
self.SetRiskManagement(CompositeRiskManagementModel(
MaximumUnrealizedProfitPercentPerSecurity(0.1325),
TrailingStopRiskManagementModel(0.0735)
))
self.SetExecution(StandardDeviationExecutionModel(40, 1.25, Resolution.Minute))
self.SetWarmUp(timedelta(hours=4))
self.started = False
self.last_rebalance = None
self._was_qld_invested = False
def OnData(self, data):
if not self.started and not self.IsWarmingUp and data.Bars.Count:
self.Rebalance()
self.started = True
for d in data.Delistings:
if d.Key in self.symbols:
self.symbols.remove(d.Key)
if self.IsWarmingUp:
return
qld_now = self.Portfolio[self.qld].Invested
if self._was_qld_invested and not qld_now:
if len(self.Transactions.GetOpenOrders()) == 0:
if not self.Portfolio[self.park].Invested:
self.SetHoldings(self.park, 0.99)
self._was_qld_invested = qld_now
def RegressionScore(self, a, b):
a = np.diff(a) / a[:-1]
b = np.diff(b) / b[:-1]
x = np.vstack([a, np.ones(len(a))]).T
return float(np.linalg.lstsq(x, b, rcond=None)[0][1])
def _LiquidateAllExcept(self, keep_symbol=None):
for holding in self.Portfolio.Values:
if holding.Invested and (keep_symbol is None or holding.Symbol != keep_symbol):
self.Liquidate(holding.Symbol)
def Rebalance(self):
today = self.Time.date()
if self.last_rebalance == today:
return
self.last_rebalance = today
h = self.History(self.symbols + [self.reference], self.lookback, Resolution.Daily)
if h.empty:
return
scores = []
for s in self.symbols:
try:
px = h.loc[s]["open"].values
ref = h.loc[self.reference]["open"].values
except KeyError:
continue
if len(px) < 3 or len(px) != len(ref):
continue
scores.append((s, self.RegressionScore(px, ref)))
if not scores:
return
scores.sort(key=lambda x: x[1], reverse=True)
leader = scores[0][0]
if leader == self.qld:
if self.Portfolio[self.park].Invested:
self.Liquidate(self.park)
self._LiquidateAllExcept(keep_symbol=self.qld)
self.SetHoldings(self.qld, 0.99)
else:
if self.Portfolio[self.qld].Invested:
self.Liquidate(self.qld)
self._LiquidateAllExcept(keep_symbol=self.park)
self.SetHoldings(self.park, 0.99)