08 March 2021

Developing a Trading System for TWS API - Interactive Brokers Part 7

What is a trading system?

It is a set of rules that can be based on technical indicators, quantitative methods, fundamental analysis or simply a mix of all or some of them.


What are the elements of a full fledged trading system that can be deployed in Production?

  • An Entry Point
  • A Stop Loss / Trailing Stop Loss
  • An Exit Point

What is the ORB Trading Strategy?

ORB is an acronym for Open Range Breakout. Typically in this system, the first X minutes defines the Open Range. X can be 5 minutes or 30 minutes or any other. In the example given below, we consider a 5 minute candle stick as the open range (OR). The High of the 5 minute candle is considered the OR High and the Low of the 5 minute candle is considered the OR Low.

If any subsequent candle (after the first 5 minute) crosses above the OR High, it is considered a 'Buy Breakout'. If any subsequent candle (after the first 5 minute) crosses below the OR Low, it is considered a 'Sell Breakout'.

What is the NIFTY ORB Trading System?

For a Long Position:
  • Entry Condition - 5 minute candlestick Close above the High of the "Open Range"
  • Fixed Stop - This is a "False Stop". It is placed at 1 ATR below the Open Range Low. (This is primarily to handle emergency situations of sudden high volatility. Also many times the 5 minute candlestick will go below the Open Range Low but actually Close above the Open Range Low. These are operator driven false pushes which need to be weeded out. )
  • Exit Condition -  If the 5 min Candlestick Close below the Open Range Low or if time is more than 15:15 hrs. Indian Standard Time(IST)
For a Short Position, the rules are the inverse of what is mentioned for a Long position.

For this strategy, we have used the Nifty futures contract for the purpose of trading. So its called NIFTY ORB Trading System. Now let us dwell into the code

For the sake of modularity, the program has been divided into three separate individual python programs.
  1. tech_indicators.py : We need the ATR for taking the stop loss and we take the ATR from this program. 
  2. nifty_ORB_main_class.py: This is where I have defined the main class and all the callbacks from IB
  3. nifty_ORB_main_pgm.py: Here we deal with the core logic of the trading system.
I have detailed almost all aspects of the callbacks in some of my earlier posts. So in this post, I will focus primarily on the nifty_ORB_main_pgm.py

The NSE market opens only at 9:15 am. We want to start this program at 9:22 am. This will ensure that by the time we enter the program, we have the first 5 minute candle data.

def main():
    # Variables used in pgm
    # market_open_time = datetime.time(9,15)
    market_close_time = datetime.time(15,30)
    my_latest_entry_time = datetime.time(15,00) # Dont take any new positions after this time
    my_close_time = datetime.time(15,15) # Close all Open Positions and Open Orders at this time
    pgm_start_time = datetime.time(9,22) # Start the program Only after 9:22
    print ("Program Start Time is: {}. Is the TWS / IB Gateway program Running?".format(pgm_start_time))
    while datetime.datetime.now().time() <= pgm_start_time:
        time.sleep(10)

Next we get the Daily data and the 5 minute data. We write the daily data to a CSV file and then read it again. I used  to open up the csv and see the data for myself during trial runs, particularly to see if the latest data point (beyond the last 5 minute) has also been sent by IB. (sometime it happens). To ensure that we don't use that data point (above above over the last data point), I have the following code.

It is important to remember that the market opens at 9:15. When we make a call to reqHistoricalData at 9:16 or 9:19 , the latest datapoint will have a timestamp of 9:15. So when we make a call to reqHistoricalData at 9:20, the latest datapoint that we have received should have a timestamp of 9:15. Occasionally though, when it takes a few more seconds to retrieve the data from our callback, the timestamp is  9:20 instead of 9:15. In such a scenario, we dont want the latest datapoint.

            if (datetime.datetime.now().minute - df_minute['Date'].iloc[-1].minute) == 0: # then we have picked up the new candlestick that just started
                print('We have picked up the latest datapoint also')
                df_minute = df_minute[:-1] # Drop the last 1 row

Next I have used the order_place flag to see if any order has been paced. If no order is placed then we place the order if the entry conditions are fulfilled. If order_placed is True , the we check to see if the exit conditions are fulfilled and when it happens, we close the open position. When open position is successfully closed, at this point,  I have set the order_place flag to None. I use this to close the open orders.

Cheers Maadi and Happy Trading!!!

No comments:

Post a Comment