Overall Statistics
Total Trades
778
Average Win
0.00%
Average Loss
-0.02%
Compounding Annual Return
-99.998%
Drawdown
13.300%
Expectancy
-0.810
Net Profit
-13.477%
Sharpe Ratio
-23.227
Probabilistic Sharpe Ratio
0%
Loss Rate
84%
Win Rate
16%
Profit-Loss Ratio
0.18
Alpha
-5.775
Beta
0.728
Annual Standard Deviation
0.304
Annual Variance
0.092
Information Ratio
-37.558
Tracking Error
0.141
Treynor Ratio
-9.68
Total Fees
$545.63
class LiquidUniverseSelection(QCAlgorithm):
    
    filteredByPrice = None
    
    def Initialize(self):
        self.SetStartDate(2019, 1, 11)  
        self.SetEndDate(2019, 7, 1) 
        self.SetCash(100000)  
        self.AddUniverse(self.CoarseSelectionFilter)
        self.UniverseSettings.Resolution = Resolution.Daily

        #1. Set the leverage to 2
        self.UniverseSettings.Leverage = 2
       
    def CoarseSelectionFilter(self, coarse):
        sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True)
        filteredByPrice = [c.Symbol for c in sortedByDollarVolume if c.Price > 10]
        return filteredByPrice[:10] 

    def OnSecuritiesChanged(self, changes):
        self.changes = changes
        self.Log(f"OnSecuritiesChanged({self.Time}):: {changes}")
        
        for security in self.changes.RemovedSecurities:
            if security.Invested:
                self.Liquidate(security.Symbol)
        
        for security in self.changes.AddedSecurities:
            #2. Leave a cash buffer by setting the allocation to 0.18 instead of 0.2 
            self.SetHoldings(security.Symbol, 0.18)
#https://www.quantconnect.com/forum/discussion/6171/dynamic-crypto-universe-portfolio/p1


from HistoricalReturnsAlphamodel_mod import HistoricalReturnsAlphaModel_mod
from Execution.ImmediateExecutionModel import ImmediateExecutionModel
from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel

class CryptoMomentum(QCAlgorithm):

    def Initialize(self):
        self.stateData = {}
        self.SetStartDate(2019, 1, 19)  # Set Start Date
        self.SetEndDate(2019, 1, 22)
        self.SetCash(100000)  # Set Strategy Cash
        self.SetCash("BTC", 1)
        
        #self.__macd = self.MACD("SPY", 12, 26, 9, MovingAverageType.Exponential, Resolution.Daily)
        
        self.SetBrokerageModel(BrokerageName.Bitfinex, AccountType.Margin)
        
        self.SetBenchmark(Symbol.Create('BTCUSD', SecurityType.Crypto, Market.Bitfinex))
        
        # Add the pairs containing *BTC among all 346 pairs in Bitfinex
        symbols = ["LTCBTC", "ETHBTC", "ETCBTC", "RRTBTC", "ZECBTC", "XMRBTC",
                    "DSHBTC", "XRPBTC", "IOTBTC", "EOSBTC", "SANBTC", "OMGBTC",
                    "BCHBTC", "NEOBTC", "ETPBTC", "QTMBTC", "AVTBTC", "EDOBTC",
                    "BTGBTC", "DATBTC", "QSHBTC", "YYWBTC", "GNTBTC", "SNTBTC",
                    "BATBTC", "MNABTC", "FUNBTC", "ZRXBTC", "TNBBTC", "SPKBTC",
                    "TRXBTC", "RCNBTC", "RLCBTC", "AIDBTC", "SNGBTC", "REPBTC",
                    "ELFBTC", "IOSBTC", "AIOBTC", "REQBTC", "RDNBTC", "LRCBTC",
                    "WAXBTC", "DAIBTC", "CFIBTC", "AGIBTC", "MTNBTC", "SNGBTC",
                    "ODEBTC", "ANTBTC", "DTHBTC", "MITBTC", "STJBTC", "XLMBTC",
                    "XVGBTC", "BCIBTC", "MKRBTC", "VENBTC", "KNCBTC", "POABTC",
                    "LYMBTC", "UTKBTC", "VEEBTC", "DADBTC", "ORSBTC", "AUCBTC",
                    "POYBTC", "FSNBTC", "CBTBTC", "ZCNBTC", "SENBTC", "NCABTC",
                    "CNDBTC", "CTXBTC", "PAIBTC", "SEEBTC", "ESSBTC", "ATMBTC",
                    "HOTBTC", "DTABTC", "IQXBTC", "WPRBTC", "ZILBTC", "BNTBTC",
                    "XTZBTC", "OMNBTC", "DGBBTC", "BSVBTC", "BABBTC", "RBTBTC",
                    "RIFBTC", "VSYBTC", "BFTBTC"]
        
        Symbols = []
        for symbol in symbols:
            # add according forex data to add the crypto pairs
            self.AddCrypto(symbol[:3]+"USD", Resolution.Daily)
            Symbols.append(Symbol.Create(symbol, SecurityType.Crypto, Market.Bitfinex))
            
        self.SetUniverseSelection(ManualUniverseSelectionModel(Symbols))
        self.AddAlpha(HistoricalReturnsAlphaModel(7, Resolution.Daily))
        self.SetExecution(ImmediateExecutionModel())
        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
        
        
        self.__numberOfSymbols = 100
        self.__numberOfSymbolsFine = 5
        
    def OnData(self, data):    
        pass
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from clr import AddReference
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")

