Overall Statistics |
Total Trades 710 Average Win 0.58% Average Loss -0.20% Compounding Annual Return 230.802% Drawdown 16.000% Expectancy 1.521 Net Profit 185.438% Sharpe Ratio 2.8 Loss Rate 35% Win Rate 65% Profit-Loss Ratio 2.89 Alpha 0.841 Beta 0.236 Annual Standard Deviation 0.31 Annual Variance 0.096 Information Ratio 2.404 Tracking Error 0.313 Treynor Ratio 3.679 Total Fees $13955.22 |
import statsmodels.api as sm import numpy MAX_LEVERAGE = 1.0 alpha_samples = 10 volatility_samples = 15 long_only = True MAX_VOLATILITY = 0.10 class BasicTemplateAlgorithm(QCAlgorithm): def __init__(self): pass def Initialize(self): self.SetCash(100000) self.SetStartDate(2017,1,1) #self.SetEndDate(2007,12,31) self.SetBrokerageModel(BrokerageName.GDAX) self.SetBenchmark("BTCUSD") #self.universe = ["BTCUSD"] self.universe = ["BTCUSD", "ETHUSD", "LTCUSD"] #self.universe = ["BTCUSD", "ETHBTC", "LTCBTC"] #self.universe = ["BTCUSD", "ETHBTC", "LTCBTC","ETHUSD","LTCUSD"] for symbol in self.universe: self.AddCrypto(symbol, Resolution.Minute) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(0, 1), Action(self.Rebalance)) def OnData(self, slice): pass def min_variance(self, returns): cov = numpy.cov(returns) vu = numpy.ones(cov.shape[0]) if (numpy.linalg.det(cov) != 0): num = numpy.linalg.solve(cov,vu) den = numpy.dot(vu, num) w = num / den return w / numpy.sum(numpy.absolute(w)) else: return None def Rebalance(self): #try: last_price = {} prices = {} returns = {} for symbol in self.universe: last_price[symbol] = float(self.Securities[symbol].Price) prices[symbol] = numpy.asarray([float(x.Price) for x in self.History(symbol,alpha_samples,Resolution.Daily)] + [last_price[symbol]]) returns[symbol] = numpy.nan_to_num(prices[symbol][1:] / prices[symbol][:-1] - 1.0) """ TODO if (len(btc_returns) == len(eth_returns) == len(ltc_returns)): security_returns = numpy.vstack([btc_returns,eth_returns,ltc_returns]) else: self.Log("Missing data") return """ security_returns = numpy.asarray([returns[symbol] for symbol in self.universe]) if (len(security_returns) == 1): pfolio_weights = numpy.asarray([1.0]) else: pfolio_weights = self.min_variance(security_returns[:,-alpha_samples:]) if (pfolio_weights is None): self.Log("Min_variance error") return # long only if (long_only == True): index = 0 for weight,symbol in zip(pfolio_weights,symbol): if (weight < 0): if (symbol[-3:] == "BTC"): pfolio_weights[0] -= weight # convention BTCUSD is first pfolio_weights[index] = 0 index += 1 pfolio_returns = numpy.nan_to_num((pfolio_weights[:,None]*security_returns).sum(axis=0)) #self.Log("{0} {1} {2} {3} {4}".format(pfolio_returns[-1], pfolio_returns[-2], pfolio_returns[-3], pfolio_returns[-4], pfolio_returns[-5])) pfolio_std = numpy.std(pfolio_returns[-volatility_samples:]) #pfolio_std = numpy.std(numpy.clip(pfolio_returns[-volatility_samples:],None,0.0)) leverage = numpy.clip(MAX_VOLATILITY / (pfolio_std * numpy.sqrt(252)),0.0,MAX_LEVERAGE) #leverage = MAX_LEVERAGE for symbol,weight in zip(self.universe,pfolio_weights): if ((weight * leverage * float(self.Portfolio.TotalPortfolioValue) ) / last_price[symbol] < 0.01): weight = 0.0 self.SetHoldings(symbol, weight * leverage) self.Log("{0} {1: 4.2f} % {2: 4.2f} ".format(symbol, (weight * leverage) / MAX_LEVERAGE * 100.0, last_price[symbol])) self.Log("CASH {0: 4.2f} %".format((MAX_LEVERAGE - leverage) / MAX_LEVERAGE * 100.0)) #except Exception as e: pass