加密货币中的时间序列动量因子
登录后收藏学术论文
Stefan Hubrich
- T. Rowe Price Program for Charitable Giving
- ?T.Rowe Price
策略概要
该策略的投资范围包括11种加密货币。该策略将每种货币前一周的回报计算为动量因子,然后使用z-score对其进行标准化,以创建标准化变量。投资组合采用等权重,总风险敞口限制为10%,再除以可用加密货币的数量,从而实现最大10%的配置。如果动量因子高于零,则权重为正;如果低于零,则权重为负,这使得投资组合可以净多头或净空头。然而,由于做空加密货币不可行,因此建议在实际实施中采用只做多策略。投资组合每周进行再平衡,论文中还讨论了额外的基于风险的加权选项。
II. 策略合理性
该研究利用了四年的每日加密货币数据,捕捉了市场中的高波动性,这使得每周再平衡变得有效。加密货币的波动性允许在不借贷或不使用杠杆的情况下进行有意义的配置。研究表明,基于前期每周回报的动量因子在加密货币投资组合中产生了统计上显著的正阿尔法。这表明,尽管加密货币市场固有的波动性,但基于动量的策略在加密货币领域仍能获利。该研究还利用各种基准投资组合对动量因子投资组合的回报进行回归,结果表明高阿尔法和实质性信息比率,证实了动量在加密货币投资中的附加价值。
回测表现
波动率8.1%
夏普比率0.78
索提诺比率0.487
胜率52%
完整 Python 代码
from AlgorithmImports import *
import numpy as np
#endregion
class TimeSeriesMomentumCryptocurrencies(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2015, 1, 1)
self.SetCash(100000)
self.symbols = ['BTCUSD', 'ETCUSD', 'ETHUSD', 'LTCUSD', 'XMRUSD', 'ZECUSD']
self.data = {}
self.percentage_traded = 0.1
for symbol in self.symbols:
data = self.AddCrypto(symbol, Resolution.Daily, Market.Bitfinex)
data.SetFeeModel(CustomFeeModel())
data.SetLeverage(10)
self.data[symbol] = RollingWindow[float](5)
def OnData(self, data):
for symbol in self.data:
symbol_obj = self.Symbol(symbol)
if symbol_obj in data.Bars and data[symbol_obj]:
self.data[symbol].Add(data[symbol_obj].Value)
if self.Time.date().weekday() != 0:
return
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:
if symbol in data and data[symbol]:
self.SetHoldings(symbol, self.percentage_traded * weight[symbol])
# Custom fee model.
class CustomFeeModel(FeeModel):
def GetOrderFee(self, parameters):
fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
return OrderFee(CashAmount(fee, "USD"))