Overall Statistics
Total Trades
3625
Average Win
0.21%
Average Loss
-1.18%
Compounding Annual Return
204.962%
Drawdown
42.800%
Expectancy
0.114
Net Profit
1632.368%
Sharpe Ratio
1.765
Probabilistic Sharpe Ratio
94.360%
Loss Rate
5%
Win Rate
95%
Profit-Loss Ratio
0.18
Alpha
0
Beta
0
Annual Standard Deviation
0.507
Annual Variance
0.257
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$185056.31
import numpy as np
import pandas as pd
from collections import deque

class QuantumOptimizedPrism(QCAlgorithm):

    def Initialize(self):
        
        '''Look back for breakout'''
        self.Lookback = 175
        
        self.SetBrokerageModel(BrokerageName.GDAX, AccountType.Cash)
        self.SetCash(100000)
        self.symbolList = ["BTCUSD","ETHUSD","LTCUSD"]
        self.rollingWindow = {}
        self.weights = {}
        self.flashcheck = {}
        
        for name in self.symbolList:
            self.AddCrypto(name, Resolution.Hour, Market.GDAX)
            self.rollingWindow["close_top_{0}".format(name)] = deque(maxlen=self.Lookback)
            self.weights[name] =  1 / len(self.symbolList)
            self.flashcheck[name] = 0
            
        self.SetStartDate(2017, 5, 1)
        self.SetBenchmark("BTCUSD")
        self.SetWarmUp(self.Lookback)
        
    def flashcrashcheck(self, symbol, price):
        '''Check for significant price change'''
        pchange = (price - self.flashcheck[symbol]) /  ((price + self.flashcheck[symbol])/2)  * 100
        self.flashcheck[symbol] = price
        
        if pchange >= 10:
            flash = True
            self.Debug("{} - FlashCrash: {}".format(self.Time, pchange))
        else:
            flash = False
            
        return flash
        
    def indicator(self, sym):
        '''Rolling quantile for upper and lower bounds'''
        top = pd.Series(self.rollingWindow["close_top_"+str(sym)]).quantile(0.99)
        bot = pd.Series(self.rollingWindow["close_top_"+str(sym)]).quantile(0.01)
        
        return top, bot

    def OnData(self, data):
        
        '''The data is bugged on this day for BTC'''
        if self.Time.day == 10 and self.Time.month == 8 and self.Time.year == 2018:
            return
        
        for symbol in self.symbolList:
            sym_price = data[symbol].Price
            stop = self.flashcrashcheck(symbol, sym_price)
            self.rollingWindow["close_top_{0}".format(symbol)].appendleft(sym_price)
            
            if not self.IsWarmingUp and not stop:
                top, bot = self.indicator(symbol)
                
                if sym_price >= top:
                    self.SetHoldings(symbol, self.weights[symbol])
                    
                elif sym_price <= bot:
                    self.SetHoldings(symbol, 0)
                else:
                    pass

            
    def OnOrderEvent(self, orderEvent):
        self.Debug("{} {}".format(self.Time, orderEvent.ToString()))

    def OnEndOfAlgorithm(self):
        self.Log("{} - TotalPortfolioValue: {}".format(self.Time, self.Portfolio.TotalPortfolioValue))
        self.Log("{} - CashBook: {}".format(self.Time, self.Portfolio.CashBook))