An Introduction to TWS API with Jupyter Notebooks

Quant

What is an API?

According to Wikipedia, an Application Programming Interface (API) is defined as a software intermediary that facilitates communication between two different pieces of software. The TWS API was developed with the intention of allowing Interactive Brokers’ clients to automate common tasks in Trader Workstation, a desktop based trading application developed by IBKR.

TWS API has official clients for C#, C++, Java, Visual Basic, and Python. In addition, a number of third-party libraries have also been developed to make it easier for developers to work with TWS. One of these libraries is ib_insync, which allows for asynchronous communication with TWS, and allows us to write code in a linear programming style. ib_insync also allows us to use the API with Jupyter notebooks.

Getting Started

  1. Download and install the stable version of Trader Workstation: https://www.interactivebrokers.com/en/trading/tws.php
  2. Create and activate a new Python virtual environment.
  3. Install ibapi_insync.
  4. Install pandas for better data formatting.
  5. Start TWS and log in using a paper account.

Connecting to Trader Workstation

Communication between the client application and TWS takes place over a local socket connection defined by a host and port number. Unless you are deploying your deploying your app to a server the host will usually be your computer’s localhost, i.e. 127.0.0.1. In addition to the host, we also need to know the port number on which TWS is listening to requests. This can be found in TWS by clicking File -> Global Configuration -> API -> Settings -> Socket Port. When logging in with a paper account, this will usually be set to port 7497, however you are free to change this to any port that is open on the current device. Each client application connecting to TWS via the API must be identified by a unique clientId.

from ib_insync import *

HOST = ‘127.0.0.1’
PORT = 7497
CLIENT_ID = 1

util.startLoop() # Starts loop that allows us to work with the API in Jupyter notebooks – this is not necessary in a script
ib_client = IB() # Creates an instance of the IB client class
ib_client.connect(HOST, PORT, CLIENT_ID) # Connects to TWS

<IB connected to 127.0.0.1:7497 clientId=1>

We should now be connected to TWS. To check that everything is working correctly, let’s request the account summary for the currently signed in user using the accountSummary() method. This returns a list of account summary objects. Since we are using a single account, let’s just take a look at the first element of that list.

# Retrieve account summary for currently signed in user

accounts = ib_client.accountSummary()
print(f”Account currently signed in to TWS is: {accounts[0]}”)

Account currently signed in to TWS is: AccountValue(account='DU4760065', tag='AccountType', value='INDIVIDUAL', currency='', modelCode='')

Information about the user, including account type and client type, is returned to client application.

Requesting Contract details

Contracts are the fundamental blocks of most requests made using the API. Contract objects represent trading instruments such as stocks, futures, or options. Requests requiring contracts are first sent to TWS, where they are matched with available data, and, where ambiguity in the contract exists, an error is returned to the client. Ambiguous contracts can be resolved by passing additional data about the instrument, for example the contract ID, or the exchange on which the instrument is traded.

Let’s create two example contracts for which we will request the contract details. A forex contract for the currency pair EUR.USD, and the the AAPL@NASDAQ stock contract.

# Request details for Forex and Stock contracts

forex_contract = Forex(“EURUSD”)
stock_contract = Stock(“AAPL”, exchange=“ISLAND”)

full_forex_contract_details = ib_client.reqContractDetails(forex_contract)
full_stock_contract_details = ib_client.reqContractDetails(stock_contract)

print(f”Full contract details for EURUSD: {full_forex_contract_details}“, end = “\n\n”)
print(f”Full contract details for AAPL stock: {full_stock_contract_details}”)

