| Overall Statistics |
|
Total Trades 1502 Average Win 0.26% Average Loss -0.15% Compounding Annual Return 1.195% Drawdown 17.900% Expectancy 0.044 Net Profit 4.217% Sharpe Ratio 0.142 Probabilistic Sharpe Ratio 2.183% Loss Rate 62% Win Rate 38% Profit-Loss Ratio 1.71 Alpha 0.015 Beta -0.018 Annual Standard Deviation 0.094 Annual Variance 0.009 Information Ratio -0.438 Tracking Error 0.199 Treynor Ratio -0.751 Total Fees $29328.98 |
import numpy as np
class QuantumNadionCompensator(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2017, 1, 1) # Set Start Date
self.SetCash(100000) # Set Strategy Cash
_ = [self.AddCrypto(x, Resolution.Hour, Market.Bitfinex) for x in ['BTCUSD', 'ETHUSD']]
self.SetBrokerageModel(BrokerageName.Bitfinex, AccountType.Margin)
# Kalman filter parameters
self.theta = np.ones(2) # Hidden state - weights of the linear model
self.R = None # Variance-covariance matrix
self.delta = 1e-6 # System noise
self.wt = self.delta / (1 - self.delta) * np.eye(2)
self.vt = 1e-7 # Measurement noise
# Strategy parameters
self.invest_type = None # long/short BTCUSD
self.invest_portf = 0.1 # Share of the portfolio to be invested into each asset
def OnData(self, data):
# Kalman filtering update
obs = np.array([data['ETHUSD'].Close, 1])
y = data['BTCUSD'].Close
if self.R is None:
self.R = np.eye(2)#np.zeros((2,2))
#self.R[0,0] = 100
else:
self.R = self.C + self.wt
yhat = obs.dot(self.theta)
et = y - yhat
# Variance of the prediction at t=i
Qt = obs.dot(self.R).dot(obs.T) + self.vt
pred_err = np.sqrt(Qt)
# Posterior values of states theta
At = self.R.dot(obs.T) / Qt
self.theta = self.theta + At.flatten() * et
self.C = self.R - At * obs.dot(self.R)
# Implement pairs trading strategy
if self.invest_type is None:
if et < -pred_err:
# Undervalued BTC => long BTC, short ETH
self.SetHoldings('BTCUSD', self.invest_portf, False)
self.SetHoldings('ETHUSD', -self.theta[0] * self.invest_portf * data['ETHUSD'].Close / data['BTCUSD'].Close, False)
self.invest_type = 'long'
elif et > pred_err:
# Overvalued BTC => long BTC, short ETH
self.SetHoldings('BTCUSD', -self.invest_portf, False)
self.SetHoldings('ETHUSD', self.theta[0] * self.invest_portf * data['ETHUSD'].Close / data['BTCUSD'].Close, False)
self.invest_type = 'short'
elif self.invest_type == 'long' and et > -pred_err or self.invest_type == 'short' and et < pred_err:
self.SetHoldings('BTCUSD', 0, False)
self.SetHoldings('ETHUSD', 0, False)
self.invest_type = None