Overall Statistics
Total Trades
19
Average Win
125.27%
Average Loss
-7.53%
Compounding Annual Return
257.396%
Drawdown
29.400%
Expectancy
6.840
Net Profit
942.522%
Sharpe Ratio
3.427
Probabilistic Sharpe Ratio
94.916%
Loss Rate
56%
Win Rate
44%
Profit-Loss Ratio
16.64
Alpha
0.822
Beta
0.523
Annual Standard Deviation
0.507
Annual Variance
0.257
Information Ratio
-0.03
Tracking Error
0.489
Treynor Ratio
3.324
Total Fees
$418757.05
Estimated Strategy Capacity
$12000000.00
Lowest Capacity Asset
BTCUSD XJ
# Simone Pantaleoni btcusd kalman-mom strategy

from pykalman import KalmanFilter
import numpy as np

# ---------------------------------------------------------------------------
CRYPTO = 'BTCUSD'; PERIOD = 30; MOM_F = 3; MOM_M = 30; MOM_S = 60; LEV = 1.0;
# ---------------------------------------------------------------------------

class BollingerBreakoutAlgorithm(QCAlgorithm):

    def Initialize(self):

        self.SetStartDate(2020, 1, 1)
        self.SetEndDate(2021, 11, 1)
        self.SetCash(1000000)             
        self.SetBrokerageModel(BrokerageName.GDAX, AccountType.Cash)
        self.crypto = self.AddCrypto(CRYPTO, Resolution.Daily).Symbol
        self.rollingWindow = RollingWindow[TradeBar](PERIOD)
        self.Consolidate(self.crypto, Resolution.Daily, self.CustomBarHandler)
        self.SetWarmUp(1*PERIOD, Resolution.Daily)
        self.mom_fast = self.MOMP(self.crypto, MOM_F, Resolution.Daily)
        self.mom_mid = self.MOMP(self.crypto, MOM_M, Resolution.Daily)
        self.mom_slow = self.MOMP(self.crypto, MOM_S, Resolution.Daily)
        

    def CustomBarHandler(self, bar):
        self.rollingWindow.Add(bar)
        

    def OnData(self, data):
        if not self.rollingWindow.IsReady: return
    
        L = np.flipud(np.array([self.rollingWindow[i].Low for i in range(PERIOD)]))

        self.kf = KalmanFilter(transition_matrices = [1],
                 observation_matrices = [1],
                 initial_state_mean = 0,
                 initial_state_covariance = 1,
                 observation_covariance=1,
                 transition_covariance=.01)
        
        kf,_ = self.kf.filter(L)
        
        price = self.Securities[self.crypto].Close
        mom_fast = self.mom_fast.Current.Value
        mom_mid = self.mom_mid.Current.Value
        mom_slow = self.mom_slow.Current.Value
        mom_comb = float(mom_slow + mom_mid + 2 * mom_fast)
        
        self.Plot(self.crypto, "Price", self.Securities[self.crypto].Price)        
        self.Plot(self.crypto, "Kalman", kf[-1]) 
        self.Plot("Momentum", "mom_comb", mom_comb)
        self.Plot("Momentum", "zero", 0)
        
        holdings = self.Portfolio[self.crypto].Quantity
        
        if holdings <= 0:
             if price >= kf[-1] and mom_comb >= 0:
                    self.SetHoldings(self.crypto, 1.0)
        elif holdings >= 0:
            if price < kf[-1] and mom_comb < 0:
                self.Liquidate()