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