Overall Statistics Total Trades4Average Win0.36%Average Loss0%Compounding Annual Return25.098%Drawdown0.000%Expectancy0Net Profit0.726%Sharpe Ratio9.117Probabilistic Sharpe Ratio100.000%Loss Rate0%Win Rate100%Profit-Loss Ratio0Alpha0.161Beta-0.004Annual Standard Deviation0.018Annual Variance0Information Ratio1.501Tracking Error0.616Treynor Ratio-44.778Total Fees\$0.00
from datetime import timedelta
import numpy as np
import math
import pandas as pd
from sklearn.linear_model import LinearRegression
from scipy.odr import Model, Data, ODR
from scipy import stats
from statistics import stdev
from pykalman import KalmanFilter

class VentralUncoupledShield(QCAlgorithm):

def Initialize(self):
self.SetStartDate(2020,3,1)    # Set Start Date
#self.SetEndDate(2020,3,15)      # Set End Date
self.SetEndDate(2020,3,11)      # Set End Date
self.SetCash(10000)
self.currency1='GBPUSD'
self.currency2='USDJPY'

#kalman filter initialization
self.delta = 1e-7 #process noise
self.observation_cov=1e-4 #observation covariance
self.counter=1
self.means=0
self.covs=0
self.kf=0
self.std_upper=0
self.std_lower=0
self.no_of_std=3
self.allocation=0.5
self.pred_currency2 = 0

#charting
self.Charts = dict()

def Kalman_update(self,value1,value2):
if self.counter == 1:
trans_cov = self.delta / (1 - self.delta) * np.eye(2)
obs_mat = [value1, 1]
self.kf = KalmanFilter(n_dim_obs=1, n_dim_state = 2,
initial_state_mean = np.zeros(2),
initial_state_covariance = np.ones((2, 2)),
transition_matrices = np.eye(2),
observation_matrices = obs_mat,
observation_covariance = self.observation_cov,
transition_covariance = trans_cov)

means, covs = self.kf.filter(np.asarray(value2))
self.means = means[0]#mean for slope and intercept
self.covs = covs[0]#2X2 variance for slope and intercept
self.counter = self.counter + 1

else:
obs_mat = np.asarray([[value1, 1]])
means, covs = self.kf.filter_update(self.means,
self.covs,
observation = value2,
observation_matrix = obs_mat)
self.means = means.data
self.covs = covs

self.pred_currency2=self.means[0]*value1+self.means[1]

def pair_quantity(self,value1,value2,hedge_ratio,fund):
if hedge_ratio < 1:
self.Debug('Hedge ratio {} is negative, need to swap the pair'.format(hedge_ratio))
value1_unit = 0
value2_unit = 0
else:
lot=math.floor(fund/(value1*hedge_ratio+value2*1))#get lot
value1_unit = math.floor(hedge_ratio*lot)
value2_unit = math.floor(lot)
return value1_unit,value2_unit #number of unit to buy in currency 1 , currency 2

def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
Arguments:
data: Slice object keyed by symbol containing the stock data
'''

self.Kalman_update(data[self.currency1].Close,data[self.currency2].Close)
#self.std_upper=np.sqrt(self.covs[0,0]) * self.no_of_std
#self.std_lower=-1*self.std_upper
self.std_upper= self.no_of_std
self.std_lower= -self.no_of_std

self.Liquidate()#liquidate all
self.Liquidate()#liquidate all
self.spread_last = self.spread