| Overall Statistics |
|
Total Trades 385 Average Win 7.21% Average Loss -0.89% Compounding Annual Return 471.983% Drawdown 23.600% Expectancy 1.602 Net Profit 974.912% Sharpe Ratio 2.665 Loss Rate 71% Win Rate 29% Profit-Loss Ratio 8.08 Alpha 2.227 Beta -65.462 Annual Standard Deviation 0.497 Annual Variance 0.247 Information Ratio 2.637 Tracking Error 0.497 Treynor Ratio -0.02 Total Fees $0.00 |
import numpy as np
import decimal as d
### <summary>
### Basic mean reversion of bitcoin, buy when above sma. Sell when below.
### </summary>
class BTCMeanReversion(QCAlgorithm):
def Initialize(self):
'''Initialise the data and resolution required, as well as the cash and start-end dates for the algorithm'''
self.SetStartDate(2016,10,07) #Set Start Date
self.SetEndDate(2018,02,15) #Set End Date
self.SetCash(100000) #Set Strategy Cash
self.SetBrokerageModel(BrokerageName.GDAX, AccountType.Cash)
self.AddCrypto("BTCUSD", Resolution.Hour)
self.short_sma = self.SMA("BTCUSD", 15, Resolution.Daily)
self.short_ema = self.EMA("BTCUSD", 5, Resolution.Daily)
def OnData(self, data):
btcPrice = self.Securities["BTCUSD"].Price
if btcPrice > self.short_sma.Current.Value:
if not self.Portfolio.Invested:
if btcPrice > self.short_ema.Current.Value:
self.SetHoldings("BTCUSD", 1)
elif self.Portfolio.Invested:
if btcPrice < self.short_ema.Current.Value:
self.SetHoldings("BTCUSD", 0)
else:
if self.Portfolio.Invested:
self.SetHoldings("BTCUSD", 0)
# Override SetHoldings to use limit orders (ratio is of totalPortfolioValue.)
def SetHoldings(self, symbol, ratio):
security = self.Securities[symbol]
if not security.IsTradable:
self.Debug("{} is not tradable.".format(symbol))
return # passive fail
ratio = d.Decimal(ratio)
price, quantity = security.Price, security.Holdings.Quantity
# Keep 2% Cash (for the limit order, rounding errors, and safety)
totalPortfolioValue = self.Portfolio.TotalPortfolioValue * d.Decimal(0.98)
# +0.1% Limit Order
# (to make sure it executes quickly and without much loss)
# (if you set the limit large it will act like a market order)
limit = 1.001
desiredQuantity = totalPortfolioValue * ratio / price
orderQuantity = desiredQuantity - quantity
# limit needs to be inverse when selling
limitPrice = price * d.Decimal(limit if orderQuantity >= 0 else 1/limit)
self.Log("Limit Order: {} coins @ ${} per coin".format(orderQuantity, limitPrice))
self.LimitOrder(symbol, orderQuantity, limitPrice)