Overall Statistics
Total Orders
907
Average Win
5.22%
Average Loss
-1.47%
Compounding Annual Return
52.449%
Drawdown
55.900%
Expectancy
0.577
Start Equity
100000
End Equity
1917351.88
Net Profit
1817.352%
Sharpe Ratio
1.03
Sortino Ratio
1.068
Probabilistic Sharpe Ratio
38.806%
Loss Rate
65%
Win Rate
35%
Profit-Loss Ratio
3.55
Alpha
0.352
Beta
0.775
Annual Standard Deviation
0.417
Annual Variance
0.174
Information Ratio
0.827
Tracking Error
0.398
Treynor Ratio
0.554
Total Fees
$92824.16
Estimated Strategy Capacity
$500000.00
Lowest Capacity Asset
UUP TQBX2PUC67OL
Portfolio Turnover
23.08%
Drawdown Recovery
269
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
        self.universe_settings.leverage = 1.0

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

        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)

        self.lookback_vol = 20
        self.target_vol = 0.80
        self.confidence_threshold = 0.10
        self.current_holding = None
        
        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):
        pass

    def rebalance(self):
        if self.is_warming_up: 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:
            if best_score > 0:
                target_asset = best_asset
            else:
                target_asset = 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

        if not spy_trend and target_asset != self.safe:
             uup_sym = self.symbols[self.tickers.index("UUP")]
             uup_score = scores.get(uup_sym, -999)
             
             if uup_score > 0 and uup_score > scores.get(target_asset, -999):
                 target_asset = uup_sym
             elif scores.get(target_asset, -999) < 0:
                 target_asset = self.safe

        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(1.0, 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
        
        invested = [x.symbol for x in self.active_securities.values() if x.invested]
        for s in invested:
            if s != target_asset:
                self.liquidate(s)

        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)
                
            rem = 1.0 - target_weight
            if rem > 0.1 and target_asset != self.safe:
                self.set_holdings(self.safe, rem)