Full contract details for EURUSD: [ContractDetails(contract=Contract(secType='CASH', conId=12087792, symbol='EUR', exchange='IDEALPRO', currency='USD', localSymbol='EUR.USD', tradingClass='EUR.USD'), marketName='EUR.USD', minTick=5e-05, sizeMinTick=1.0, orderTypes='ACTIVETIM,AD,ADJUST,ALERT,ALGO,ALLOC,AVGCOST,BASKET,CASHQTY,COND,CONDORDER,DAY,DEACT,DEACTDIS,DEACTEOD,GAT,GTC,GTD,GTT,HID,IOC,LIT,LMT,MIT,MKT,NONALGO,OCA,REL,RELPCTOFS,SCALE,SCALERST,STP,STPLMT,TRAIL,TRAILLIT,TRAILLMT,TRAILMIT,WHATIF', validExchanges='IDEALPRO', priceMagnifier=1, underConId=0, longName='European Monetary Union Euro', contractMonth='', industry='', category='', subcategory='', timeZoneId='US/Eastern', tradingHours='20220526:1715-20220527:1700;20220528:CLOSED;20220529:1715-20220530:1700;20220530:1715-20220531:1700;20220531:1715-20220601:1700;20220601:1715-20220602:1700', liquidHours='20220526:1715-20220527:1700;20220528:CLOSED;20220529:1715-20220530:1700;20220530:1715-20220531:1700;20220531:1715-20220601:1700;20220601:1715-20220602:1700', evRule='', evMultiplier=0, mdSizeMultiplier=1, aggGroup=4, underSymbol='', underSecType='', marketRuleIds='239', secIdList=[], realExpirationDate='', lastTradeTime='', stockType='', cusip='', ratings='', descAppend='', bondType='', couponType='', callable=False, putable=False, coupon=0, convertible=False, maturity='', issueDate='', nextOptionDate='', nextOptionType='', nextOptionPartial=False, notes='')]
Full contract details for AAPL stock: [ContractDetails(contract=Contract(secType='STK', conId=265598, symbol='AAPL', exchange='ISLAND', primaryExchange='NASDAQ', currency='USD', localSymbol='AAPL', tradingClass='NMS'), marketName='NMS', minTick=0.01, sizeMinTick=100.0, orderTypes='ACTIVETIM,AD,ADJUST,ALERT,ALLOC,AON,AVGCOST,BASKET,BENCHPX,CASHQTY,COND,CONDORDER,DAY,DEACT,DEACTDIS,DEACTEOD,DIS,GAT,GTC,GTD,GTT,HID,IOC,LIT,LMT,LOC,MIT,MKT,MOC,MTL,NGCOMB,NONALGO,OCA,OPG,PEGBENCH,RTH,SCALE,SCALERST,SNAPMID,SNAPMKT,SNAPREL,STP,STPLMT,TRAIL,TRAILLIT,TRAILLMT,TRAILMIT,WHATIF', validExchanges='SMART,AMEX,NYSE,CBOE,PHLX,ISE,CHX,ARCA,ISLAND,DRCTEDGE,BEX,BATS,EDGEA,CSFBALGO,JEFFALGO,BYX,IEX,EDGX,FOXRIVER,PEARL,NYSENAT,LTSE,MEMX,PSX', priceMagnifier=1, underConId=0, longName='APPLE INC', contractMonth='', industry='Technology', category='Computers', subcategory='Computers', timeZoneId='US/Eastern', tradingHours='20220527:0400-20220527:2000;20220528:CLOSED;20220529:CLOSED;20220530:CLOSED;20220531:0400-20220531:2000;20220601:0400-20220601:2000', liquidHours='20220527:0930-20220527:1600;20220528:CLOSED;20220529:CLOSED;20220530:CLOSED;20220531:0930-20220531:1600;20220601:0930-20220601:1600', evRule='', evMultiplier=0, mdSizeMultiplier=100, aggGroup=1, underSymbol='', underSecType='', marketRuleIds='26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26', secIdList=[TagValue(tag='ISIN', value='US0378331005')], realExpirationDate='', lastTradeTime='', stockType='COMMON', cusip='', ratings='', descAppend='', bondType='', couponType='', callable=False, putable=False, coupon=0, convertible=False, maturity='', issueDate='', nextOptionDate='', nextOptionType='', nextOptionPartial=False, notes='')]

Full information about the contract, including the contract ID, security type, exchange, trading hours, and the available order types are returned.

Note how the exchange was explicitly passed to the stock contract. This is done to retrieve data for just the stock traded on the NASDAQ (ISLAND) exchange. To get information about the stock on all exchanges, you can remove this parameter.

Realtime and Historical data requests

Now that we have some contracts set up, let’s request data for them. Clients using TWS API can request both live and historical market data for most instruments provided that they have the appropriate market data subscriptions. Interactive Brokers provides free market data for Forex contracts, so we will use this for the subsequent examples.

