| Overall Statistics |
|
Total Trades 1658 Average Win 0.21% Average Loss -0.16% Compounding Annual Return 5.615% Drawdown 9.300% Expectancy 0.318 Net Profit 55.277% Sharpe Ratio 0.852 Probabilistic Sharpe Ratio 28.520% Loss Rate 43% Win Rate 57% Profit-Loss Ratio 1.31 Alpha 0.037 Beta 0.03 Annual Standard Deviation 0.046 Annual Variance 0.002 Information Ratio -0.287 Tracking Error 0.157 Treynor Ratio 1.318 Total Fees $1658.00 Estimated Strategy Capacity $200000.00 Lowest Capacity Asset ZECUSD E3 |
from AlgorithmImports import *
import numpy as np
class TimeSeriesMomentumCryptocurrencies(QCAlgorithm):
#EN LA PRIMERA PARTE OBTENEMOS 6 DATOS DE CRYPTOMONEDAS CON LAS CUALES CREAMOS UN MA
#CON EL PRECIO DE LAS 6
def Initialize(self):
self.SetStartDate(2015, 1, 1)
self.SetCash(10000)
self.symbols = ['BTCUSD', 'ETCUSD', 'ETHUSD', 'LTCUSD', 'XMRUSD', 'ZECUSD']
self.data = {}
for symbol in self.symbols:
data = self.AddCrypto(symbol, Resolution.Daily, Market.Bitfinex)
#data.SetLeverage(10)
self.data[symbol] = RollingWindow[float](5)
data.SetFeeModel(CustomFeeModel())
self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), self.TimeRules.At(0, 0), self.Rebalance)
#OBTENEMOS LOS PRECIOS DE LOS TICKERS PARA HACER TRADING
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:
#EN CADA SIMBOLO APLICAMOS UNA NORMALIZACION DE RETORNOS PERO A LA INVERSA
#NO SE PORQUE A LA INVERSA
prices = np.array([x for x in self.data[symbol]])
perf = prices[0] / prices[-1] - 1
#OBTENEMOS RETORNOS DIARIOS
daily_returns = prices[:-1] / prices[1:] - 1
vol = np.std(daily_returns)
perf_vol[symbol] = (perf, vol)
# CON BASE EN LA FORMULA DE VOLUME WEIGHT HACEMOS BUSCAMOS TOTAL VOL Y ES LA SUMA
#DE 1/VARIANZS DE LOS ACTIVOS
total_vol = sum([1 / x[1][1] for x in perf_vol.items()])
if total_vol == 0: return
#YA QUE TENEMOS EL TOTAL CON BASE EN LA FORMULA DIVIDIMOS 1/VOL DEL ACTIVO
#ENTRE TOTAL VOL ESTO NOS DIRA QUE % DEL PORTAFOLIO INVERTIR
#PARA CADA ACTIVO TENDRA UN PESO ESPECIFICO QUE ESTE SUMARA A 100
#EL WEIGHT SE MULTPILICA POR NUESTRO PORTADFOLIO
#EL WEIGHT TENDRA UN VALOR DE 0 A 1
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
#SI MOMENTUM ES POSITIVO ENTONCES PRESEGUIRA A ASIGNAR PESO EN EL ALLOCATION
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]
#SE CREA UN FOR PARA PODER ESTAR INVIRTIENDO EN CADA SIMBOLO
for symbol in invested:
#SI EL SIMBOLO NO ESTA EN LONG NO SE LE ASIGNARA NADA
if symbol not in long:
self.Liquidate(symbol)
#SI EL SIMBOLO ESTA EN LONG ENTONCES EL ALGORITMO LE PERMITIRA PASAR AL UTLIMO FILTRO
#EN EL QUE SERA PODER METER RISK ALLOCATION ESTO ES, SI EL MOMENTUM ES POSITIVO
#ENTONCES TENDRA EL PASE PARA QUE PUEDA OBTENER UN % DEL ALGORITMO, SI NO LO PASA
#NO ENTRARA
for symbol in long:
self.SetHoldings(symbol, 0.1 * weight[symbol])
class CustomFeeModel:
def GetOrderFee(self, parameters):
fee = max(1, parameters.Security.Price
* parameters.Order.AbsoluteQuantity
* 0.001 )
return OrderFee(CashAmount(fee, 'USD'))