Overall Statistics |
Total Orders 299 Average Win 2.19% Average Loss -1.28% Compounding Annual Return 22.807% Drawdown 41.900% Expectancy 0.802 Start Equity 100000.0 End Equity 488189.87 Net Profit 388.190% Sharpe Ratio 0.794 Sortino Ratio 0.812 Probabilistic Sharpe Ratio 31.602% Loss Rate 34% Win Rate 66% Profit-Loss Ratio 1.71 Alpha 0.065 Beta 0.96 Annual Standard Deviation 0.187 Annual Variance 0.035 Information Ratio 0.531 Tracking Error 0.115 Treynor Ratio 0.155 Total Fees $841.69 Estimated Strategy Capacity $3400000.00 Lowest Capacity Asset BTCUSD E3 Portfolio Turnover 4.51% |
# region imports from AlgorithmImports import * from sklearn.tree import DecisionTreeRegressor from sklearn.preprocessing import StandardScaler # endregion class AIStocksBondsRotationAlgorithm(QCAlgorithm): def initialize(self): self.set_start_date(2017, 1, 1) self.settings.daily_precise_end_time = False self._bitcoin = self.add_crypto("BTCUSD", market=Market.BITFINEX, leverage=2).symbol self._equities = [self.add_equity(ticker).symbol for ticker in ['SPY', 'GLD', 'BND']] self._factors = [self.add_data(Fred, ticker, Resolution.DAILY).symbol for ticker in ['VIXCLS', 'T10Y3M', 'DFF']] self._model = DecisionTreeRegressor(max_depth=12, random_state=1) self._scaler = StandardScaler() self.schedule.on(self.date_rules.month_start(self._equities[0]), self.time_rules.after_market_open(self._equities[0], 1), self._rebalance) self._lookback_years = self.get_parameter('lookback_years', 4) self._max_bitcoin_weight = self.get_parameter('max_bitcoin_weight', 0.1) def _rebalance(self): factors = self.history(self._factors, timedelta(self._lookback_years*365), Resolution.DAILY)['value'].unstack(0).dropna() label = self.history(self._equities + [self._bitcoin], timedelta(self._lookback_years*365), Resolution.DAILY, data_normalization_mode=DataNormalizationMode.TOTAL_RETURN)['close'].unstack(0).dropna().pct_change(21).shift(-21).dropna() prediction_by_symbol = pd.Series() for symbol in self._equities + [self._bitcoin]: asset_labels = label[symbol].dropna() idx = factors.index.intersection(asset_labels.index) self._model.fit(self._scaler.fit_transform(factors.loc[idx]), asset_labels.loc[idx]) prediction = self._model.predict(self._scaler.transform([factors.iloc[-1]]))[0] if prediction > 0: prediction_by_symbol.loc[symbol] = prediction weight_by_symbol = 1.5 * prediction_by_symbol / prediction_by_symbol.sum() if self._bitcoin in weight_by_symbol and weight_by_symbol.loc[self._bitcoin] > self._max_bitcoin_weight: weight_by_symbol.loc[self._bitcoin] = self._max_bitcoin_weight if len(weight_by_symbol) > 1: equities = [symbol for symbol in self._equities if symbol in weight_by_symbol] weight_by_symbol.loc[equities] = 1.5 * weight_by_symbol.loc[equities] / weight_by_symbol.loc[equities].sum() self.set_holdings([PortfolioTarget(symbol, weight) for symbol, weight in weight_by_symbol.items()], True)