from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework.Alphas import *
from datetime import timedelta

class HistoricalReturnsAlphaModel_mod(AlphaModel):
    '''Uses Historical returns to create insights.'''

    def __init__(self, *args, **kwargs):
        '''Initializes a new default instance of the HistoricalReturnsAlphaModel class.
        Args:
            lookback(int): Historical return lookback period
            resolution: The resolution of historical data'''
        self.lookback = kwargs['lookback'] if 'lookback' in kwargs else 1
        self.resolution = kwargs['resolution'] if 'resolution' in kwargs else Resolution.Daily
        self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.lookback)
        self.symbolDataBySymbol = {}

    def Update(self, algorithm, data):
        '''Updates this alpha model with the latest data from the algorithm.
        This is called each time the algorithm receives data for subscribed securities
        Args:
            algorithm: The algorithm instance
            data: The new data available
        Returns:
            The new insights generated'''
        insights = []

        for symbol, symbolData in self.symbolDataBySymbol.items():
            if symbolData.CanEmit:

                direction = InsightDirection.Flat
                magnitude = symbolData.Return
                if magnitude > 0: direction = InsightDirection.Up
                if magnitude < 0: direction = InsightDirection.Down

                insights.append(Insight.Price(symbol, self.predictionInterval, direction, magnitude, None))

        return insights

    def OnSecuritiesChanged(self, algorithm, changes):
        '''Event fired each time the we add/remove securities from the data feed
        Args:
            algorithm: The algorithm instance that experienced the change in securities
            changes: The security additions and removals from the algorithm'''

        # clean up data for removed securities
        for removed in changes.RemovedSecurities:
            symbolData = self.symbolDataBySymbol.pop(removed.Symbol, None)
            if symbolData is not None:
                symbolData.RemoveConsolidators(algorithm)

        # initialize data for added securities
        symbols = [ x.Symbol for x in changes.AddedSecurities ]
        history = algorithm.History(symbols, self.lookback, self.resolution)
        if history.empty: return

        tickers = history.index.levels[0]
        for ticker in tickers:
            symbol = SymbolCache.GetSymbol(ticker)

            if symbol not in self.symbolDataBySymbol:
                symbolData = SymbolData(symbol, self.lookback)
                self.symbolDataBySymbol[symbol] = symbolData
                symbolData.RegisterIndicators(algorithm, self.resolution)
                symbolData.WarmUpIndicators(history.loc[ticker])


class SymbolData:
    '''Contains data specific to a symbol required by this model'''
    def __init__(self, symbol, lookback):
        self.Symbol = symbol
        self.ROC = RateOfChange('{}.ROC({})'.format(symbol, lookback), lookback)
        self.Consolidator = None
        self.previous = 0

    def RegisterIndicators(self, algorithm, resolution):
        self.Consolidator = algorithm.ResolveConsolidator(self.Symbol, resolution)
        algorithm.RegisterIndicator(self.Symbol, self.ROC, self.Consolidator)

    def RemoveConsolidators(self, algorithm):
        if self.Consolidator is not None:
            algorithm.SubscriptionManager.RemoveConsolidator(self.Symbol, self.Consolidator)

    def WarmUpIndicators(self, history):
        for tuple in history.itertuples():
            self.ROC.Update(tuple.Index, tuple.close)

    @property
    def Return(self):
        return float(self.ROC.Current.Value)

    @property
    def CanEmit(self):
        if self.previous == self.ROC.Samples:
            return False

        self.previous = self.ROC.Samples
        return self.ROC.IsReady

    def __str__(self, **kwargs):
        return '{}: {:.2%}'.format(self.ROC.Name, (1 + self.Return)**252 - 1)