Hello,

I’m still new to QuantConnect and I used the recent time to read a lot in the community in order to get my head around the main concepts. In parallel I tried to practice with code.

I would like to code a basic framework that can handle the most common parts like:

  • defining the main parameters (account size, backtesting timeframe, symbol, market, resolution, brokerage, leverage, etc.)
  • defining the criteria/rules for the trading setup (including indicators if required)
  • defining the risk and order management (position size, trade entry, stop loss, take profit)
  • using Debug function 
  • using RollingWindow function
  • using Schedule function

 

Please find below my example code.

This example strategy is NOT designed to be profitable, but for learning purposes only! :-)

In this example the strategy is long-only and consists of 3 simple criteria:

  • if fast EMA > slow EMA then long
  • only enter position between 9-10am UTC
  • only have one position at a time

 

The RollingWindow function is used to derive the entry, stop loss and take profit levels from the previous candle:

  • stop buy at previous candle high
  • stop loss at previous candle low
  • take profit at previous candle high plus 10%

The Schedule function is used to handle the required trading time slot (9-10am UTC).

The Risk Management is determined by 2 requirements:

  • max risk per trade = 0.5% from portfolio value
  • max equity per trade = portfolio value * max leverage * 25%

 

I would like to use this first example code to identify and solve the main issues and potential misconceptions that I (probably) have and then take it further from there.

Your feedback and comments are highly appreciated!

Cheers, 

Thom

 

class SessionTrend(QCAlgorithm):

def Initialize(self):

# input
self.SetTimeZone('Europe/London')

self.SetCash(100000)
self.SetStartDate(2019,4,1)
self.SetEndDate(2019,4,30)

self._max_risk_per_trade_factor = 0.005
self._max_equity_per_trade_factor = 0.25
self._maxLeverage_factor = 20.0

self._symbol = 'EURUSD'
self._pricePrecision = 4
self._resolution = Resolution.Hour
self._market = Market.Oanda
self._brokerage = BrokerageName.OandaBrokerage
self.SetBrokerageModel(self._brokerage, AccountType.Margin)

# add Price Data to data
self._eurusd = self.AddForex(self._symbol, self._resolution, self._market, leverage=10.0)

# RollingWindow
self._window = RollingWindow[QuoteBar](2)

# indicators
self._ema_fast = self.EMA(self._symbol, 8, self._resolution)
self._ema_slow = self.EMA(self._symbol, 21, self._resolution)

# schedule
self._session = False
self.Schedule.On(self.DateRules.EveryDay(self._symbol), self.TimeRules.At(9, 0), Action(self._sessionOn))
self.Schedule.On(self.DateRules.EveryDay(self._symbol), self.TimeRules.At(10, 0), Action(self._sessionOff))


def _sessionOn(self):
self._session = True

def _sessionOff(self):
self._session = False


def OnData(self, data):

# retrieve current price data
self._currentPrice = self.Securities[self._symbol].Close

# add price data to RollingWindow
self._window.Add(data[self._symbol])

# wait for indicator to be ready.
if not self._ema_slow.IsReady: return

# Setup criteria
_invested = self.Portfolio[self._symbol].Invested
_ema_bullish = (self._ema_fast.Current.Value > self._ema_slow.Current.Value)
_condition = not _invested and self._session and _ema_bullish


# long orders
if _condition:
# trade setup
self._stopBuy = round(self._window[1].High, self._pricePrecision)
self._stopLoss = round(self._window[1].Low, self._pricePrecision)
self._takeProfit = round(self._window[1].High * 1.1, self._pricePrecision)

# risk management
self._max_equity_per_trade = self.Portfolio.TotalPortfolioValue * self._maxLeverage_factor * self._max_equity_per_trade_factor # max allowed equity per trade [currency]
self._max_risk_per_trade = round(self.Portfolio.TotalPortfolioValue * self._max_risk_per_trade_factor, 0) # max allowed risk per trade [currency]
self._risk_per_unit = round(self._stopBuy - self._stopLoss, self._pricePrecision) # risk per unit [currency]
self._max_quantity_equity = round(self._max_equity_per_trade / self._stopBuy, 0) # max quantity per trade [nr. of contracts] based on max equity
self._max_quantity_risk = round(self._max_risk_per_trade / self._risk_per_unit, 0) # max quantity per trade [nr. of contracts] based on max risk
self._quantity = round(min(self._max_quantity_equity, self._max_quantity_risk), 0) # number of contracts to be ordered

# order management
self._marketBuyTicket = self.MarketOrder(self._symbol, self._quantity, False, 'market buy')
self._limitSellTicket = self.LimitOrder(self._symbol, -self._quantity, self._takeProfit, 'target limit sell')
self._stopMarketSellTicket = self.StopMarketOrder(self._symbol, -self._quantity, self._stopLoss, 'stop market sell')

self.Debug(f'order time: {self.Time}, tag: {self._marketBuyTicket.Tag}, quantity: {self._marketBuyTicket.Quantity}, fill price: {self._marketBuyTicket.AverageFillPrice}, status: {self._marketBuyTicket.Status}')


def OnOrderEvent(self, orderEvent):
_orderFromEvent = self.Transactions.GetOrderById(orderEvent.OrderId)
_orderTicketFromEvent = self.Transactions.GetOrderTicket(orderEvent.OrderId)
_openOrderTickets = self.Transactions.GetOrderTickets()

# OCO
if _orderTicketFromEvent.Status == OrderStatus.Filled:
# cancel stop loss order
if _orderTicketFromEvent.Tag == 'target limit sell':
for _ticket in _openOrderTickets:
if _ticket.Tag == 'stop market sell':
self.Debug(f'event time: {orderEvent.UtcTime}, event: {_orderTicketFromEvent.Tag}, cancelled order: {_ticket.Tag}')
self.Transactions.CancelOrder(_ticket.OrderId)
# cancel take profit order
elif _orderTicketFromEvent.Tag == 'stop market sell':
for _ticket in _openOrderTickets:
if _ticket.Tag == 'target limit sell':
self.Debug(f'event time: {orderEvent.UtcTime}, event: {_orderTicketFromEvent.Tag}, cancelled order: {_ticket.Tag}')
self.Transactions.CancelOrder(_ticket.OrderId)