| 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)