One of the simplest data requests that can be made using the API is a snapshot request. Snapshot requests, as the name suggest, provide an overview of the instrument’s market data at the time of request. In order to invoke a snapshot market data request, the reqMktData method can be used with the parameter snapshot set to True.

# Requesting a single snapshot

snapshot = ib_client.reqMktData(forex_contract, snapshot = True)
print(snapshot)

Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2022, 5, 27, 13, 16, 37, 246483, tzinfo=datetime.timezone.utc), bid=1.07147, bidSize=2800000.0, ask=1.07148, askSize=1000000.0, high=1.0765, low=1.06975, close=1.073, halted=0.0, ticks=[TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 37, 246483, tzinfo=datetime.timezone.utc), tickType=6, price=1.0765, size=0.0), TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 37, 246483, tzinfo=datetime.timezone.utc), tickType=7, price=1.06975, size=0.0), TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 37, 246483, tzinfo=datetime.timezone.utc), tickType=9, price=1.073, size=0.0), TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 37, 246483, tzinfo=datetime.timezone.utc), tickType=49, price=0.0, size=0)])

Where streaming market data is preferred, the snapshot parameter can be set to False. This will continuously retrieve ticker updates from TWS until the request is cancelled. The below example retrieves 10 ticks for the EUR.USD ticker. Ticks are spaced apart by 1 second.

# Request the next 10 ticks

NUM_TICKS = 10

ticker = ib_client.reqMktData(forex_contract, snapshot=False)
while NUM_TICKS != 0:
          ib_client.sleep(1)
          if ticker is None:
                    continue
          print(ticker, end = “\n\n”)
          NUM_TICKS = 1

