| Overall Statistics |
|
Total Trades 1733 Average Win 1.04% Average Loss -1.28% Compounding Annual Return 322.836% Drawdown 31.600% Expectancy 0.418 Net Profit 8325.983% Sharpe Ratio 1.934 Probabilistic Sharpe Ratio 98.849% Loss Rate 22% Win Rate 78% Profit-Loss Ratio 0.81 Alpha 1.161 Beta 0.137 Annual Standard Deviation 0.608 Annual Variance 0.369 Information Ratio 1.744 Tracking Error 0.614 Treynor Ratio 8.586 Total Fees $166282.43 |
import numpy as np
# Custom fee implementation
class CustomFeeModel:
def GetOrderFee(self, parameters):
fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.002
return OrderFee(CashAmount(fee, 'USD'))
class BollingerCryptoTrading(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2017, 1, 1) # Set Start Date
self.SetCash(10000) # Set Strategy Cash
self.lookback = 500 # History length
self.symbols = [
"BTCUSD",
"ETHUSD",
"LTCUSD",
]
for i in self.symbols:
self.AddCrypto(i, Resolution.Hour, Market.Bitfinex, AccountType.Margin)
self.Securities[i].SetFeeModel(CustomFeeModel())
self.position = dict.fromkeys(self.symbols, 0)
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(9, 30), Action(self.rebalance))
self.needs_rebalancing = False
def OnData(self, data):
# get price history
hist = self.History(self.symbols, self.lookback, Resolution.Hour)
self.Debug("Processing history of length %i" % len(hist))
for symbol in self.symbols:
if not symbol in hist.index:
self.position[symbol] = 0.0
continue
mean_price = (hist.loc[symbol]['close']).iloc[-200:].mean()
std_price = (hist.loc[symbol]['close']).iloc[-400:].std()
price = (hist.loc[symbol]['close']).iloc[-1]
if price < 1.0:
continue
upper = mean_price + 1.0 * std_price
lower = mean_price - 6.0 * std_price
vol = (hist.loc[symbol]['volume']).iloc[-1]
mean_vol = (hist.loc[symbol]['volume']).mean()
volume_aug = (vol / mean_vol) > 1.2
exit_short = price > mean_price and self.position[symbol] < 0.0
exit_long = price < mean_price and self.position[symbol] > 0.0
if exit_short or exit_long:
self.position[symbol] = 0
self.needs_rebalancing = True
if price > upper and volume_aug and self.position[symbol] != 1.0:
self.position[symbol] = 1.0
self.needs_rebalancing = True
elif price < lower and volume_aug and self.position[symbol] != -1.0:
self.position[symbol] = -1.0
self.needs_rebalancing = True
if self.needs_rebalancing:
self.rebalance()
def rebalance(self):
self.Debug("Rebalancing")
w_sum = 0.2
for symbol, w in self.position.items():
w_sum += np.abs(w)
if w == 0:
self.Liquidate(symbol)
targets_list = [
PortfolioTarget(symbol, w/w_sum)
for symbol, w in self.position.items()
if w != 0
]
self.SetHoldings(targets_list)
self.needs_rebalancing = False