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)