Overall Statistics
Total Orders
209
Average Win
2.30%
Average Loss
-1.09%
Compounding Annual Return
45.234%
Drawdown
19.000%
Expectancy
1.401
Start Equity
100000
End Equity
645291.77
Net Profit
545.292%
Sharpe Ratio
1.276
Sortino Ratio
1.468
Probabilistic Sharpe Ratio
77.287%
Loss Rate
23%
Win Rate
77%
Profit-Loss Ratio
2.11
Alpha
0.261
Beta
0.476
Annual Standard Deviation
0.225
Annual Variance
0.051
Information Ratio
1.018
Tracking Error
0.227
Treynor Ratio
0.603
Total Fees
$1398.07
Estimated Strategy Capacity
$27000000.00
Lowest Capacity Asset
UAMY V6RH1Y2WUICL
Portfolio Turnover
1.19%
Drawdown Recovery
1101
# region imports
from AlgorithmImports import *
# endregion


class ThesisAllocation(QCAlgorithm):

    def initialize(self):
        self.set_start_date(self.end_date - timedelta(5 * 365))
        self.set_cash(100_000)
        self._lookback = 63
        ma_period = 200
        tickers = ["SPY", "TLT", "GLD", "UAMY", "SNDK"]
        self._symbols = []
        for ticker in tickers:
            security = self.add_equity(ticker, Resolution.DAILY)
            # Attach the trend-filter moving average to each risky sleeve.
            security.ma = self.sma(security, ma_period)
            self._symbols.append(security.symbol)
        # The T-bill sleeve receives any weight routed out of below-trend sleeves.
        self._bills = self.add_equity("BIL", Resolution.DAILY)
        self.set_warm_up(max(ma_period, self._lookback) + 5, Resolution.DAILY)
        self.schedule.on(self.date_rules.month_start(self._symbols[0]), self.time_rules.at(8, 0), self._rebalance)

    def on_warmup_finished(self):
        self._rebalance()

    def _rebalance(self):
        if self.is_warming_up:
            return
        vol = self.history(self._symbols, self._lookback, Resolution.DAILY)["close"].unstack(level=0).pct_change().dropna().std()
        weights = vol * 0.0 + 1.0
        weights = weights / weights.sum() * 0.98
        # Route each below-trend sleeve's share into T-bills instead of holding it.
        bills_weight = 0.0
        for symbol, weight in weights.items():
            security = self.securities[symbol]
            if security.ma.is_ready and security.price < security.ma.current.value:
                bills_weight += weight
                weight = 0.0
            self.set_holdings(symbol, weight)
        self.set_holdings(self._bills, bills_weight)