Overall Statistics
Total Orders
997
Average Win
2.76%
Average Loss
-1.64%
Compounding Annual Return
37.871%
Drawdown
90.200%
Expectancy
0.370
Start Equity
100000.00
End Equity
1307571.69
Net Profit
1207.572%
Sharpe Ratio
1.105
Sortino Ratio
1.509
Probabilistic Sharpe Ratio
29.265%
Loss Rate
49%
Win Rate
51%
Profit-Loss Ratio
1.68
Alpha
-0.203
Beta
0.938
Annual Standard Deviation
0.813
Annual Variance
0.66
Information Ratio
-0.613
Tracking Error
0.45
Treynor Ratio
0.957
Total Fees
$246721.86
Estimated Strategy Capacity
$1900000.00
Lowest Capacity Asset
JASMYUSD 2XR
Portfolio Turnover
1.40%
# region imports
from AlgorithmImports import *
# endregion

class StrategicCryptoReserveAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_end_date(2025, 3, 1)
        self.set_start_date(self.end_date - timedelta(8*365))
        self.set_brokerage_model(BrokerageName.COINBASE, AccountType.CASH)
        self._market_pairs = [
            x.key.symbol 
            for x in self.symbol_properties_database.get_symbol_properties_list(Market.COINBASE) 
            if (x.value.quote_currency == self.account_currency and   # Account currency is USD
                x.value.market_ticker.split('-')[0] not in ['USDT', 'USDC'])  # Remove stable coins
        ]
        self.time_rules.set_default_time_zone(TimeZones.UTC)
        date_rule = self.date_rules.month_start()
        self.universe_settings.schedule.on(date_rule)
        self.universe_settings.resolution = Resolution.DAILY
        self.schedule.on(date_rule, self.time_rules.midnight, self._rebalance)
        self._universe = self.add_universe(CryptoUniverse.coinbase(self._select_assets))

    def _select_assets(self, data):
        selected = [c for c in data if str(c.symbol.id).split()[0] in self._market_pairs]
        selected = [c.symbol for c in sorted(selected, key=lambda c: c.volume_in_usd)[-10:]]
        self.plot('Universe', 'Size', len(selected))
        return selected

    def _rebalance(self):
        symbols = self._universe.selected
        if not symbols:
            return
        inv_return_volatility = 1/self.history(symbols, 365, Resolution.DAILY).close.unstack(0).pct_change()[1:].std()
        inverse_sum = inv_return_volatility.sum()
        self.set_holdings([PortfolioTarget(s, inv_vol/inverse_sum*0.95) for s, inv_vol in inv_return_volatility.items()], True)