| Overall Statistics |
|
Total Trades 606 Average Win 0.48% Average Loss -0.38% Compounding Annual Return -13.101% Drawdown 16.300% Expectancy -0.122 Net Profit -13.301% Sharpe Ratio -1.312 Probabilistic Sharpe Ratio 0.195% Loss Rate 61% Win Rate 39% Profit-Loss Ratio 1.27 Alpha -0.111 Beta 0.067 Annual Standard Deviation 0.077 Annual Variance 0.006 Information Ratio -0.941 Tracking Error 0.28 Treynor Ratio -1.489 Total Fees $106275.10 Estimated Strategy Capacity $34000000.00 Lowest Capacity Asset NQ XHYQYCUDLM9T |
from typing import Dict, List
# CONFIGS
RSI_period = 14
RSI_upper = 30
RSI_lower = 27
bar_size = timedelta(minutes=5)
portfolio_pct = .1
stoploss_dist = 20 # distance below high for stop loss
takeprofit_dist = 20 # distance above high for take profit
stoplimit_dist = 5 # distance b/w the stop and limit prices of a stop limit order
max_losses = 2 # max number of losses in a day
debug = True # turn off to reduce logging
# END CONFIGS
f = False
if f:
from AlgorithmImports import *
class Consulting(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019, 8, 1)
self.SetEndDate(2020, 8, 5)
self.SetCash(10000000)
future = self.AddFuture(Futures.Indices.NASDAQ100EMini, Resolution.Minute)
future.SetFilter(0, 90)
self.rsi = RelativeStrengthIndex(RSI_period)
self.consolidators: Dict[Symbol, QuoteBarConsolidator] = {}
self.just_bought = False
self.market_ticket = None # Market order ticket
self.stoploss_ticket = None # StopMarket stop loss ticket
self.takeprofit = None # take profit price
self.high = -1
self.last_rsi = None
self.loss_count = 0
self.curr_day = -1
self.quoteBar = None
self.prev_contract = None
self.stoploss_cumulative = 0
self.takeprofit_cumulative = 0
def OnData(self, data:Slice):
# new day
if self.curr_day != self.Time.day:
self.curr_day = self.Time.day
self.NewDay(data)
return
if not self.Securities[self.GetSymbol()].IsTradable:
return
def GetSymbol(self) -> Symbol:
'''
get current front month contract
'''
return list(self.consolidators.keys())[0]
def NewDay(self, data:Slice):
self.Plot('Stoploss count', 'count', self.stoploss_cumulative)
self.Plot('Take profit count', 'count', self.takeprofit_cumulative)
self.Reset()
self.PruneContracts()
self.ChooseContract(data)
def Reset(self):
self.Liquidate()
self.last_rsi = None
self.loss_count = 0
self.rsi.Reset()
self.ResetOrders()
def ChooseContract(self, data:Slice):
for chain in data.FutureChains:
contracts = [contract for contract in chain.Value]
if len(contracts) == 0:
self.Print('No contracts found')
return
contract = sorted(contracts, key=lambda k : k.OpenInterest, reverse=True)[0]
self.SetUpContract(contract.Symbol)
continue
def SetUpContract(self, symbol:Symbol):
# consolidate the contract data
consolidator = QuoteBarConsolidator(bar_size)
consolidator.DataConsolidated += self.OnDataConsolidated
self.SubscriptionManager.AddConsolidator(symbol, consolidator)
self.consolidators[symbol] = consolidator
def PruneContracts(self):
# unconsolidate untradeable symbols
for symbol in self.consolidators:
consolidator = self.consolidators[symbol]
self.SubscriptionManager.RemoveConsolidator(symbol, consolidator)
consolidator.DataConsolidated -= self.OnDataConsolidated
self.consolidators = {}
def ResetOrders(self):
self.market_ticket = None
self.stoploss_ticket = None
self.takeprofit = None
def Print(self, msg):
if debug:
self.Log(msg)
def OnDataConsolidated(self, sender, quoteBar:QuoteBar):
'''
5 minute consolidator
Update RSI, SetHoldings
'''
self.rsi.Update(self.Time, quoteBar.Close)
self.quoteBar = quoteBar
if not self.rsi.IsReady:
return
curr_rsi = self.rsi.Current.Value
if self.loss_count > max_losses:
return
# self.Plot('RSI', 'Value', curr_rsi)
if (not self.Portfolio.Invested and self.last_rsi
and self.last_rsi < RSI_lower and curr_rsi > RSI_upper):
if quoteBar.High - stoploss_dist < quoteBar.Close:
symbol = self.GetSymbol()
quantity = self.CalculateOrderQuantity(symbol, portfolio_pct)
self.just_bought = True
self.market_ticket = self.MarketOrder(symbol, quantity)
if quoteBar.High > self.high:
self.high = quoteBar.High
if self.stoploss_ticket:
updateFields = UpdateOrderFields()
updateFields.StopPrice = self.high - stoploss_dist
updateFields.LimitPrice = self.high - stoploss_dist - stoplimit_dist
self.stoploss_ticket.Update(updateFields)
if self.takeprofit and quoteBar.Close > self.takeprofit:
self.takeprofit_cumulative += 1
self.Liquidate()
self.ResetOrders()
self.last_rsi = curr_rsi
def OnOrderEvent(self, orderEvent: OrderEvent):
if self.just_bought:
self.just_bought = False
self.stoploss_ticket = self.StopLimitOrder(orderEvent.Symbol, -orderEvent.Quantity, self.quoteBar.High - stoploss_dist, self.quoteBar.High - stoploss_dist - stoplimit_dist)
self.takeprofit = self.quoteBar.High + stoploss_dist
elif self.stoploss_ticket and orderEvent.OrderId == self.stoploss_ticket.OrderId:
self.ResetOrders()
self.loss_count += 1
self.stoploss_cumulative += 1