Overall Statistics
Total Orders
646
Average Win
7.08%
Average Loss
-3.94%
Compounding Annual Return
59.634%
Drawdown
51.300%
Expectancy
0.375
Start Equity
100000
End Equity
2647279.58
Net Profit
2547.280%
Sharpe Ratio
1.064
Sortino Ratio
1.132
Probabilistic Sharpe Ratio
36.163%
Loss Rate
51%
Win Rate
49%
Profit-Loss Ratio
1.80
Alpha
0.446
Beta
1.021
Annual Standard Deviation
0.515
Annual Variance
0.265
Information Ratio
0.92
Tracking Error
0.487
Treynor Ratio
0.537
Total Fees
$146584.17
Estimated Strategy Capacity
$360000.00
Lowest Capacity Asset
UUP TQBX2PUC67OL
Portfolio Turnover
29.24%
Drawdown Recovery
218
from AlgorithmImports import *
import numpy as np

class TheOmniscientParadox(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2019, 1, 1)
        self.set_end_date(datetime.now())
        self.set_cash(100000)

        self.settings.rebalance_portfolio_on_insight_changes = False
        self.universe_settings.resolution = Resolution.MINUTE

        # ✅ Route 2: allow mild margin leverage
        self.universe_settings.leverage = 2.0

        # Universe (UGL stays)
        self.tickers = ["SOXL", "TECL", "TQQQ", "FAS", "ERX", "UGL", "UUP", "TMF", "BIL"]
        self.symbols = [self.add_equity(t, Resolution.MINUTE).symbol for t in self.tickers]
        self.safe = self.symbols[-1]

        # ✅ Apply leverage to each security (important in QC)
        for s in self.symbols:
            self.securities[s].set_leverage(2.0)

        self.indicators = {}
        for s in self.symbols:
            self.indicators[s] = {
                'roc_fast': self.rocp(s, 9, Resolution.DAILY),
                'roc_med': self.rocp(s, 21, Resolution.DAILY),
                'roc_slow': self.rocp(s, 63, Resolution.DAILY),
                'vol': self.std(s, 21, Resolution.DAILY),
                'rsi': self.rsi(s, 14, MovingAverageType.WILDERS, Resolution.DAILY),
                'sma': self.sma(s, 50, Resolution.DAILY)
            }

        self.spy = self.add_equity("SPY", Resolution.DAILY).symbol
        self.spy_sma = self.sma(self.spy, 200, Resolution.DAILY)

        # ✅ Less conservative vol sizing
        self.lookback_vol = 10      # was 20
        self.target_vol = 1.15      # was 0.80
        self.max_weight = 1.35      # allow mild >1 exposure

        self.confidence_threshold = 0.10
        self.current_holding = None

        # ✅ Portfolio crash brake
        self.peak_equity = 100000
        self.dd_limit = 0.55  # 55% max drawdown from peak

        self.schedule.on(
            self.date_rules.every_day(self.symbols[0]),
            self.time_rules.before_market_close(self.symbols[0], 5),
            self.rebalance
        )

        self.set_warm_up(100)

    def on_data(self, data):
        # ✅ Update peak and enforce drawdown brake
        pv = self.portfolio.total_portfolio_value
        if pv > self.peak_equity:
            self.peak_equity = pv

        if self.peak_equity > 0:
            dd = 1.0 - (pv / self.peak_equity)
            if dd > self.dd_limit:
                # Emergency de-risk: dump everything into BIL
                for x in self.active_securities.values():
                    if x.invested:
                        self.liquidate(x.symbol)
                self.set_holdings(self.safe, 1.0)
                self.current_holding = self.safe

    def rebalance(self):
        if self.is_warming_up:
            return

        # If we are already in emergency-safe, don't fight it intraday
        if self.current_holding == self.safe and self.portfolio.total_portfolio_value < self.peak_equity * (1 - self.dd_limit):
            return

        spy_trend = self.securities[self.spy].close > self.spy_sma.current.value

        scores = {}
        for s in self.symbols:
            if s == self.safe:
                continue

            inds = self.indicators[s]
            if not inds['roc_slow'].is_ready:
                continue

            fast = inds['roc_fast'].current.value
            med = inds['roc_med'].current.value
            slow = inds['roc_slow'].current.value
            vol = inds['vol'].current.value
            rsi = inds['rsi'].current.value
            price = self.securities[s].close
            sma = inds['sma'].current.value

            if vol == 0:
                vol = 1.0

            weighted_mom = (fast * 0.5) + (med * 0.3) + (slow * 0.2)
            risk_adj_mom = weighted_mom / vol
            trend_score = 1.0 if price > sma else 0.5

            rsi_penalty = 1.0
            if rsi > 85:
                rsi_penalty = 0.9
            elif rsi < 30:
                rsi_penalty = 0.9

            final_score = risk_adj_mom * trend_score * rsi_penalty
            scores[s] = final_score

        if not scores:
            return

        sorted_assets = sorted(scores.items(), key=lambda x: x[1], reverse=True)
        best_asset = sorted_assets[0][0]
        best_score = sorted_assets[0][1]

        target_asset = self.current_holding

        if self.current_holding is None:
            target_asset = best_asset if best_score > 0 else self.safe
        else:
            current_score = scores.get(self.current_holding, -999)

            if self.current_holding == self.safe:
                if best_score > 0.02:
                    target_asset = best_asset
            else:
                if best_score > current_score * (1 + self.confidence_threshold):
                    target_asset = best_asset
                elif current_score < -0.02:
                    target_asset = self.safe

        # ✅ Weak-SPY handling: let UGL/TMF/UUP compete (from earlier update)
        if not spy_trend and target_asset != self.safe:
            ugl_sym = self.symbols[self.tickers.index("UGL")]
            tmf_sym = self.symbols[self.tickers.index("TMF")]
            uup_sym = self.symbols[self.tickers.index("UUP")]

            defensive_syms = [ugl_sym, tmf_sym, uup_sym]

            best_def = None
            best_def_score = -999
            for d in defensive_syms:
                sc = scores.get(d, -999)
                if sc > best_def_score:
                    best_def = d
                    best_def_score = sc

            if best_def_score > scores.get(target_asset, -999):
                target_asset = best_def
            elif scores.get(target_asset, -999) < 0:
                target_asset = self.safe

        # ✅ Vol targeting sizing, but allow mild >1 exposure
        if target_asset and target_asset != self.safe:
            hist = self.history(target_asset, self.lookback_vol + 1, Resolution.DAILY)
            if not hist.empty:
                rets = hist.close.pct_change().dropna()
                curr_vol = np.std(rets) * np.sqrt(252)

                if curr_vol > 0:
                    weight = self.target_vol / curr_vol
                else:
                    weight = 1.0

                target_weight = min(self.max_weight, weight)
            else:
                target_weight = 1.0
        elif target_asset == self.safe:
            target_weight = 1.0
        else:
            target_weight = 0.0

        self.current_holding = target_asset

        # Liquidate non-target positions first
        invested = [x.symbol for x in self.active_securities.values() if x.invested]
        for s in invested:
            if s != target_asset:
                self.liquidate(s)

        # ✅ Pure profit mode: DO NOT auto-fill remainder into BIL anymore.
        # Either hold the chosen asset at target_weight, or BIL when selected.
        if target_asset:
            curr_val = self.portfolio[target_asset].holdings_value
            tot_val = self.portfolio.total_portfolio_value
            curr_w = curr_val / tot_val if tot_val > 0 else 0

            if abs(curr_w - target_weight) > 0.05:
                self.set_holdings(target_asset, target_weight)