Overall Statistics |
Total Trades 2327 Average Win 0.71% Average Loss -1.17% Compounding Annual Return 13.817% Drawdown 21.100% Expectancy 0.153 Net Profit 474.695% Sharpe Ratio 0.966 Probabilistic Sharpe Ratio 35.274% Loss Rate 28% Win Rate 72% Profit-Loss Ratio 0.60 Alpha 0.129 Beta 0.18 Annual Standard Deviation 0.158 Annual Variance 0.025 Information Ratio 0.104 Tracking Error 0.227 Treynor Ratio 0.848 Total Fees $18318.09 Estimated Strategy Capacity $8300000000.00 Lowest Capacity Asset TLT SGNKIKYGE9NP |
# Stock-Bond Trading using Kalman Filter from math import floor import numpy as np # ------------------------------------------------- STOCK = 'QQQ'; BOND = 'TLT'; LEV = 1.00; T = 0.020; # ------------------------------------------------- class KalmanFilterTrading(QCAlgorithm): def Initialize(self): self.SetStartDate(2008, 1, 1) self.SetEndDate(2021, 7, 3) self.SetCash(100000) self.SetBrokerageModel(AlphaStreamsBrokerageModel()) self.stock = self.AddEquity(STOCK, Resolution.Minute).Symbol self.bond = self.AddEquity(BOND, Resolution.Minute).Symbol self.kf = KalmanFilter() self.SetWarmUp(10, Resolution.Daily) self.Schedule.On(self.DateRules.EveryDay(self.stock), self.TimeRules.BeforeMarketClose(self.stock, 1), self.Trade) def Trade(self): if self.IsWarmingUp: return stock_price = self.Securities[self.stock].Price bond_price = self.Securities[self.bond].Price forecast_error, prediction_std_dev, hedge = self.kf.update(stock_price, bond_price) if forecast_error < -prediction_std_dev: self.SetHoldings(self.stock, LEV*hedge) self.SetHoldings(self.bond, LEV*(1 - hedge)) elif forecast_error > prediction_std_dev: self.SetHoldings(self.stock, LEV*(1 - hedge)) self.SetHoldings(self.bond, LEV*hedge) self.Plot("HEDGE", "hedge", float(hedge)) self.Plot("ERROR", "forecast_error", float(forecast_error)) self.Plot("STDEV", "prediction_std_dev", float(prediction_std_dev)) class KalmanFilter: def __init__(self): self.delta = 1e-4 self.wt = self.delta / (1 - self.delta) * np.eye(2) self.vt = 1e-3 self.theta = np.zeros(2) self.P = np.zeros((2, 2)) self.R = None self.t = T def update(self, price_one, price_two): F = np.asarray([price_one, 1.0]).reshape((1, 2)) y = price_two if self.R is not None: self.R = self.C + self.wt else: self.R = np.zeros((2, 2)) yhat = F.dot(self.theta) et = y - yhat Qt = F.dot(self.R).dot(F.T) + self.vt sqrt_Qt = np.sqrt(Qt) At = self.R.dot(F.T) / Qt self.theta = self.theta + At.flatten() * et self.C = self.R - At * F.dot(self.R) hedge = self.t*self.theta[0] return et, sqrt_Qt, hedge ''' START 1/1/2008 END 7/2/2021 STOCK = 'QQQ'; BOND = 'TLT'; LEV = 1.00; T = 0.025; EveryDay Sharpe Ratio 0.971 Total Trades 2401 Average Win 0.67% Average Loss -1.12% Compounding Annual Return 13.774% Drawdown 20.900% Expectancy 0.154 Net Profit 471.759% PSR 35.955% Loss Rate 28% Win Rate 72% Profit-Loss Ratio 0.60 Alpha 0.128 Beta 0.181 Annual Standard Deviation 0.156 Annual Variance 0.024 Information Ratio 0.102 Tracking Error 0.226 Treynor Ratio 0.837 Total Fees $18019.24 Estimated Strategy Capacity $6700000000.00 Lowest Capacity Asset TLT SGNKIKYGE9NP '''