| Overall Statistics |
|
Total Orders 7680 Average Win 0.54% Average Loss -0.36% Compounding Annual Return 341.839% Drawdown 41.200% Expectancy 0.718 Start Equity 10000 End Equity 129752063.14 Net Profit 1297420.631% Sharpe Ratio 4.445 Sortino Ratio 5.723 Probabilistic Sharpe Ratio 100.000% Loss Rate 31% Win Rate 69% Profit-Loss Ratio 1.49 Alpha 1.929 Beta 1.496 Annual Standard Deviation 0.464 Annual Variance 0.215 Information Ratio 4.965 Tracking Error 0.397 Treynor Ratio 1.378 Total Fees $1187488.99 Estimated Strategy Capacity $0 Lowest Capacity Asset UVXY V0H08FY38ZFP Portfolio Turnover 21.24% Drawdown Recovery 100 |
from AlgorithmImports import *
class QuadEnsemble(QCAlgorithm):
"""
4-Way Equal-Weight Ensemble: T11 + T10 + S3 + S2 (25% each)
Each strategy runs its full independent logic on 25% of capital.
Overlapping positions are weight-summed before execution.
T11 — FeaverFrontrunner (XLK/KMLM switcher + 50/50 bear split)
T10 — SimonsKMLM (pure RSI cascade + XLK/KMLM switcher)
S3 — DailyRegimeRotation (3-of-4 SMA voting + RSI triggers)
S2 — HolyGrail (TQQQ 200-SMA gate + BSV defensive)
Thesis: All 4 survived 2024+ OOS with Calmar > 6. S3 has genuinely independent
signal (3-of-4 SMA vote). T10/T11 share XLK/KMLM logic but diverge in bear.
S2 adds hard TQQQ 200-SMA gate. Combined: bull agreement → amplified, bear
disagreement → partial hedge, overbought signals fire independently → layered UVXY.
"""
QUARTER = 0.25
SVIX_LIVE = datetime(2022, 3, 30)
UVIX_LIVE = datetime(2022, 3, 30)
_T10_LATE = {"KMLM", "LABU"}
_T11_LATE = {"KMLM"}
def initialize(self) -> None:
self.set_start_date(2020, 1, 1)
self.set_end_date(2026, 12, 31) # fixed end date — avoids clock/timezone non-reproducibility
self.set_cash(10_000)
self.set_brokerage_model(
BrokerageName.INTERACTIVE_BROKERS_BROKERAGE,
AccountType.MARGIN,
)
self.set_benchmark("SPY")
self.settings.minimum_order_margin_portfolio_percentage = 0.0
res = Resolution.DAILY
# ── Universe (deduplicated) ───────────────────────────────────────────
all_tickers = [
# T10/T11 shared
"TQQQ", "TECL", "SOXL", "SQQQ", "UVXY", "SVIX", "SVXY",
"XLK", "KMLM", "TLT",
# T10 overbought cascade
"QQQE", "VTV", "VOX", "VOOG", "VOOV", "XLP", "XLY", "FAS",
# T10 dip-buy
"SPXL", "LABU",
# T11 overbought
"SPY", "IOO", "VTV", "XLF",
# T11 bull
"TECS", "SOXS",
# T11 bear
"QQQ", "PSQ", "QLD", "BTAL", "BIL", "AGG", "SH", "BND", "IEF",
# S2 extras
"BSV",
# S3 extras
"SMH", "UVIX",
]
seen = set()
unique = [t for t in all_tickers if not (t in seen or seen.add(t))]
self._syms = {t: self.add_equity(t, res).symbol for t in unique}
# ── T10 indicators ────────────────────────────────────────────────────
def rsi10(t): return self.rsi(self._syms[t], 10, MovingAverageType.WILDERS, res)
self._t10_rsi = {t: rsi10(t) for t in [
"QQQE", "VTV", "VOX", "TECL", "VOOG", "VOOV", "XLP",
"TQQQ", "XLY", "FAS", "SPY",
"SOXL", "SPXL", "LABU", "XLK", "KMLM",
]}
# ── T11 indicators ────────────────────────────────────────────────────
self._t11_rsi10 = {t: rsi10(t) for t in [
"SPY", "IOO", "TQQQ", "VTV", "XLF",
"XLK", "KMLM", "PSQ", "BND", "QQQ", "IEF",
]}
def rsi20(t): return self.rsi(self._syms[t], 20, MovingAverageType.WILDERS, res)
self._t11_rsi20 = {t: rsi20(t) for t in ["TLT", "PSQ", "AGG"]}
self._t11_rsi60_sh = self.rsi(self._syms["SH"], 60, MovingAverageType.WILDERS, res)
self._t11_spy_sma200 = self.sma(self._syms["SPY"], 200, res)
self._t11_tqqq_sma20 = self.sma(self._syms["TQQQ"], 20, res)
self._t11_kmlm_sma20 = self.sma(self._syms["KMLM"], 20, res)
# ── S2 indicators ─────────────────────────────────────────────────────
self._s2_tqqq_sma200 = self.sma(self._syms["TQQQ"], 200, res)
self._s2_tqqq_sma20 = self.sma(self._syms["TQQQ"], 20, res)
self._s2_tqqq_rsi10 = rsi10("TQQQ")
self._s2_soxl_rsi10 = rsi10("SOXL")
self._s2_sqqq_rsi10 = rsi10("SQQQ")
self._s2_bsv_rsi10 = rsi10("BSV")
# ── S3 indicators ─────────────────────────────────────────────────────
self._s3_spy_sma202 = self.sma(self._syms["SPY"], 202, res)
self._s3_qqq_sma202 = self.sma(self._syms["QQQ"], 202, res)
self._s3_smh_sma202 = self.sma(self._syms["SMH"], 202, res)
self._s3_soxl_sma202 = self.sma(self._syms["SOXL"], 202, res)
def rsi8(t): return self.rsi(self._syms[t], 8, MovingAverageType.WILDERS, res)
def rsi15(t): return self.rsi(self._syms[t], 15, MovingAverageType.WILDERS, res)
self._s3_rsi_qqq8 = rsi8("QQQ")
self._s3_rsi_smh8 = rsi8("SMH")
self._s3_rsi_spy15 = rsi15("SPY")
self._s3_rsi_qqq15 = rsi15("QQQ")
self._s3_rsi_smh15 = rsi15("SMH")
self._s3_rsi_soxl15 = rsi15("SOXL")
self.set_warm_up(215, res)
self._trade_count = 0
self._last_label = ""
self.schedule.on(
self.date_rules.every_day(self._syms["SPY"]),
self.time_rules.after_market_open(self._syms["SPY"], 30),
self._rebalance,
)
# ── Readiness ──────────────────────────────────────────────────────────────
@property
def _t10_ready(self) -> bool:
core = [v for k, v in self._t10_rsi.items() if k not in self._T10_LATE]
return not self.is_warming_up and all(r.is_ready for r in core)
@property
def _t11_ready(self) -> bool:
core10 = [v for k, v in self._t11_rsi10.items() if k not in self._T11_LATE]
return (not self.is_warming_up
and self._t11_spy_sma200.is_ready
and self._t11_tqqq_sma20.is_ready
and all(r.is_ready for r in core10)
and all(r.is_ready for r in self._t11_rsi20.values())
and self._t11_rsi60_sh.is_ready)
@property
def _s2_ready(self) -> bool:
return (not self.is_warming_up
and self._s2_tqqq_sma200.is_ready
and self._s2_tqqq_sma20.is_ready
and self._s2_tqqq_rsi10.is_ready
and self._s2_soxl_rsi10.is_ready
and self._s2_sqqq_rsi10.is_ready
and self._s2_bsv_rsi10.is_ready)
@property
def _s3_ready(self) -> bool:
return (not self.is_warming_up
and self._s3_spy_sma202.is_ready
and self._s3_qqq_sma202.is_ready
and self._s3_smh_sma202.is_ready
and self._s3_soxl_sma202.is_ready
and self._s3_rsi_qqq8.is_ready
and self._s3_rsi_smh8.is_ready
and self._s3_rsi_spy15.is_ready
and self._s3_rsi_qqq15.is_ready
and self._s3_rsi_smh15.is_ready
and self._s3_rsi_soxl15.is_ready)
# ── T11 helpers ────────────────────────────────────────────────────────────
def _t11_bond_baller(self, r10, r20, tqqq_px, tqqq_sma) -> str:
if r20["TLT"] > r20["PSQ"]: return "QQQ"
if tqqq_px > tqqq_sma:
if r10["PSQ"] < 35: return "PSQ"
if r20["AGG"] > self._t11_rsi60_sh.current.value: return "TQQQ"
return "PSQ"
else:
if r10["IEF"] > r20["PSQ"]: return "PSQ"
return "SQQQ"
def _t11_feaver_bear(self, r10, r20, tqqq_px, tqqq_sma) -> str:
hist = self.history(self._syms["QQQ"], 61, Resolution.DAILY)
qqq_60d = 0.0
if not hist.empty and len(hist) >= 61:
c = hist["close"].values
qqq_60d = (c[-1] / c[0] - 1) * 100
if qqq_60d < -12:
if r10["BND"] > r10["QQQ"]: return "QLD"
return "BTAL"
if tqqq_px > tqqq_sma:
if r10["PSQ"] < 35: return "PSQ"
if r20["AGG"] > self._t11_rsi60_sh.current.value: return "TQQQ"
return "PSQ"
else:
if r10["IEF"] > r20["PSQ"]: return "PSQ"
return "SQQQ"
# ── Strategy signals → weight dicts ───────────────────────────────────────
def _t10_weights(self) -> dict:
if not self._t10_ready: return {}
r = {t: self._t10_rsi[t].current.value for t in self._t10_rsi
if self._t10_rsi[t].is_ready}
if (r.get("QQQE",0)>79 or r.get("VTV",0)>79 or r.get("VOX",0)>79
or r.get("TECL",0)>79 or r.get("VOOG",0)>79 or r.get("VOOV",0)>79
or r.get("XLP",0)>75 or r.get("TQQQ",0)>79 or r.get("XLY",0)>80
or r.get("FAS",0)>80 or r.get("SPY",0)>80):
return {self._syms["UVXY"]: self.QUARTER}
if r.get("TQQQ",50) < 30: return {self._syms["TECL"]: self.QUARTER}
if r.get("SOXL",50) < 30: return {self._syms["SOXL"]: self.QUARTER}
if r.get("SPXL",50) < 30: return {self._syms["SPXL"]: self.QUARTER}
if self._t10_rsi["LABU"].is_ready and r["LABU"] < 25:
return {self._syms["LABU"]: self.QUARTER}
vs = "SVIX" if self.time >= self.SVIX_LIVE else "SVXY"
kmlm_ready = self._t10_rsi["KMLM"].is_ready
xlk_wins = (not kmlm_ready) or (r["XLK"] > r["KMLM"])
if xlk_wins:
return {self._syms["TECL"]: self.QUARTER/3,
self._syms["SOXL"]: self.QUARTER/3,
self._syms[vs]: self.QUARTER/3}
return {self._syms["SQQQ"]: self.QUARTER*0.5,
self._syms["TLT"]: self.QUARTER*0.5}
def _t11_weights(self) -> dict:
if not self._t11_ready: return {}
r10 = {t: self._t11_rsi10[t].current.value for t in self._t11_rsi10
if self._t11_rsi10[t].is_ready}
r20 = {t: self._t11_rsi20[t].current.value for t in self._t11_rsi20}
spy_px = self.securities[self._syms["SPY"]].close
tqqq_px = self.securities[self._syms["TQQQ"]].close
kmlm_px = self.securities[self._syms["KMLM"]].close
spy_sma = self._t11_spy_sma200.current.value
tqqq_sma = self._t11_tqqq_sma20.current.value
kmlm_sma = self._t11_kmlm_sma20.current.value
ob79 = (r10["SPY"]>79 or r10["IOO"]>79 or r10["TQQQ"]>79
or r10["VTV"]>79 or r10["XLF"]>79)
if ob79:
ob81 = (r10["SPY"]>81 or r10["IOO"]>81 or r10["TQQQ"]>81
or r10["VTV"]>81 or r10["XLF"]>81)
if ob81:
return {self._syms["UVXY"]: self.QUARTER}
return {self._syms["UVXY"]: self.QUARTER/3,
self._syms["BIL"]: self.QUARTER/3,
self._syms["BTAL"]: self.QUARTER/3}
if r10["TQQQ"] < 30: return {self._syms["TQQQ"]: self.QUARTER}
if r10["SPY"] < 30: return {self._syms["SPXL"]: self.QUARTER}
if spy_px > spy_sma:
kmlm_ready = self._t11_rsi10["KMLM"].is_ready and self._t11_kmlm_sma20.is_ready
if not kmlm_ready or r10["XLK"] > r10["KMLM"]:
return {self._syms["TECL"]: self.QUARTER/3,
self._syms["SOXL"]: self.QUARTER/3,
self._syms["TQQQ"]: self.QUARTER/3}
if kmlm_px < kmlm_sma:
return {self._syms["TECL"]: self.QUARTER/3,
self._syms["SOXL"]: self.QUARTER/3,
self._syms["TQQQ"]: self.QUARTER/3}
return {self._syms["TECS"]: self.QUARTER/3,
self._syms["SOXS"]: self.QUARTER/3,
self._syms["SQQQ"]: self.QUARTER/3}
else:
bb = self._t11_bond_baller(r10, r20, tqqq_px, tqqq_sma)
fb = self._t11_feaver_bear(r10, r20, tqqq_px, tqqq_sma)
w: dict = {}
w[self._syms[bb]] = w.get(self._syms[bb], 0) + self.QUARTER * 0.5
w[self._syms[fb]] = w.get(self._syms[fb], 0) + self.QUARTER * 0.5
return w
def _s2_weights(self) -> dict:
if not self._s2_ready: return {}
tqqq_price = self.securities[self._syms["TQQQ"]].close
tqqq_rsi = self._s2_tqqq_rsi10.current.value
soxl_rsi = self._s2_soxl_rsi10.current.value
sqqq_rsi = self._s2_sqqq_rsi10.current.value
bsv_rsi = self._s2_bsv_rsi10.current.value
sma200 = self._s2_tqqq_sma200.current.value
sma20 = self._s2_tqqq_sma20.current.value
if tqqq_price > sma200:
sym = self._syms["UVXY"] if tqqq_rsi > 79 else self._syms["TQQQ"]
return {sym: self.QUARTER}
if tqqq_rsi < 31: return {self._syms["TECL"]: self.QUARTER}
if soxl_rsi < 30: return {self._syms["SOXL"]: self.QUARTER}
if tqqq_price < sma20:
sym = self._syms["SQQQ"] if sqqq_rsi > bsv_rsi else self._syms["BSV"]
return {sym: self.QUARTER}
return {self._syms["TQQQ"]: self.QUARTER}
def _s3_weights(self) -> dict:
if not self._s3_ready: return {}
spy_bull = self.securities[self._syms["SPY"]].price > self._s3_spy_sma202.current.value
qqq_bull = self.securities[self._syms["QQQ"]].price > self._s3_qqq_sma202.current.value
smh_bull = self.securities[self._syms["SMH"]].price > self._s3_smh_sma202.current.value
soxl_bull = self.securities[self._syms["SOXL"]].price > self._s3_soxl_sma202.current.value
bull = (int(spy_bull)+int(qqq_bull)+int(smh_bull)+int(soxl_bull)) >= 3
overbought = (self._s3_rsi_spy15.current.value > 72 or
self._s3_rsi_qqq15.current.value > 72 or
self._s3_rsi_smh15.current.value > 72 or
self._s3_rsi_soxl15.current.value > 72)
if bull:
if overbought:
vol = (self._syms["UVIX"]
if (self.time >= self.UVIX_LIVE
and self.securities[self._syms["UVIX"]].has_data
and self.securities[self._syms["UVIX"]].price > 0)
else self._syms["UVXY"])
return {vol: self.QUARTER}
return {self._syms["TQQQ"]: self.QUARTER*0.5,
self._syms["SOXL"]: self.QUARTER*0.5}
if self._s3_rsi_qqq8.current.value < 29 or self._s3_rsi_smh8.current.value < 31:
return {self._syms["SOXL"]: self.QUARTER}
return {} # cash
# ── Merge and apply ────────────────────────────────────────────────────────
def _rebalance(self) -> None:
if self.is_warming_up: return
w10 = self._t10_weights()
w11 = self._t11_weights()
w2 = self._s2_weights()
w3 = self._s3_weights()
combined: dict = {}
for w in [w10, w11, w2, w3]:
for sym, wt in w.items():
combined[sym] = combined.get(sym, 0.0) + wt
# Liquidate anything no longer targeted (including full cash state)
targets = set(combined)
for h in list(self.portfolio.values()):
if h.invested and h.symbol not in targets:
self.liquidate(h.symbol)
for sym, wt in combined.items():
self.set_holdings(sym, wt)
def lbl(w): return "+".join(f"{round(wt/self.QUARTER*100):.0f}%{s.value}"
for s, wt in w.items()) if w else "CASH"
new_label = f"T10={lbl(w10)}|T11={lbl(w11)}|S2={lbl(w2)}|S3={lbl(w3)}"
if new_label != self._last_label:
self._trade_count += 1
net = "+".join(f"{round(w*100):.0f}%{s.value}"
for s, w in sorted(combined.items(), key=lambda x: -x[1]))
self.log(f"[{self._trade_count:04d}] {self.time.date()} | net={net}")
self._last_label = new_label
def on_data(self, data: Slice) -> None: pass
def on_end_of_algorithm(self) -> None:
self.log(f"\n{'─'*55}\n Final NAV : ${self.portfolio.total_portfolio_value:>15,.2f}\n"
f" State changes : {self._trade_count}\n{'─'*55}")