Paper Trading with Interactive Brokers

In this tutorial, you will learn:

  • What is paper trading
  • How to start paper trading with Interactive Brokers

Intro to paper trading

Definition

A paper trade is a simulated trade that allows an investor to practice buying and selling without risking real money.
In this module, we will first set up a connection to Interactive Brokers Trader Workstation (IB TWS).
Then, we will learn how to create basic contracts, request market data, manage orders, and request account summary.

Setup Interactive Brokers API

Before setting up a connection to IB TWS, there are few tasks to be completed:
  1. Visit InteractiveBrokers website, and open an account
  2. Download IB API software from InteractiveBrokers GitHub account
  3. Download TWS software from InteractiveBrokers TWS
  4. Choose an IDE that you code in
  5. Subscribe to market data
For detailed instructions, please refer to InteractiveBrokers Initial Setup.

Connect to Interactive Brokers TWS

Once finish the setup, it’s time to connect to IB TWS. Use app.connect() to establish an API connection.
class App(EWrapper, EClient):

    def __init__(self):
        EClient.__init__(self, self)

# Establish API connection
# app.connect(ipAddress, portNumber, clientId)
app = App()
app.connect('127.0.0.1', 7497, 0)
app.run()
If you are successfully connected to IB TWS, you will get the below output in your terminal.
"Terminal output."

Create Basic Contracts

Then, let’s create basic contract objects (trading instruments) such as stocks, or fx pairs.
from ibapi.contract import Contract

# Create contracts - stocks
tsla_contract = Contract()
tsla_contract.symbol = "TSLA"
tsla_contract.secType = "STK"
tsla_contract.exchange = "ISLAND"
tsla_contract.currency = "USD"

# Create contracts - fx pairs
eurgbp_contract = Contract()
eurgbp_contract.symbol = "EUR"
eurgbp_contract.secType = "CASH"
eurgbp_contract.currency = "GBP"
eurgbp_contract.exchange = "IDEALPRO"

Request Market Data

Using the contract objects, we can request both streaming and historical market data.

Request Streaming Market Data

Use app.reqMktData() to request streaming market data.
class App(EWrapper, EClient):

    # Receive market data
    def tickPrice(self, tickerId, field, price, attribs):
        print("Tick Price. Ticker Id:", tickerId, ", TickType: ", TickTypeEnum.to_str(field),
              ", Price: ", price, ", CanAutoExecute: ", attribs.canAutoExecute,
              ", PastLimit: ", attribs.pastLimit, ", PreOpen: ", attribs.preOpen)

# Request market data
# app.reqMktData(tickerId, contract, genericTickList, snapshot, regulatorySnaphsot, mktDataOptions)
app.reqMktData(1, tsla_contract, '', False, False, None)
Note that if you haven’t subscribed the market data, you will receive 10-15 minute delayed streaming data. Before getting the delayed streaming data, make sure you use app.reqMarketDataType(3) to switch market data type to delayed data.
# Switch market data type
# 3 for delayed data
app.reqMarketDataType(3)

Request Historical Market Data

Use app.reqHistoricalData() to request historical bar data.
class App(EWrapper, EClient):

    # Receive historical bar data
    def historicalData(self, reqId, bar):
        print("HistoricalData. ReqId:", reqId, "BarData.", bar)

# Request historical bar data
# app.reqHistoricalData(tickerId, contract, endDateTime, durationString, barSizeSetting, whatToShow, useRTH, formatDate, keepUpToDate)
app.reqHistoricalData(1, eurgbp_contract, '', '1 M', '1 day', 'ASK', 1, 1, False, None)

Manage Orders

Now, let’s try to make an order!
First, write some methods in EWrapper that are required for receiving all relevant information on order opening, order status, and order execution.
class App(EWrapper, EClient):

    def nextValidId(self, orderId: int):
        super().nextValidId(orderId)
        self.nextorderId = orderId
        print('The next valid order id is: ', self.nextorderId)

    def orderStatus(self, orderId, status, filled, remaining, avgFillPrice, permId, parentId,
                    lastFillPrice, clientId, whyHeld, mktCapPrice):
        print("OrderStatus. Id: ", orderId, ", Status: ", status, ", Filled: ", filled,
              ", Remaining: ", remaining, ", AvgFillPrice: ", avgFillPrice,
              ", PermId: ", permId, ", ParentId: ", parentId, ", LastFillPrice: ", lastFillPrice,
              ", ClientId: ", clientId, ", WhyHeld: ", whyHeld, ", MktCapPrice: ", mktCapPrice)

    def openOrder(self, orderId, contract, order, orderState):
        print("OpenOrder. PermID: ", order.permId, ", ClientId: ", order.clientId,
              ", OrderId: ", orderId, ", Account: ", order.account, ", Symbol: ", contract.symbol,
              ", SecType: ", contract.secType, " , Exchange: ", contract.exchange,
              ", Action: ", order.action, ", OrderType: ", order.orderType,
              ", TotalQty: ", order.totalQuantity, ", CashQty: ", order.cashQty,
              ", LmtPrice: ", order.lmtPrice, ", AuxPrice: ", order.auxPrice,
              ", Status: ", orderState.status)

    def execDetails(self, reqId, contract, execution):
        print("ExecDetails. ", reqId, " - ", contract.symbol, ", ", contract.secType,
              ", ", contract.currency, " - ", execution.execId, ", ", execution.orderId,
              ", ", execution.shares , ", ", execution.lastLiquidity)

Place Orders

To place an order, use app.placeOrder() to submit an order.
# Place order
# app.placeOrder(orderId, contract, order)
app.placeOrder(app.nextorderId, eurgbp_contract, order)

Modify Orders

To modify the order, call app.placeOrder() again with the order id to be modified and the updated parameters.
# Modify order
order_id = 1
order.lmtPrice = '0.82'
app.placeOrder(order_id, eurgbp_contract, order)

Cancel Orders

To cancel an order by its order id, use app.cancelOrder().
To cancel all open orders, use app.reqGlobalCancel().
# Cancel order by order Id
app.cancelOrder(app.nextorderId)

# Cancel all open orders
app.reqGlobalCancel()

Request Account Summary

Lastly, use app.reqAccountSummary() to get the summarized account information.
class App(EWrapper, EClient):

    # Receive account summary
    def accountSummary(self, reqId:int, account:str, tag:str, value:str, currency:str):
          print("Acct Summary. ReqId:" , reqId , "Acct:", account, "Tag: ", tag, "Value:", value,
                "Currency:", currency)

# Request account summary in base currency
app.reqAccountSummary(9002, "All", "$LEDGER");

# Request account summary in HKD
app.reqAccountSummary(9002, "All", "$LEDGER:HKD");

References

Attention

All investments entail inherent risk. This repository seeks to solely educate people on methodologies to build and evaluate algorithmic trading strategies. All final investment decisions are yours and as a result you could make or lose money.