{"id":203842,"date":"2024-03-27T11:36:36","date_gmt":"2024-03-27T15:36:36","guid":{"rendered":"https:\/\/ibkrcampus.com\/?p=203842"},"modified":"2025-02-07T16:38:33","modified_gmt":"2025-02-07T21:38:33","slug":"trading-0dte-options-with-the-ibkr-native-api","status":"publish","type":"post","link":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/","title":{"rendered":"Trading 0DTE Options with the IBKR Native API"},"content":{"rendered":"\n<p><em>The article &#8220;Trading 0DTE Options with the IBKR Native API&#8221; first appeared on <a href=\"https:\/\/robotwealth.com\/trading-0dte-options-with-the-ibkr-native-api\/\">Robot Wealth blog<\/a>.<\/em><\/p>\n\n\n\n<p>Here\u2019s a thing that I suspect will make money, but that I haven\u2019t yet tested (for reasons that I will explain shortly):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Every day, at the start of the trading day, get the SPX straddle price and convert it to an expected SPX price move.<\/li>\n\n\n\n<li>Then at the end of the trading day, take the SPX price and calculate if it moved more or less than the straddle implied.<\/li>\n\n\n\n<li>Aggregate this over a few days \u2013 the simplest way would be to take the average expected move and the average actual move.<\/li>\n\n\n\n<li>The trading signal for the next day\u2019s open is as follows:\n<ul class=\"wp-block-list\">\n<li>If SPX moved more than was implied by the straddle on average over the last few days, buy the straddle.<\/li>\n\n\n\n<li>If SPX moved less than implied on average, sell the straddle.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>That is:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">if mean(actual_move) &gt; mean(expected_move):\n  buy tomorrow's 0DTE ATM straddle\nelse if mean(actual_move) &amp;lt; mean(expected_move):\n  sell tomorrow's 0DTE ATM straddle<\/pre>\n\n\n\n<p>It\u2019s essentially fitting to how well the options market predicted spoos volatility in the very short term.<\/p>\n\n\n\n<p>I think there\u2019s&nbsp;<em>probably<\/em>&nbsp;an edge here, but I\u2019m also concerned about costs, since the cost of trading a 0DTE straddle will be a large percentage of its return, most of the time.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-why-haven-t-i-tested-this-properly\">Why haven\u2019t I tested this properly?<\/h2>\n\n\n\n<p>Because the data is hard to come by. I didn\u2019t have it at hand, and I couldn\u2019t get enough from the usual free sources to test it properly.<\/p>\n\n\n\n<p>When I have a suspicion about a possible edge, or someone tells me about an edge they have a hunch about (which is where this idea came from), I like to move fast and test it out with minimal investment in time and money. Most of the time, these things don\u2019t work out, and so I want to disprove ideas quickly and move on. To do that, you need ready access to data.<\/p>\n\n\n\n<p>But the data for this idea is a little awkward. Specifically, you need historical ATM SPXW options daily open and close prices (which I don\u2019t have). And most of the usual sources (including IBKR) don\u2019t provide data for expired contracts.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-what-to-do-instead\">What to do instead?<\/h2>\n\n\n\n<p>You have some options. You could go and buy the data and test it properly. Or, you could just start trading it in small size and collect the data you need along the way.<\/p>\n\n\n\n<p>In this case, I\u2019m thinking about doing the latter. I like this approach because I learn a lot about the strategy by actually executing it. And if it has no edge, then the expected costs are just the trading fees.<\/p>\n\n\n\n<p>Also, I promised I\u2019d show you some 0DTE options stuff with the IB Native API! So here goes.<\/p>\n\n\n\n<p><em>In this article, I\u2019ll show you how to calculate the signal for this strategy and place the appropriate trades via the IB Native API.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-straddle-prices-and-expected-price-moves\">Straddle prices and expected price moves<\/h2>\n\n\n\n<p>The price of the ATM straddle allows you to estimate the expected move in the underlying that the options are pricing in. The generally accepted formula, which is just an estimate, is:<\/p>\n\n\n\n<p>\u0394<em>Pu<\/em> \u200b= 0.85 \u2217 <em>Ps<\/em>\u200b<\/p>\n\n\n\n<p>where&nbsp;<em>Pu<\/em>\u200b&nbsp;is the price of the underlying, and&nbsp;<em>Ps<\/em>\u200b&nbsp;is the price of the ATM straddle.<\/p>\n\n\n\n<p>For example say our underlying was priced at&nbsp;100.<em>The ATM straddle costs<\/em> 15. The expected move is therefore 0.85*15 =<\/p>\n\n\n\n<p>That means that at expiry of the straddle, we expect price to be within 100 +\/- 12.75, that is between&nbsp;12.75. That means that at expiry of the straddle, we expect price to be within 100+\/\u221212.75, that is between 87.25 and $112.75.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Data requirements<\/h2>\n\n\n\n<p>For this strategy, we need the following data:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Daily open and close SPX prices (the open price will be our straddle strike price, and the close will allow us to calculate the actual price move)<\/li>\n\n\n\n<li>Daily 0DTE ATM call and put option open prices<\/li>\n<\/ul>\n\n\n\n<p>Assuming we have the appropriate market data subscriptions, we can get daily SPX prices directly out of TWS.<\/p>\n\n\n\n<p>Options data is more problematic.<\/p>\n\n\n\n<p>Even if you have the appropriate subscriptions, you won\u2019t be able to get expired options contracts out of TWS. And we need a few days\u2019 worth of expired contracts to calculate our trading signal.<\/p>\n\n\n\n<p>So we\u2019ll get that data from Yahoo Finance instead.<\/p>\n\n\n\n<p>You can get XPSW options chains from Yahoo at this url:&nbsp;<a href=\"https:\/\/finance.yahoo.com\/quote\/%5ESPX\/options\/\">https:\/\/finance.yahoo.com\/quote\/%5ESPX\/options\/<\/a><\/p>\n\n\n\n<p>And you can get price data for options that haven\u2019t yet expired by selecting the expiry date from the dropdown:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"963\" height=\"675\" data-src=\"\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/yahoo_spx_option_chains-robot-wealth.png\" alt=\"\" class=\"wp-image-203881 lazyload\" data-srcset=\"https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/yahoo_spx_option_chains-robot-wealth.png 963w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/yahoo_spx_option_chains-robot-wealth-700x491.png 700w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/yahoo_spx_option_chains-robot-wealth-300x210.png 300w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/yahoo_spx_option_chains-robot-wealth-768x538.png 768w\" data-sizes=\"(max-width: 963px) 100vw, 963px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 963px; aspect-ratio: 963\/675;\" \/><\/figure>\n\n\n\n<p>I did some experimenting and found that you could also get price data for&nbsp;<em>recently<\/em>&nbsp;expired options using the following pattern for the URL:<\/p>\n\n\n\n<p>https:\/\/finance.yahoo.com\/quote\/SPXW{expiry}{contract_type}0{strike*1000}<\/p>\n\n\n\n<p>where&nbsp;<code>contract_type<\/code>&nbsp;is \u201cC\u201d or \u201cP\u201d for call and put respectively, and&nbsp;<code>expiry<\/code>&nbsp;is of the format yymmdd.<\/p>\n\n\n\n<p>Here\u2019s an example of what\u2019s available for an option that expired yesterday:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"956\" height=\"470\" data-src=\"\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/recently_expired_option-robot-wealth.png\" alt=\"\" class=\"wp-image-203882 lazyload\" data-srcset=\"https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/recently_expired_option-robot-wealth.png 956w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/recently_expired_option-robot-wealth-700x344.png 700w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/recently_expired_option-robot-wealth-300x147.png 300w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/recently_expired_option-robot-wealth-768x378.png 768w\" data-sizes=\"(max-width: 956px) 100vw, 956px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 956px; aspect-ratio: 956\/470;\" \/><\/figure>\n\n\n\n<p>We have the open price on expiry day in the table, and I&nbsp;<em>think<\/em>&nbsp;the number in large bold is the last traded price on expiry day. I don\u2019t know whether the open price represents the mid price, the bid, the ask, the first trade, or something else.<\/p>\n\n\n\n<p>Unfortunately it seems Yahoo only makes a few days\u2019 worth of contracts available. I could find nothing older than about five days. So this data source won\u2019t be useful for backtesting, but maybe we can use it for calculating our trade signal.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A strategy architecture<\/h2>\n\n\n\n<p>Given our data requirements, we can craft a trading application using the IB Native API that consists of the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Connect to TWS<\/li>\n\n\n\n<li>Request four (say) days of SPX price data from TWS<\/li>\n\n\n\n<li>Using SPX open prices as our strike prices, get SPXW call and put open and last traded prices on expiry day from Yahoo for the prior four days<\/li>\n\n\n\n<li>Calculate the ATM 0DTE straddle price and implied expected move for each of the four days<\/li>\n\n\n\n<li>Calculate the actual move from the open and close prices of SPX for each of the four days<\/li>\n\n\n\n<li>Calculate the mean expected and actual moves over the four days<\/li>\n\n\n\n<li>Calculate the trade signal<\/li>\n\n\n\n<li>Place the appropriate trades in TWS<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Strategy implementation<\/h2>\n\n\n\n<p>Following is some Python code for implementing this strategy.<\/p>\n\n\n\n<p>The main purpose is to demonstrate how to trade options using the IB Native API. If you do trade this strategy, be aware of the following caveats:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>I don\u2019t have confidence in it at the moment \u2013 it\u2019s only based on a hunch<\/li>\n\n\n\n<li>The options data source is dubious (I don\u2019t even have confidence that the data represents what I think it does)<\/li>\n<\/ul>\n\n\n\n<p>With that out of the way, here\u2019s the code. I\u2019ve heavily commented it so that you can follow along if this is new to you.<\/p>\n\n\n\n<p>For an introduction to the IB Native API, read&nbsp;<a href=\"https:\/\/robotwealth.com\/getting-started-with-the-interactive-brokers-native-api\/\">this article<\/a>&nbsp;first.<\/p>\n\n\n\n<p>I ran this shortly after Friday\u2019s open (22 March 2024). You would need to make some modifications to run it in the future (for example update the&nbsp;<code>start_date<\/code>&nbsp;and&nbsp;<code>end_date<\/code>&nbsp;parameters that control the SPX price data download) etc.<\/p>\n\n\n\n<p>Also, I\u2019ve only included the bare minimum you need to get started with a strategy such as this. In particular, I\u2019ve only included the minimum order handling logic required to trade a straddle using limit orders at the current bid\/ask price. I\u2019ve not made any attempt to handle cases where the order isn\u2019t filled. I\u2019ve also not included handling of any edge cases (for example, where an fails to be received by TWS).<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Strategy for trading 0DTE straddles via the IBKR native API\n# Buy\/sell the 0DTE ATM straddle if recent 0DTE straddles under\/over-predicted the day's spoos move\n\nfrom threading import Thread, Event\nimport time\nfrom typing import Any\nfrom ibapi.common import BarData\nfrom ibapi.wrapper import EWrapper\nfrom ibapi.client import EClient\nfrom ibapi.contract import Contract, ContractDetails\nfrom ibapi.order import *\nfrom ibapi.common import *\nfrom ibapi.account_summary_tags import AccountSummaryTags\nimport pandas as pd\nimport requests\nfrom bs4 import BeautifulSoup\n\n\n# make url for 0DTE ATM option contracts from yahoo\n# can only get approx 5 days' worth of expired contracts\ndef make_url(expiry, contract_type, strike):\n    return f\"https:\/\/finance.yahoo.com\/quote\/SPXW{expiry}{contract_type}0{strike*1000}\"\n\n# get 0dte options prices from yahoo\n# use beautiful soup to parse the HTML and extract values from relevant tags\ndef get_0dte_prices(expiry, contract_type, strike):\n    url = make_url(expiry, contract_type, strike)\n\n    # headers to simulate browser request\n    headers = {\n        \"User-Agent\": \"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/88.0.4324.150 Safari\/537.36\"\n    }\n\n    # get web page\n    response = requests.get(url, headers=headers)\n\n    # parse\n    soup = BeautifulSoup(response.text, \"html.parser\")\n\n    # extract last traded price (HTML specification is from inspection of Yahoo options data pages)\n    last_traded_price_tag = soup.find(\n        \"fin-streamer\", {\"data-test\": \"qsp-price\", \"data-field\": \"regularMarketPrice\"}\n    )\n    last_traded_price = (\n        float(last_traded_price_tag[\"value\"]) if last_traded_price_tag else \"Not found\"\n    )\n\n    # extract open price (HTML specification is from inspection of Yahoo options data pages)\n    open_price_tag = soup.find(\"td\", {\"data-test\": \"OPEN-value\"})\n    open_price = float(open_price_tag.text) if open_price_tag else \"Not found\"\n\n    return (open_price, last_traded_price)\n\n\n# class for trading the straddles strategy\nclass ibStraddlesApp(EClient, EWrapper):\n    def __init__(self, ticker):\n        EClient.__init__(self, self)\n        self.ticker = ticker\n        self.next_req_id = 0  # keep track of request ids\n        self.connection_ready = Event()  # to signal the connection has been established\n        self.done = (\n            Event()\n        )  # for signalling between threads when a message has been fully processed\n        self.historical_data = []  # for storing historical data\n        self.price = {}  # for storing current option contract price data\n\n    def increment_req_id(self):\n        self.next_req_id += 1\n\n    # override Ewrapper.error\n    def error(\n        self, reqId: TickerId, errorCode: int, errorString: str, contract: Any = None\n    ):\n        print(\"Error: \", reqId, \" \", errorCode, \" \", errorString)\n        if errorCode == 502:\n            # not connected\n            # set self.done (a threading.Event) to True\n            self.done.set()\n\n    # override Ewrapper.nextValidID - used to signal that the connection between application and TWS is complete, and\n    # returns the next valid orderID (for any future transactions).\n    # if we send messages before the connection has been established, they can be lost\n    # so wait for this method to be called\n    def nextValidId(self, orderId: int):\n        self.nextorderId = orderId\n        print(f\"Connection ready, next valid order ID: {orderId}\")\n        self.connection_ready.set()  # signal that the connection is ready\n\n    # override Ewrapper.contractDetails\n    # gets back contract details\n    def contractDetails(self, reqId: int, contractDetails: ContractDetails):\n        super().contractDetails(reqId, contractDetails)\n        print(contractDetails)\n\n    # override Ewraper.contractDetailsEnd\n    # signals that the contract details request has completed\n    def contractDetailsEnd(self, reqId: int):\n        print(f\"Contract details request {reqId} complete\")\n        self.done.set()\n\n    # override Ewrapper.historicalData\n    # TWS sends data from reqHistoricalData to this callback\n    def historicalData(self, reqId: int, bar: BarData):\n        d = {\n            \"Ticker\": self.ticker,\n            \"Date\": bar.date,\n            \"Open\": bar.open,\n            \"High\": bar.high,\n            \"Low\": bar.close,\n            \"Close\": bar.close,\n        }\n        self.historical_data.append(d)\n\n    # override EWrapper.historicalDataEnd is received\n    # signals that historical market data request is complete\n    # (note only sent if reqHistoricalData invoked with keepUpToDate=False)\n    def historicalDataEnd(self, reqId: int, start: str, end: str):\n        print(f\"Historical data request complete\")\n        self.done.set()\n\n    # callback for handling current price data requests\n    # see \/campus\/ibkr-api-page\/twsapi-doc\/#available-tick-types for available tickTypes\n    def tickPrice(self, reqId, tickType, price, attrib):\n        \"\"\"Key self.price with the reqId that made the request so that you can keep track of which item belongs to which contract.\n        See usage below for example.\n        \"\"\"\n        if not reqId in self.price.keys():\n            self.price[reqId] = {}\n\n        # handle bid price (tickType = 1)\n        if tickType == 1:\n            print(\"The current bid price is: \", price)\n            self.price[reqId][\"bid\"] = price\n\n        # handle ask price (tickType = 2)\n        if tickType == 2:\n            print(\"The current ask price is: \", price)\n            self.price[reqId][\"ask\"] = price\n\n    # override Ewrapper.tickSnapshotEnd\n    # signals snapshot request is complete\n    def tickSnapshotEnd(self, reqId: int):\n        print(f\"Current price data request complete\")\n        self.done.set()\n\n    # override Ewrapper order callbacks - just print execution and order status to screen\n    # in practice, you would monitor these and handle appropriately (eg if order wasn't filled)\n    def orderStatus(\n        self,\n        orderId,\n        status,\n        filled,\n        remaining,\n        avgFullPrice,\n        permId,\n        parentId,\n        lastFillPrice,\n        clientId,\n        whyHeld,\n        mktCapPrice,\n    ):\n        print(\n            \"orderStatus - orderid:\",\n            orderId,\n            \"status:\",\n            status,\n            \"filled\",\n            filled,\n            \"remaining\",\n            remaining,\n            \"lastFillPrice\",\n            lastFillPrice,\n        )\n\n    def openOrder(self, orderId, contract, order, orderState):\n        print(\n            \"openOrder id:\",\n            orderId,\n            contract.symbol,\n            contract.secType,\n            \"@\",\n            contract.exchange,\n            \":\",\n            order.action,\n            order.orderType,\n            order.totalQuantity,\n            orderState.status,\n        )\n\n    def execDetails(self, reqId, contract, execution):\n        print(\n            \"Order Executed: \",\n            reqId,\n            contract.symbol,\n            contract.secType,\n            contract.currency,\n            execution.execId,\n            execution.orderId,\n            execution.shares,\n            execution.lastLiquidity,\n        )\n\n\n# define our event loop - this will run in its own thread\ndef run_loop(app):\n    app.run()\n\n\n##### Instantiate a trading app and wait for a successful connection\n\n# instantiate an ibStraddlesApp\n# ticker of the underlying\napp = ibStraddlesApp(ticker=\"SPX\")\n\n# connect\n# clientID identifies our application\napp.connect(\"127.0.0.1\", 7496, clientId=0)\n\n# start the application's event loop in a thread\napi_thread = Thread(target=run_loop, args=(app,), daemon=True)\napi_thread.start()\n\n# wait until the Ewrapper.nextValidId callback is triggered, indicating a successful connection\napp.connection_ready.wait()\n\n##### Get SPX data required for trading signal\n\n# required date range - will need to update this\nstart_date = \"20240318\"\nend_date = \"20240322\"\ndate_range = pd.date_range(start=start_date, end=end_date)\nnum_days = len(date_range)\n\n# get recent SPX data\nspx = Contract()\nspx.symbol = \"SPX\"\nspx.secType = \"IND\"\nspx.currency = \"USD\"\nspx.exchange = \"CBOE\"\n\n# request historical SPX data and increment request id\napp.reqHistoricalData(\n    reqId=app.next_req_id,\n    contract=spx,\n    # 8:30 chicago is 9:30 NY\n    endDateTime=f\"{end_date} 16:00:00 US\/Central\",\n    durationStr=f\"{num_days} D\",\n    whatToShow=\"TRADES\",\n    barSizeSetting=\"1 day\",\n    useRTH=1,\n    formatDate=1,\n    keepUpToDate=False,\n    chartOptions=[],\n)\napp.increment_req_id()\n\n# wait for historical data to come back before continuing\napp.done.wait()\n\n# reset event\napp.done.clear()\n\n# make dataframe from receieved SPX data\nspx_prices = pd.DataFrame(app.historical_data)\n\n# save to disk\n# spx_prices.to_csv(\".\/ibkr-api\/spx_prices.csv\")\n\nprint(\"spx price data:\")\nprint(spx_prices)\n\n# check you have the expected data:\nif len(spx_prices[\"Date\"]) &lt; 5:\n    raise Exception(\"Missing SPX data, stopping\")\n\n##### Get options data and calculate trading signal\n\n# get historical ATM 0DTE XPSW options prices from Yahoo\nexpected_moves = []\nactual_moves = []\nfor d in spx_prices[\"Date\"][:-1]:  # don't get today's data yet\n    # get ATM strike from each day's SPX open price\n    spx_open = spx_prices.loc[spx_prices[\"Date\"] == d, \"Open\"].iloc[0]\n\n    # round to nearest $5\n    strike = round(spx_open \/ 5) * 5\n\n    # get epxiry from date string\n    expiry = str(d)[2:]\n\n    # get put open and last traded prices\n    p_open, p_close = get_0dte_prices(expiry=expiry, contract_type=\"P\", strike=strike)\n\n    # if we didn't find an ATM strike:\n    # a bit of hack to get the nearest existing strike\n    # in reality you'd be more careful\n    while p_open == \"Not found\":\n        strike -= 5\n        p_open, p_close = get_0dte_prices(\n            expiry=expiry, contract_type=\"P\", strike=strike\n        )\n\n    # get call open and last traded prices\n    c_open, c_close = get_0dte_prices(expiry=expiry, contract_type=\"C\", strike=strike)\n\n    # calculate straddle open and last traded prices\n    straddle_open_price = p_open + c_open\n\n    # calculate straddle-implied expected move and store\n    expected_move = 0.85 * straddle_open_price\n    expected_moves.append(expected_move)\n\n    # calculate actual move from SPX prices and store\n    spx_close = spx_prices.loc[spx_prices[\"Date\"] == d, \"Close\"].iloc[0]\n    actual_move = abs(spx_close - spx_open)\n    actual_moves.append(actual_move)\n\n    print(\"Expected move, actual move:\")\n    print(expected_move, actual_move)\n\n# calculate recent average expected and actual moves\nave_expected_move = sum(expected_moves) \/ len(expected_moves)\nave_actual_move = sum(actual_moves) \/ len(actual_moves)\nprint(\"Average expected move, average actual move\")\nprint(ave_expected_move, ave_actual_move)\n\n##### Prepare contract objects and get current prices for trading\n\n# get today's ATM strike and expiry\ntoday_open = spx_prices[\"Open\"].iloc[-1]\nstrike = round(today_open \/ 5) * 5\nexpiry = spx_prices[\"Date\"].iloc[-1]\nprint(f\"Today's strike:{strike}, today's expiry: {expiry}\")\n\n# create an options contract representing today's 0DTE ATM call\ncall = Contract()\ncall.symbol = \"SPXW\"\ncall.secType = \"OPT\"\ncall.currency = \"USD\"\ncall.exchange = \"SMART\"\ncall.lastTradeDateOrContractMonth = expiry\ncall.strike = strike\ncall.right = \"C\"\ncall.tradingClass = \"SPXW\"\n\n# keep track of the reqId for the call\ncall_req_id = app.next_req_id\n\n# get the call's current bid-ask prices\nprint(\"Current call prices:\")\napp.reqMktData(\n    reqId=call_req_id,\n    contract=call,\n    genericTickList=\"\",  # get all available data\n    snapshot=True,  # requires appropriate market data subscription\n    regulatorySnapshot=False,\n    mktDataOptions=[],\n)\napp.increment_req_id()\napp.done.wait()\napp.done.clear()\n\n# call prices:\n# note app.price is keyed by reqId\nprint(app.price[call_req_id])\n\n# create an options contract representing today's 0DTE ATM put\nput = Contract()\nput.symbol = \"SPXW\"\nput.secType = \"OPT\"\nput.currency = \"USD\"\nput.exchange = \"SMART\"\nput.lastTradeDateOrContractMonth = expiry\nput.strike = strike\nput.right = \"P\"\nput.tradingClass = \"SPXW\"\n\n# keep track of the reqId for the put\nput_req_id = app.next_req_id\n\n# get the put's current bid-ask prices\nprint(\"Current put prices:\")\napp.reqMktData(\n    reqId=put_req_id,\n    contract=put,\n    genericTickList=\"\",  # get all available data types\n    snapshot=True,  # requires appropriate market data subscription\n    regulatorySnapshot=False,\n    mktDataOptions=[],\n)\napp.increment_req_id()\napp.done.wait()\napp.done.clear()\n\n# put prices:\n# note app.price is keyed by reqId\nprint(app.price[put_req_id])\n\n##### Trade logic\n\n# Now we have call and put prices for today, we can shoot off limit orders at these prices\n# I prefer this to shooting off a market order into a potentially illiquid product\n# You can even add a buffer to your limit order beyond the current top of book price to give you more chance of getting filled\n# Many ways to do this - up to you.\n# But in practice, you'll need to manage your orders and fills - you might end up chasing the market\n\n# sell today's 0DTE ATM straddle if SPX has moved less than implied by recent straddle prices\nif ave_actual_move &lt; ave_expected_move:\n    # sell today's 0DTE stradle\n    # sell call:\n    print(\"Selling today's 0DTE ATM straddle\")\n    order = Order()\n    order.action = \"SELL\"\n    order.totalQuantity = 1  # note will be multiplied by contract multiplier\n    order.orderType = \"LMT\"\n    order.lmtPrice = app.price[call_req_id][\"bid\"]  # limit sell the call at the bid\n    order.transmit = True\n    app.placeOrder(app.nextorderId, call, order)\n    app.nextorderId += 1\n\n    # sell put:\n    order = Order()\n    order.action = \"SELL\"\n    order.totalQuantity = 1  # note will be multiplied by contract multiplier\n    order.orderType = \"LMT\"\n    order.lmtPrice = app.price[put_req_id][\"bid\"]  # limit sell the put at the bid\n    order.transmit = True\n    app.placeOrder(app.nextorderId, put, order)\n    app.nextorderId += 1\n# buy today's 0DTE ATM straddle if SPX has moved more than implied by recent straddle prices\nelse:\n    # buy today's 0DTE stradle\n    # buy call:\n    print(\"Buying today's 0DTE ATM straddle\")\n    order = Order()\n    order.action = \"BUY\"\n    order.totalQuantity = 1  # note will be multiplied by contract multiplier\n    order.orderType = \"LMT\"\n    order.lmtPrice = app.price[call_req_id][\"ask\"]  # limit buy the call at the ask\n    order.transmit = True\n    app.placeOrder(app.nextorderId, call, order)\n    app.nextorderId += 1\n\n    # buy put:\n    order = Order()\n    order.action = \"BUY\"\n    order.totalQuantity = 1  # note will be multiplied by contract multiplier\n    order.orderType = \"LMT\"\n    order.lmtPrice = app.price[put_req_id][\"ask\"]  # limit buy the put at the ask\n    order.transmit = True\n    app.placeOrder(app.nextorderId, put, order)\n    app.nextorderId += 1\n\n# You'll want to handle the order as well - maybe cancel it if the market runs away for instance.\n# When placing orders via the API and building a robust trading system, it is important to monitor for callback notifications,\n# specifically for IBApi::EWrapper::error, IBApi::EWrapper::orderStatus changes, IBApi::EWrapper::openOrder warnings, and\n# IBApi::EWrapper::execDetails to ensure proper operation.\n# Here we just use these methods to print execution details to screen.\n\n# disconnect once orders handled satisfactorily\n# commented here for simplicity since we didn't do any order handling\n# app.disconnect()<\/pre>\n\n\n\n<p>Here\u2019s the output from running this code shortly after Friday\u2019s open:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Connection ready, next valid order ID: 16\nError:  -1   2104   Market data farm connection is OK:usfarm.nj\nError:  -1   2104   Market data farm connection is OK:usfuture\nError:  -1   2104   Market data farm connection is OK:usopt\nError:  -1   2104   Market data farm connection is OK:usfarm\nError:  -1   2106   HMDS data farm connection is OK:euhmds\nError:  -1   2106   HMDS data farm connection is OK:cashhmds\nError:  -1   2106   HMDS data farm connection is OK:fundfarm\nError:  -1   2106   HMDS data farm connection is OK:ushmds\nError:  -1   2158   Sec-def data farm connection is OK:secdefnj\nHistorical data request complete\nspx price data:\n  Ticker      Date     Open     High      Low    Close\n0    SPX  20240318  5154.77  5175.60  5149.42  5149.42\n1    SPX  20240319  5139.09  5180.31  5178.51  5178.51\n2    SPX  20240320  5181.69  5226.19  5224.62  5224.62\n3    SPX  20240321  5253.43  5261.10  5241.53  5241.53\n4    SPX  20240322  5242.48  5244.21  5241.18  5244.18\nExpected move, actual move:\n32.852500000000006 5.350000000000364\nExpected move, actual move:\n22.8905 39.42000000000007\nExpected move, actual move:\n31.517999999999997 42.93000000000029\nExpected move, actual move:\n21.504999999999995 11.900000000000546\nAverage expected move, average actual move\n27.1915 24.90000000000032\nToday's strike:5240, today's expiry: 20240322\nCurrent call prices:\nThe current bid price is:  16.43\nThe current ask price is:  16.45\nCurrent price data request complete\n{'bid': 16.43, 'ask': 16.45}\nCurrent put prices:\nThe current bid price is:  12.44\nThe current ask price is:  12.49\nCurrent price data request complete\n{'bid': 12.44, 'ask': 12.49}\nSelling today's 0DTE ATM straddle\nopenOrder id: 17 SPX OPT @ SMART : SELL LMT 1 PreSubmitted\norderStatus - orderid: 17 status: PreSubmitted filled 0 remaining 1 lastFillPrice 0.0\nOrder Executed:  -1 SPX OPT USD 00020057.65fd0c22.01.01 12 1 2\nopenOrder id: 17 SPX OPT @ SMART : SELL LMT 1 Filled\norderStatus - orderid: 17 status: Filled filled 1 remaining 0 lastFillPrice 16.43\nopenOrder id: 17 SPX OPT @ SMART : SELL LMT 1 Filled\norderStatus - orderid: 17 status: Filled filled 1 remaining 0 lastFillPrice 16.43\nopenOrder id: 18 SPX OPT @ SMART : SELL LMT 1 Submitted\norderStatus - orderid: 18 status: Submitted filled 0 remaining 1 lastFillPrice 0.0\nOrder Executed:  -1 SPX OPT USD 00020057.65fd0c2b.01.01 13 1 1\nopenOrder id: 18 SPX OPT @ SMART : SELL LMT 1 Filled\norderStatus - orderid: 18 status: Filled filled 1 remaining 0 lastFillPrice 12.44\nopenOrder id: 18 SPX OPT @ SMART : SELL LMT 1 Filled\norderStatus - orderid: 18 status: Filled filled 1 remaining 0 lastFillPrice 12.44<\/pre>\n\n\n\n<p>You can see that the strategy successfully connected to TWS, and received the SPX data for today and the previous 4 sessions. Note that today\u2019s data is incomplete \u2013 the OHLC data only represents a short period after 8:30am Chicago time. But we only need today\u2019s open price (for figuring out today\u2019s ATM strike).<\/p>\n\n\n\n<p>It then calculated the last four days\u2019 straddle-implied expected moves and the actual SPX moves, and then took the averages to get the trade signal.<\/p>\n\n\n\n<p>Next, it got today\u2019s strike from today\u2019s SPX open price.<\/p>\n\n\n\n<p>It then asked TWS for a current snapshot of top of book prices for the 0DTE ATM call and put, and used these prices to submit limit orders.<\/p>\n\n\n\n<p>In this case, shortly after the orders were sent, they were filled. In practice, you would need to handle this more carefully, for example dealing with cases where the market ran away from you and your limit order was unfilled.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>In this article, we saw a minimal implementation of a strategy that uses the recent SPX actual moves and straddle-implied moves to directionally trade 0DTE straddles.<\/p>\n\n\n\n<p>The main hurdle was obtaining data for expired SPXW options, but luckily the very recent contracts are available on Yahoo Finance.<\/p>\n\n\n\n<p>It would be nice to simulate this strategy, but it would require historical SPXW option opening and closing prices. Until then, I am considering trading this at very small size (using the minis) just to gain some insight into how it trades.<\/p>\n\n\n\n<p>Please note that this is only a minimal example. In particular, I\u2019ve not included any order handling logic, other than to submit limit orders and print their status to screen.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Following is some Python code for implementing this strategy. The main purpose is to demonstrate how to trade options using the IB Native API.<\/p>\n","protected":false},"author":271,"featured_media":203900,"comment_status":"open","ping_status":"closed","sticky":true,"template":"","format":"standard","meta":{"_acf_changed":true,"footnotes":""},"categories":[339,343,349,338,341,9563],"tags":[851,14986,1014,1015,575,1224,595],"contributors-categories":[13676],"class_list":{"0":"post-203842","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-data-science","8":"category-programing-languages","9":"category-python-development","10":"category-ibkr-quant-news","11":"category-quant-development","12":"category-options-quant","13":"tag-algo-trading","14":"tag-beautifulsoup","15":"tag-eclient","16":"tag-ewrapper","17":"tag-ibkr-api","18":"tag-pandas","19":"tag-python","20":"contributors-categories-robot-wealth"},"pp_statuses_selecting_workflow":false,"pp_workflow_action":"current","pp_status_selection":"publish","acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Trading 0DTE Options with the IBKR Native API | IBKR Quant<\/title>\n<meta name=\"description\" content=\"Following is some Python code for implementing this strategy. The main purpose is to demonstrate how to trade options using the IB Native API.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.interactivebrokers.com\/campus\/wp-json\/wp\/v2\/posts\/203842\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Trading 0DTE Options with the IBKR Native API\" \/>\n<meta property=\"og:description\" content=\"Following is some Python code for implementing this strategy. The main purpose is to demonstrate how to trade options using the IB Native API.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/\" \/>\n<meta property=\"og:site_name\" content=\"IBKR Campus US\" \/>\n<meta property=\"article:published_time\" content=\"2024-03-27T15:36:36+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-02-07T21:38:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/blue-digital-charts-trading-screen.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"563\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Kris Longmore\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kris Longmore\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\n\t    \"@context\": \"https:\\\/\\\/schema.org\",\n\t    \"@graph\": [\n\t        {\n\t            \"@type\": \"NewsArticle\",\n\t            \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/trading-0dte-options-with-the-ibkr-native-api\\\/#article\",\n\t            \"isPartOf\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/trading-0dte-options-with-the-ibkr-native-api\\\/\"\n\t            },\n\t            \"author\": {\n\t                \"name\": \"Kris Longmore\",\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/person\\\/79c2a2775a70a4da1accf0068d731933\"\n\t            },\n\t            \"headline\": \"Trading 0DTE Options with the IBKR Native API\",\n\t            \"datePublished\": \"2024-03-27T15:36:36+00:00\",\n\t            \"dateModified\": \"2025-02-07T21:38:33+00:00\",\n\t            \"mainEntityOfPage\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/trading-0dte-options-with-the-ibkr-native-api\\\/\"\n\t            },\n\t            \"wordCount\": 1576,\n\t            \"commentCount\": 3,\n\t            \"publisher\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/trading-0dte-options-with-the-ibkr-native-api\\\/#primaryimage\"\n\t            },\n\t            \"thumbnailUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/03\\\/blue-digital-charts-trading-screen.jpg\",\n\t            \"keywords\": [\n\t                \"Algo Trading\",\n\t                \"BeautifulSoup\",\n\t                \"EClient\",\n\t                \"EWrapper\",\n\t                \"IBKR API\",\n\t                \"Pandas\",\n\t                \"Python\"\n\t            ],\n\t            \"articleSection\": [\n\t                \"Data Science\",\n\t                \"Programming Languages\",\n\t                \"Python Development\",\n\t                \"Quant\",\n\t                \"Quant Development\",\n\t                \"Quant Options\"\n\t            ],\n\t            \"inLanguage\": \"en-US\",\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"CommentAction\",\n\t                    \"name\": \"Comment\",\n\t                    \"target\": [\n\t                        \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/trading-0dte-options-with-the-ibkr-native-api\\\/#respond\"\n\t                    ]\n\t                }\n\t            ]\n\t        },\n\t        {\n\t            \"@type\": \"WebPage\",\n\t            \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/trading-0dte-options-with-the-ibkr-native-api\\\/\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/trading-0dte-options-with-the-ibkr-native-api\\\/\",\n\t            \"name\": \"Trading 0DTE Options with the IBKR Native API | IBKR Campus US\",\n\t            \"isPartOf\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#website\"\n\t            },\n\t            \"primaryImageOfPage\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/trading-0dte-options-with-the-ibkr-native-api\\\/#primaryimage\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/trading-0dte-options-with-the-ibkr-native-api\\\/#primaryimage\"\n\t            },\n\t            \"thumbnailUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/03\\\/blue-digital-charts-trading-screen.jpg\",\n\t            \"datePublished\": \"2024-03-27T15:36:36+00:00\",\n\t            \"dateModified\": \"2025-02-07T21:38:33+00:00\",\n\t            \"description\": \"Following is some Python code for implementing this strategy. The main purpose is to demonstrate how to trade options using the IB Native API.\",\n\t            \"inLanguage\": \"en-US\",\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"ReadAction\",\n\t                    \"target\": [\n\t                        \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/trading-0dte-options-with-the-ibkr-native-api\\\/\"\n\t                    ]\n\t                }\n\t            ]\n\t        },\n\t        {\n\t            \"@type\": \"ImageObject\",\n\t            \"inLanguage\": \"en-US\",\n\t            \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/trading-0dte-options-with-the-ibkr-native-api\\\/#primaryimage\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/03\\\/blue-digital-charts-trading-screen.jpg\",\n\t            \"contentUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/03\\\/blue-digital-charts-trading-screen.jpg\",\n\t            \"width\": 1000,\n\t            \"height\": 563,\n\t            \"caption\": \"Quant\"\n\t        },\n\t        {\n\t            \"@type\": \"WebSite\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#website\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/\",\n\t            \"name\": \"IBKR Campus US\",\n\t            \"description\": \"Financial Education from Interactive Brokers\",\n\t            \"publisher\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\"\n\t            },\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"SearchAction\",\n\t                    \"target\": {\n\t                        \"@type\": \"EntryPoint\",\n\t                        \"urlTemplate\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/?s={search_term_string}\"\n\t                    },\n\t                    \"query-input\": {\n\t                        \"@type\": \"PropertyValueSpecification\",\n\t                        \"valueRequired\": true,\n\t                        \"valueName\": \"search_term_string\"\n\t                    }\n\t                }\n\t            ],\n\t            \"inLanguage\": \"en-US\"\n\t        },\n\t        {\n\t            \"@type\": \"Organization\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\",\n\t            \"name\": \"Interactive Brokers\",\n\t            \"alternateName\": \"IBKR\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/\",\n\t            \"logo\": {\n\t                \"@type\": \"ImageObject\",\n\t                \"inLanguage\": \"en-US\",\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/logo\\\/image\\\/\",\n\t                \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/05\\\/ibkr-campus-logo.jpg\",\n\t                \"contentUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/05\\\/ibkr-campus-logo.jpg\",\n\t                \"width\": 669,\n\t                \"height\": 669,\n\t                \"caption\": \"Interactive Brokers\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/logo\\\/image\\\/\"\n\t            },\n\t            \"publishingPrinciples\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/about-ibkr-campus\\\/\",\n\t            \"ethicsPolicy\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/cyber-security-notice\\\/\"\n\t        },\n\t        {\n\t            \"@type\": \"Person\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/person\\\/79c2a2775a70a4da1accf0068d731933\",\n\t            \"name\": \"Kris Longmore\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/author\\\/krislongmore\\\/\"\n\t        }\n\t    ]\n\t}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Trading 0DTE Options with the IBKR Native API | IBKR Quant","description":"Following is some Python code for implementing this strategy. The main purpose is to demonstrate how to trade options using the IB Native API.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.interactivebrokers.com\/campus\/wp-json\/wp\/v2\/posts\/203842\/","og_locale":"en_US","og_type":"article","og_title":"Trading 0DTE Options with the IBKR Native API","og_description":"Following is some Python code for implementing this strategy. The main purpose is to demonstrate how to trade options using the IB Native API.","og_url":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/","og_site_name":"IBKR Campus US","article_published_time":"2024-03-27T15:36:36+00:00","article_modified_time":"2025-02-07T21:38:33+00:00","og_image":[{"width":1000,"height":563,"url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/blue-digital-charts-trading-screen.jpg","type":"image\/jpeg"}],"author":"Kris Longmore","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Kris Longmore","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/#article","isPartOf":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/"},"author":{"name":"Kris Longmore","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/person\/79c2a2775a70a4da1accf0068d731933"},"headline":"Trading 0DTE Options with the IBKR Native API","datePublished":"2024-03-27T15:36:36+00:00","dateModified":"2025-02-07T21:38:33+00:00","mainEntityOfPage":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/"},"wordCount":1576,"commentCount":3,"publisher":{"@id":"https:\/\/ibkrcampus.com\/campus\/#organization"},"image":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/#primaryimage"},"thumbnailUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/blue-digital-charts-trading-screen.jpg","keywords":["Algo Trading","BeautifulSoup","EClient","EWrapper","IBKR API","Pandas","Python"],"articleSection":["Data Science","Programming Languages","Python Development","Quant","Quant Development","Quant Options"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/","url":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/","name":"Trading 0DTE Options with the IBKR Native API | IBKR Campus US","isPartOf":{"@id":"https:\/\/ibkrcampus.com\/campus\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/#primaryimage"},"image":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/#primaryimage"},"thumbnailUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/blue-digital-charts-trading-screen.jpg","datePublished":"2024-03-27T15:36:36+00:00","dateModified":"2025-02-07T21:38:33+00:00","description":"Following is some Python code for implementing this strategy. The main purpose is to demonstrate how to trade options using the IB Native API.","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/trading-0dte-options-with-the-ibkr-native-api\/#primaryimage","url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/blue-digital-charts-trading-screen.jpg","contentUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/blue-digital-charts-trading-screen.jpg","width":1000,"height":563,"caption":"Quant"},{"@type":"WebSite","@id":"https:\/\/ibkrcampus.com\/campus\/#website","url":"https:\/\/ibkrcampus.com\/campus\/","name":"IBKR Campus US","description":"Financial Education from Interactive Brokers","publisher":{"@id":"https:\/\/ibkrcampus.com\/campus\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ibkrcampus.com\/campus\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ibkrcampus.com\/campus\/#organization","name":"Interactive Brokers","alternateName":"IBKR","url":"https:\/\/ibkrcampus.com\/campus\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/logo\/image\/","url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/05\/ibkr-campus-logo.jpg","contentUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/05\/ibkr-campus-logo.jpg","width":669,"height":669,"caption":"Interactive Brokers"},"image":{"@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/logo\/image\/"},"publishingPrinciples":"https:\/\/www.interactivebrokers.com\/campus\/about-ibkr-campus\/","ethicsPolicy":"https:\/\/www.interactivebrokers.com\/campus\/cyber-security-notice\/"},{"@type":"Person","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/person\/79c2a2775a70a4da1accf0068d731933","name":"Kris Longmore","url":"https:\/\/www.interactivebrokers.com\/campus\/author\/krislongmore\/"}]}},"jetpack_featured_media_url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/03\/blue-digital-charts-trading-screen.jpg","_links":{"self":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts\/203842","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/users\/271"}],"replies":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/comments?post=203842"}],"version-history":[{"count":0,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts\/203842\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/media\/203900"}],"wp:attachment":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/media?parent=203842"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/categories?post=203842"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/tags?post=203842"},{"taxonomy":"contributors-categories","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/contributors-categories?post=203842"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}