Fully automated trading with Deephaven and Interactive Brokers
· 7 min read
Chip Kent
Chief Data Scientist @Deephaven
Use Deephaven and IB to build your own fully automated market maker.
Many of the world's largest and most profitable hedge funds, such as Renaissance Technologies, Virtu, Citadel, Two Sigma, Tower Research, and Jump Trading, use algorithms to determine when to buy and sell stocks, futures, bonds, options, and other securities. They have replaced human traders with emotionless computers that can act at speeds far beyond human cognition.
If you have a brilliant algorithmic trading idea, you no longer need to join a top hedge fund to trade it.
Using Deephaven and Interactive Brokers, a very popular brokerage in the quantitative finance world, you can build your own fully-automated trading strategy. All you need is deephaven-ib.
To illustrate the process, let's write a market maker.
"Market maker" may be an unfamiliar term, but the concept is straightforward. A market maker is a strategy that quotes both a buy and a sell price for a security, hoping to make a profit by buying at the low price and selling at the high price. Market makers typically turn over positions quickly, hoping to make a small amount of profit on each trade.
To learn how we put this dashboard and automated market making system together, read on.
from ibapi.contract import Contract from ibapi.order import Order import deephaven_ib as dhib from deephaven.updateby import ema_time from deephaven import time_table from deephaven.plot import Figure from deephaven.plot.selectable_dataset import one_click from deephaven.plot import PlotStyle ########################################################################### # WARNING: THIS SCRIPT EXECUTES TRADES!! ONLY USE ON PAPER TRADING ACCOUNTS ########################################################################### print("==============================================================================================================") print("==== Create a client and connect.") print("==== ** Accept the connection in TWS **") print("==============================================================================================================") client = dhib.IbSessionTws(host="host.docker.internal", port=7497, client_id=0, download_short_rates=False, read_only=False) print(f"IsConnected: {client.is_connected()}") client.connect() print(f"IsConnected: {client.is_connected()}") ## Setup account ="DU4943848" max_position_dollars =10000.0 ema_t ="00:02:00"
Once that is done, it is time to get real-time input data tables from Interactive Brokers. Our market maker will need market prices, positions, and orders. All of this data is available in the deephaven-ib client.
Next, it is time to subscribe to data for the securities we want to make markets in. In this case, we are requesting data for GOOG, BAC, and for AAPL. All three subscribe to market data from the Interactive Brokers Smart router. GOOG and BAC will place orders using the Interactive Brokers Smart router, and AAPL will place orders on the New York Stock Exchange (NYSE).
Click to see the code
print("==============================================================================================================") print("==== Request data.") print("==============================================================================================================") registered_contracts_data ={} registred_contracts_orders ={} defadd_contract(symbol:str, exchange:str="SMART")->None: """ Configure a contract for trading. :param symbol: Symbol to trade. :param exchange: exchange where orders get routed. :return: None """ contract = Contract() contract.symbol = symbol contract.secType ="STK" contract.currency ="USD" contract.exchange ="SMART" rc = client.get_registered_contract(contract) id= rc.contract_details[0].contract.conId registered_contracts_data[id]= rc client.request_tick_data_realtime(rc, dhib.TickDataType.BID_ASK) print(f"Registered contract: id={id} rc={rc}") if exchange !="SMART": contract.exchange ="NYSE" rc = client.get_registered_contract(contract) registred_contracts_orders[id]= rc print(f"Registered contract: id={id} rc={rc}") add_contract("GOOG") add_contract("BAC") add_contract("AAPL", exchange="NYSE")
Now that we have data, it is time to make some predictions. Our model is very simple. We use a 2 minute moving average to compute our predicted price as well as one standard deviation error bars (Bollinger Bands). We will place buy orders at the low price and sell orders at the high price.
Now we come to the cool part -- automatically generating and canceling orders. To do this, we create a Python function, update_orders, that uses the deephaven-ib API to cancel existing orders on a security and then place new orders at new prices. Because native Python functions can be used in Deephaven queries, update can be used to call update_orders every time the prediction for a security updates.
In our case, canceling and replacing orders every time the market ticks is overkill, so we use snapshot to downsample the predictions once a minute.
Click to see the code
print("==============================================================================================================") print("==== Generate orders.") print("==============================================================================================================") open_orders ={} defupdate_orders(contract_id:int, pred_low:float, pred_high:float, buy_order:bool, sell_order:bool)->int: """ Update orders on a contract. First existing orders are canceled. Then new buy/sell limit orders are placed. :param contract_id: Contract id. :param pred_low: Price for buy limit orders. :param pred_high: Price for sell limit orders. :param buy_order: True to post a buy order; False to not post a buy order. :param sell_order: True to post a sell order; False to not post a sell order. :return: Number of orders submitted. """ if contract_id in open_orders: for order in open_orders[contract_id]: # print(f"Canceling order: contract_id={contract_id} order_id={order.request_id}") order.cancel() new_orders =[] rc = registred_contracts_orders[contract_id] if sell_order: order_sell = Order() order_sell.account = account order_sell.action ="SELL" order_sell.orderType ="LIMIT" order_sell.totalQuantity =100 order_sell.lmtPrice =round( pred_high,2) order_sell.transmit =True order = client.order_place(rc, order_sell) new_orders.append(order) if buy_order: order_buy = Order() order_buy.account = account order_buy.action ="BUY" order_buy.orderType ="LIMIT" order_buy.totalQuantity =100 order_buy.lmtPrice =round( pred_low,2) order_buy.transmit =True order = client.order_place(rc, order_buy) new_orders.append(order) open_orders[contract_id]= new_orders returnlen(new_orders) orders = time_table("00:01:00") \ .rename_columns("SnapTime=Timestamp") \ .snapshot(preds.last_by(["Symbol"])) \ .where(f"Timestamp > TimestampFirst + '{ema_t}'") \ .natural_join(positions, on="ContractId", joins="Position") \ .update_view([ "Position = replaceIfNull(Position, 0.0)", "PositionDollars = Position * MidPrice", "MaxPositionDollars = max_position_dollars", "BuyOrder = PositionDollars < MaxPositionDollars", "SellOrder = PositionDollars > -MaxPositionDollars", ]) \ .update("NumNewOrders = (long)update_orders(ContractId, PredLow, PredHigh, BuyOrder, SellOrder)")
What if you want to start market making AMZN? That's easy. You just need to run one line of code.
add_contract("AMZN")
These same concepts can be used to develop algorithmic trading strategies that execute on Alpaca, BiNance, CoinBase, or any other exchange or broker that offers an API.
What algorithmic trading will you do with Deephaven? Tell us on Slack.