ib_client.cancelMktData(forex_contract)

Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2022, 5, 27, 13, 16, 48, 312572, tzinfo=datetime.timezone.utc), bid=1.07147, bidSize=1000000.0, ask=1.07148, askSize=3000000.0, prevBid=1.07148, prevBidSize=2000000.0, prevAsk=1.07149, prevAskSize=2000000.0, high=1.0765, low=1.06975, close=1.073, halted=0.0, ticks=[TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 48, 312572, tzinfo=datetime.timezone.utc), tickType=1, price=1.07147, size=1000000.0), TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 48, 312572, tzinfo=datetime.timezone.utc), tickType=2, price=1.07148, size=3000000.0)])
Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2022, 5, 27, 13, 16, 49, 226633, tzinfo=datetime.timezone.utc), bid=1.07148, bidSize=1000000.0, ask=1.07149, askSize=3000000.0, prevBid=1.07147, prevBidSize=2000000.0, prevAsk=1.07148, prevAskSize=4000000.0, high=1.0765, low=1.06975, close=1.073, halted=0.0, ticks=[TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 49, 226633, tzinfo=datetime.timezone.utc), tickType=1, price=1.07148, size=1000000.0), TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 49, 226633, tzinfo=datetime.timezone.utc), tickType=2, price=1.07149, size=3000000.0)])
Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2022, 5, 27, 13, 16, 50, 717092, tzinfo=datetime.timezone.utc), bid=1.07149, bidSize=1000000.0, ask=1.0715, askSize=1000000.0, prevBid=1.07148, prevBidSize=2000000.0, prevAsk=1.07149, prevAskSize=3000000.0, high=1.0765, low=1.06975, close=1.073, halted=0.0, ticks=[TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 50, 717092, tzinfo=datetime.timezone.utc), tickType=3, price=1.0715, size=1000000.0)])
Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2022, 5, 27, 13, 16, 51, 518501, tzinfo=datetime.timezone.utc), bid=1.07142, bidSize=1000000.0, ask=1.07144, askSize=3000000.0, prevBid=1.07143, prevBidSize=2000000.0, prevAsk=1.07143, prevAskSize=1000000.0, high=1.0765, low=1.06975, close=1.073, halted=0.0, ticks=[TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 51, 518501, tzinfo=datetime.timezone.utc), tickType=1, price=1.07142, size=1000000.0)])
Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2022, 5, 27, 13, 16, 52, 618759, tzinfo=datetime.timezone.utc), bid=1.07142, bidSize=2000000.0, ask=1.07144, askSize=3500000.0, prevBid=1.07143, prevBidSize=1000000.0, prevAsk=1.07143, prevAskSize=3000000.0, high=1.0765, low=1.06975, close=1.073, halted=0.0, ticks=[TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 52, 618759, tzinfo=datetime.timezone.utc), tickType=0, price=1.07142, size=2000000.0)])
Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2022, 5, 27, 13, 16, 53, 421083, tzinfo=datetime.timezone.utc), bid=1.07142, bidSize=2000000.0, ask=1.07144, askSize=3000000.0, prevBid=1.07143, prevBidSize=1000000.0, prevAsk=1.07143, prevAskSize=3500000.0, high=1.0765, low=1.06975, close=1.073, halted=0.0, ticks=[TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 53, 421083, tzinfo=datetime.timezone.utc), tickType=3, price=1.07144, size=3000000.0)])
Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2022, 5, 27, 13, 16, 53, 921868, tzinfo=datetime.timezone.utc), bid=1.07142, bidSize=2000000.0, ask=1.07144, askSize=2000000.0, prevBid=1.07143, prevBidSize=1000000.0, prevAsk=1.07143, prevAskSize=3000000.0, high=1.0765, low=1.06975, close=1.073, halted=0.0, ticks=[TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 53, 921868, tzinfo=datetime.timezone.utc), tickType=3, price=1.07144, size=2000000.0)])
Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2022, 5, 27, 13, 16, 55, 125149, tzinfo=datetime.timezone.utc), bid=1.07142, bidSize=3000000.0, ask=1.07144, askSize=2000000.0, prevBid=1.07143, prevBidSize=2000000.0, prevAsk=1.07143, prevAskSize=3000000.0, high=1.0765, low=1.06975, close=1.073, halted=0.0, ticks=[TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 55, 125149, tzinfo=datetime.timezone.utc), tickType=0, price=1.07142, size=3000000.0)])
Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2022, 5, 27, 13, 16, 55, 125149, tzinfo=datetime.timezone.utc), bid=1.07142, bidSize=3000000.0, ask=1.07144, askSize=2000000.0, prevBid=1.07143, prevBidSize=2000000.0, prevAsk=1.07143, prevAskSize=3000000.0, high=1.0765, low=1.06975, close=1.073, halted=0.0, ticks=[TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 55, 125149, tzinfo=datetime.timezone.utc), tickType=0, price=1.07142, size=3000000.0)])
Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2022, 5, 27, 13, 16, 55, 125149, tzinfo=datetime.timezone.utc), bid=1.07142, bidSize=3000000.0, ask=1.07144, askSize=2000000.0, prevBid=1.07143, prevBidSize=2000000.0, prevAsk=1.07143, prevAskSize=3000000.0, high=1.0765, low=1.06975, close=1.073, halted=0.0, ticks=[TickData(time=datetime.datetime(2022, 5, 27, 13, 16, 55, 125149, tzinfo=datetime.timezone.utc), tickType=0, price=1.07142, size=3000000.0)])

When developing trading strategies, API user’s may also want to retrieve historical data. This can be easily done using the reqHistoricalData method. Note the endDateTime parameter. Setting this to a particular point in time will result in data prior to that point being returned. Where the parameter is left as a blank string, the current time is used instead. The following request retrieves previous month’s data with a bar size of 1 day.

# Request historical bars for the last month with bar size of 1 day

historical_bars = ib_client.reqHistoricalData(
    forex_contract,
    endDateTime = “”,
    durationStr = “1 M”,
    barSizeSetting = “1 day”,
    whatToShow = “MIDPOINT”,
    useRTH = False,
    formatDate = 1
)

df = util.df(historical_bars)
print(df)

