Overall Statistics |
Total Trades 1432 Average Win 0.23% Average Loss -0.17% Compounding Annual Return 8.397% Drawdown 6.500% Expectancy 0.457 Net Profit 76.840% Sharpe Ratio 1.216 Probabilistic Sharpe Ratio 72.310% Loss Rate 38% Win Rate 62% Profit-Loss Ratio 1.36 Alpha 0.056 Beta 0.025 Annual Standard Deviation 0.048 Annual Variance 0.002 Information Ratio -0.291 Tracking Error 0.151 Treynor Ratio 2.333 Total Fees $0.00 Estimated Strategy Capacity $12000.00 Lowest Capacity Asset XMRUSD E3 |
# https://quantpedia.com/strategies/time-series-momentum-factor-in-cryptocurrencies/ # # The investment universe consists of 11 cryptocurrencies (the full list can be found in the paper). Momentum factor is the prior week’s return # for each currency and therefore can be calculated as a sum of returns for the last week (the data are avalaible at coinmetrics.io). After that, # the momentum factor is standardized with z-scoring the variable longitudinally – de-meaning it and dividing by its standard deviation to create # a normalized variable with a zero mean and unit standard deviation, separately for each currency. Portfolio is equally weighted, where the # absolute weight is 10% divided by n, where 10% is the gross exposure limit (only 10% of portfolio is invested in cryptocurrencies) and n is # the number of currencies available for investment. The weight is positive when the longitudinally standardized momentum factor is above zero # and negative when this factor is below zero, this allows portfolios that can be net long or short the market. However, it is not possible to # short cryptocurrencies and the practical application would require for example the long only strategy. Portfolio is rebalanced weekly. Last # but not least, there are two weighting schemes, the second one is risk based and more information about it is in the paper, we have chosen # equally-weighted strategy for a representative purposes. import numpy as np class TimeSeriesMomentumCryptocurrencies(QCAlgorithm): def Initialize(self): self.SetStartDate(2015, 1, 1) self.SetCash(100000) self.symbols = ['BTCUSD', 'ETCUSD', 'ETHUSD', 'LTCUSD', 'XMRUSD', 'ZECUSD'] self.data = {} for symbol in self.symbols: self.AddCrypto(symbol, Resolution.Daily, Market.Bitfinex) self.data[symbol] = RollingWindow[float](5) self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), self.TimeRules.AfterMarketOpen(self.symbols[0]), self.Rebalance) def OnData(self, data): for symbol in self.data: symbol_obj = self.Symbol(symbol) if symbol_obj in data.Bars: if data[symbol_obj]: price = data[symbol_obj].Value if price != 0: self.data[symbol].Add(price) def Rebalance(self): perf_vol = {} for symbol in self.symbols: if self.data[symbol].IsReady: prices = np.array([x for x in self.data[symbol]]) perf = prices[0] / prices[-1] - 1 daily_returns = prices[:-1] / prices[1:] - 1 vol = np.std(daily_returns) perf_vol[symbol] = (perf, vol) # Volatility weighting total_vol = sum([1 / x[1][1] for x in perf_vol.items()]) if total_vol == 0: return weight = {} for symbol in perf_vol: vol = perf_vol[symbol][1] if vol != 0: weight[symbol] = (1.0 / vol) / total_vol else: weight[symbol] = 0 # Trade execution. long = [x[0] for x in perf_vol.items() if x[1][0] > 0] invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested] for symbol in invested: if symbol not in long: self.Liquidate(symbol) for symbol in long: self.SetHoldings(symbol, 0.1 * weight[symbol])