Overall Statistics
Total Trades
227
Average Win
18.92%
Average Loss
-7.47%
Compounding Annual Return
318.262%
Drawdown
56.500%
Expectancy
1.219
Net Profit
223775.100%
Sharpe Ratio
3.46
Probabilistic Sharpe Ratio
98.567%
Loss Rate
37%
Win Rate
63%
Profit-Loss Ratio
2.53
Alpha
2.423
Beta
-0.087
Annual Standard Deviation
0.697
Annual Variance
0.486
Information Ratio
3.193
Tracking Error
0.717
Treynor Ratio
-27.856
Total Fees
$134619.42
Estimated Strategy Capacity
$11000.00
Lowest Capacity Asset
ETHUSD E3
class DualMomentum(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2016, 1, 1)  # Set Start Date
        #self.SetEndDate(2021, 2, 1)    # Set Start Date
        self.InitCash = 100000
        self.SetCash(self.InitCash)           # Set Strategy Cash
        
        self.equities = ["BTCUSD", "ETHUSD"]
        self.equityCombinedMomentum = {}
        
        self.bonds = ["UBT"]
        self.bondCombinedMomentum = {}
        
        self.InitCash = 100000
        self.MKT = self.AddCrypto("BTCUSD", Resolution.Daily, Market.Bitfinex).Symbol
        self.bitcoin = []
        
        for equity in self.equities:
            self.AddCrypto(equity, Resolution.Hour, Market.Bitfinex)
            self.Securities[equity].SetDataNormalizationMode(DataNormalizationMode.TotalReturn)
            self.equityCombinedMomentum[equity] = CombinedMomentum(self, equity)

        for bond in self.bonds:
            self.AddEquity(bond, Resolution.Hour)
            self.Securities[bond].SetDataNormalizationMode(DataNormalizationMode.TotalReturn)
            self.bondCombinedMomentum[bond] = CombinedMomentum(self, bond)
        
        self.leverage = 1
        self.Schedule.On(self.DateRules.Every(DayOfWeek.Friday), self.TimeRules.At(15, 0), self.rebalance)
    
    def shiftAssets(self, target, type):
        if not (self.Portfolio[target].Invested):
            for symbol in self.Portfolio.Keys:
                self.Liquidate(symbol)
            if not self.Portfolio.Invested:
                if type == 0:
                    self.MarketOnCloseOrder(target, self.CalculateOrderQuantity(target, 1 * self.leverage))
                else:
                    self.MarketOnCloseOrder(target, self.CalculateOrderQuantity(target, 1 * self.leverage))
    
    def rebalance(self):
        topEquities = sorted(self.equityCombinedMomentum.items(), key=lambda x: x[1].getValue(), reverse=True)
        topBonds = sorted(self.bondCombinedMomentum.items(), key=lambda x: x[1].getValue(), reverse=True)
        if (topEquities[0][1].getValue() > 0):
            self.shiftAssets(topEquities[0][0], 0)
        else:
            self.shiftAssets(topBonds[0][0], 1)
            
        # Plot Benchmark
        hist = self.History(self.MKT, 2, Resolution.Daily)['close'].unstack(level= 0).dropna() 
        self.bitcoin.append(hist[self.MKT].iloc[-1])
        bitcoin_perf = self.bitcoin[-1] / self.bitcoin[0] * self.InitCash
        self.Plot('Strategy Equity', 'BTCUSD', bitcoin_perf)

    def OnData(self, data):
        pass
    
class CombinedMomentum():
    def __init__(self, algo, symbol):
        self.fst = algo.MOMP(symbol,  15, Resolution.Daily)
        #self.med = algo.MOMP(symbol,  15, Resolution.Daily)
        #self.slw = algo.MOMP(symbol,  20, Resolution.Daily)
        #self.lng = algo.MOMP(symbol,  40, Resolution.Daily)
        
    def getValue(self):
        value = (self.fst.Current.Value)
        return value