dateopen high low closevolumeaveragebarCount
02022-04-281.05610 1.05650 1.04715 1.04990-1.0-1.0-1
12022-04-291.05005 1.05930 1.04915 1.05425-1.0-1.0-1
22022-05-021.05440 1.05685 1.04905 1.05065-1.0-1.0-1
32022-05-031.05040 1.05780 1.04925 1.05200-1.0-1.0-1
42022-05-041.05220 1.06310 1.05060 1.06200-1.0-1.0-1
52022-05-051.06255 1.06420 1.04925 1.05395-1.0-1.0-1
62022-05-061.05450 1.05990 1.04830 1.05435-1.0-1.0-1
72022-05-091.05480 1.05925 1.04955 1.05605-1.0-1.0-1
82022-05-101.05625 1.05855 1.05255 1.05285-1.0-1.0-1
92022-05-111.05325 1.05775 1.05020 1.05125-1.0-1.0-1
102022-05-121.05150 1.05295 1.03540 1.03805-1.0-1.0-1
112022-05-131.03795 1.04195 1.03495 1.04135-1.0-1.0-1
122022-05-161.04065 1.04430 1.03890 1.04330-1.0-1.0-1
132022-05-171.04325 1.05560 1.04285 1.05505-1.0-1.0-1
142022-05-181.05495 1.05640 1.04605 1.04630-1.0-1.0-1
152022-05-191.04625 1.06070 1.04600 1.05845-1.0-1.0-1
162022-05-201.05860 1.05995 1.05330 1.05610-1.0-1.0-1
172022-05-231.05635 1.06975 1.05600 1.06905-1.0-1.0-1
182022-05-241.06900 1.07490 1.06610 1.07360-1.0-1.0-1
192022-05-251.07290 1.07390 1.06425 1.06780-1.0-1.0-1
202022-05-261.06820 1.07320 1.06625 1.07280-1.0-1.0-1
212022-05-271.07255 1.07650 1.06970 1.07150-1.0-1.0-1

When requesting historical data, it may also be important to know how far back data is available. This can be found for a contract using the reqHeadTimestamp method.

# Request timestamp of earliest available data for this contract

head_timestamp = ib_client.reqHeadTimeStamp(forex_contract, “MIDPOINT”, useRTH = True)
print(f”Head timestamp for EURUSD: {head_timestamp}”)

Head timestamp for EURUSD: 2005-03-09 04:30:00

Placing & Managing Orders

Now that we can request contracts and market data, it’s time to move on to the most important aspect of TWS API – order placement and management.

First we’ll place an example limit order for the AAPL@NASDAQ stock contract. To ensure that the order is not immediately filled, we’ll set the limit price to a value well above the current ask price. Optional parameters such as the time-in-force, and whether to use certain price management algorithms can also be passed into the order object at this stage. Once the order is set up, orders can be placed for specific contracts using the placeOrder method by passing both the contract and order details.

# Create a LMT type order to buy 1 contract of AAPL stock

order_details = Order(
    action = “BUY”,
    orderType = “LMT”,
    totalQuantity = 1,
    lmtPrice = 999,
    tif = “DAY”,
    usePriceMgmtAlgo = True

)
order = ib_client.placeOrder(stock_contract, order_details)

To get the status for all open orders we can use the reqOpenOrders method. An open order is an order that has yet to be filled. Filled orders are referred to as executions.

# Request open orders from TWS

open_orders = ib_client.reqOpenOrders()
[print(order, end = “\n\n”) for order in open_orders]

Order(orderId=62, clientId=1, permId=338637127, action='BUY', totalQuantity=1.0, orderType='LMT', lmtPrice=999.0, auxPrice=0.0, tif='DAY', ocaType=3, displaySize=2147483647, trailStopPrice=1000.0, volatilityType=0, deltaNeutralOrderType='None', deltaNeutralOpenClose='?', referencePriceType=0, account='DU4760065', clearingIntent='IB', adjustedOrderType='None', cashQty=0.0, dontUseAutoPriceForHedge=True, usePriceMgmtAlgo=True)
[None]

To modify orders, we can call the placeOrder method again with the updated order details. Information such as the order ID need to be passed into the updated Order object to ensure it’s correctly matched to an existing order in TWS. Let’s modify the limit price field for the order above to a more sensible value.

# Modify the order to be of type

existing_order = open_orders[0]
existing_order.lmtPrice = 200
ib_client.placeOrder(stock_contract, existing_order)

