Overall Statistics Total Trades1445Average Win0.74%Average Loss-0.69%Compounding Annual Return5.208%Drawdown5.500%Expectancy0.064Net Profit35.336%Sharpe Ratio1.022Probabilistic Sharpe Ratio49.583%Loss Rate49%Win Rate51%Profit-Loss Ratio1.08Alpha0.052Beta0.022Annual Standard Deviation0.053Annual Variance0.003Information Ratio-0.031Tracking Error0.242Treynor Ratio2.407Total Fees\$0.00
import numpy as np
from math import floor

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.qty = 2000

def update(self, price_one, price_two):
# Create the observation matrix of the latest prices
# of TLT and the intercept value (1.0)
F = np.asarray([price_one, 1.0]).reshape((1, 2))
y = price_two

# The prior value of the states \theta_t is
# distributed as a multivariate Gaussian with
# mean a_t and variance-covariance R_t
if self.R is not None:
self.R = self.C + self.wt
else:
self.R = np.zeros((2, 2))

# Calculate the Kalman Filter update
# ----------------------------------
# Calculate prediction of new observation
# as well as forecast error of that prediction
yhat = F.dot(self.theta)
et = y - yhat

# Q_t is the variance of the prediction of
# observations and hence \sqrt{Q_t} is the
# standard deviation of the predictions
Qt = F.dot(self.R).dot(F.T) + self.vt
sqrt_Qt = np.sqrt(Qt)

# The posterior value of the states \theta_t is
# distributed as a multivariate Gaussian with mean
# m_t and variance-covariance C_t
At = self.R.dot(F.T) / Qt
self.theta = self.theta + At.flatten() * et
self.C = self.R - At * F.dot(self.R)
hedge_quantity = int(floor(self.qty*self.theta))

return et, sqrt_Qt, hedge_quantity
import numpy as np
from math import floor
from KalmanFilter import KalmanFilter
class VerticalParticleInterceptor(QCAlgorithm):

def Initialize(self):
self.SetStartDate(2006, 4, 26)  # Set Start Date
self.SetEndDate(2012, 4, 9)
self.SetCash(100000)  # Set Strategy Cash

self.SetSecurityInitializer(self.CustomSecurityInitializer)

self.symbols = [self.AddEquity(x, Resolution.Minute).Symbol for x in ['EWA', 'EWC']]
self.kf = KalmanFilter()
self.invested = None

def CustomSecurityInitializer(self, security):
security.SetFeeModel(CustomFeeModel())
security.SetDataNormalizationMode(DataNormalizationMode.Raw)

# Get recent price and holdings information
ewa = self.CurrentSlice[self.symbols].Close
ewc = self.CurrentSlice[self.symbols].Close
holdings = self.Portfolio[self.symbols]

forecast_error, prediction_std_dev, hedge_quantity = self.kf.update(ewa, ewc)

if not holdings.Invested:
if forecast_error < -prediction_std_dev:
insights = Insight.Group([Insight(self.symbols, timedelta(1), InsightType.Price, InsightDirection.Down),
Insight(self.symbols, timedelta(1), InsightType.Price, InsightDirection.Up)])
self.EmitInsights(insights)
self.MarketOrder(self.symbols, self.kf.qty)
self.MarketOrder(self.symbols, -hedge_quantity)

elif forecast_error > prediction_std_dev:
insights = Insight.Group([Insight(self.symbols, timedelta(1), InsightType.Price, InsightDirection.Up),
Insight(self.symbols, timedelta(1), InsightType.Price, InsightDirection.Down)])
self.EmitInsights(insights)
self.MarketOrder(self.symbols, -self.kf.qty)
self.MarketOrder(self.symbols, hedge_quantity)

if holdings.Invested:
# Close long position
if holdings.IsShort and (forecast_error >= -prediction_std_dev):
insights = Insight.Group([Insight(self.symbols, timedelta(1), InsightType.Price, InsightDirection.Flat),
Insight(self.symbols, timedelta(1), InsightType.Price, InsightDirection.Flat)])
self.EmitInsights(insights)
self.Liquidate()
self.invested = None

# Close short position
elif holdings.IsLong and (forecast_error <= prediction_std_dev):
insights = Insight.Group([Insight(self.symbols, timedelta(1), InsightType.Price, InsightDirection.Flat),
Insight(self.symbols, timedelta(1), InsightType.Price, InsightDirection.Flat)])
self.EmitInsights(insights)
self.Liquidate()
self.invested = None

class CustomFeeModel:
def GetOrderFee(self, parameters):
return OrderFee(CashAmount(0, 'USD'))