Trade(contract=Stock(symbol='AAPL', exchange='ISLAND'), order=Order(orderId=62, clientId=1, permId=338637127, action='BUY', totalQuantity=1.0, orderType='LMT', lmtPrice=999.0, auxPrice=0.0, tif='DAY', usePriceMgmtAlgo=True), orderStatus=OrderStatus(orderId=62, status='PreSubmitted', filled=0.0, remaining=1.0, avgFillPrice=0.0, permId=338637127, parentId=0, lastFillPrice=0.0, clientId=1, whyHeld='', mktCapPrice=0.0), fills=[], log=[TradeLogEntry(time=datetime.datetime(2022, 5, 27, 13, 17, 11, 752164, tzinfo=datetime.timezone.utc), status='PendingSubmit', message='', errorCode=0), TradeLogEntry(time=datetime.datetime(2022, 5, 27, 13, 17, 12, 265494, tzinfo=datetime.timezone.utc), status='PreSubmitted', message='', errorCode=0), TradeLogEntry(time=datetime.datetime(2022, 5, 27, 13, 17, 37, 833807, tzinfo=datetime.timezone.utc), status='PreSubmitted', message='Modify', errorCode=0)])

If we request openOrders once more, we should see the first order’s limit price has changed to $200.

open_orders = ib_client.reqOpenOrders()
print(open_orders[0])

Order(orderId=62, clientId=1, permId=338637127, action='BUY', totalQuantity=1.0, orderType='LMT', lmtPrice=200.0, auxPrice=0.0, tif='DAY', ocaType=3, displaySize=2147483647, volatilityType=0, deltaNeutralOrderType='None', deltaNeutralOpenClose='?', referencePriceType=0, account='DU4760065', clearingIntent='IB', adjustedOrderType='None', cashQty=0.0, dontUseAutoPriceForHedge=True, usePriceMgmtAlgo=True)

Finally, let’s cancel all outstanding orders. This can be done by looping over all existing orders and passing them to the cancelOrder method.

# Cancel all open orders

for order in open_orders:
     ib_client.cancelOrder(order)

Conclusion

The examples above serve as a very general introduction into the capabilities of TWS API. Some of the content not covered in this introduction includes market scanners, functionalities for financial advisors, options calculations, and the various order types and price management algorithms. For a full list of functionality we recommend taking a look at the official TWS API documentation: https://interactivebrokers.github.io/tws-api

Example use cases of TWS API can be found on the IBKR Quant Blog: https://www.tradersinsight.news/category/ibkr-quant-news/ . The official download for TWS API also contains sample client apps.

Disclosure: Interactive Brokers

The analysis in this material is provided for information only and is not and should not be construed as an offer to sell or the solicitation of an offer to buy any security. To the extent that this material discusses general market activity, industry or sector trends or other broad-based economic or political conditions, it should not be construed as research or investment advice. To the extent that it includes references to specific securities, commodities, currencies, or other instruments, those references do not constitute a recommendation by IBKR to buy, sell or hold such investments. This material does not and is not intended to take into account the particular financial conditions, investment objectives or requirements of individual customers. Before acting on this material, you should consider whether it is suitable for your particular circumstances and, as necessary, seek professional advice.

The views and opinions expressed herein are those of the author and do not necessarily reflect the views of Interactive Brokers LLC, its affiliates, or its employees.

Any trading symbols displayed are for illustrative purposes only and are not intended to portray recommendations.

In accordance with EU regulation: The statements in this document shall not be considered as an objective or independent explanation of the matters. Please note that this document (a) has not been prepared in accordance with legal requirements designed to promote the independence of investment research, and (b) is not subject to any prohibition on dealing ahead of the dissemination or publication of investment research.

Disclosure: API Examples Discussed

Throughout the lesson, please keep in mind that the examples discussed are purely for technical demonstration purposes, and do not constitute trading advice. Also, it is important to remember that placing trades in a paper account is recommended before any live trading.

Disclosure: Order Types / TWS

The order types available through Interactive Brokers LLC’s Trader Workstation are designed to help you limit your loss and/or lock in a profit. Market conditions and other factors may affect execution. In general, orders guarantee a fill or guarantee a price, but not both. In extreme market conditions, an order may either be executed at a different price than anticipated or may not be filled in the marketplace.

Disclosure: Forex

There is a substantial risk of loss in foreign exchange trading. The settlement date of foreign exchange trades can vary due to time zone differences and bank holidays. When trading across foreign exchange markets, this may necessitate borrowing funds to settle foreign exchange trades. The interest rate on borrowed funds must be considered when computing the cost of trades across multiple markets.