New
The Intraday Backtester and Otto, your AI agent are now live for every Trading Tools subscriber

Intraday Backtester API

View as Markdown

Run custom intraday option backtests with one-minute precision. Define a strategy with entry and exit times, delta or strike-width leg targets, stops, and profit targets, then backtest it against intraday options data going back to October 2020. The API powers the Intraday Custom Backtester in the ORATS dashboard.

This is an asynchronous job API: submit a backtest, poll its status until it completes (a two week single-symbol run typically finishes in under a minute), then fetch the results. Authentication uses the token query parameter on every request.

Available strategies: PUT_CREDIT_SPREAD, CALL_DEBIT_SPREAD, LONG_CALL, SHORT_PUT, CALL_CREDIT_SPREAD, PUT_DEBIT_SPREAD, SHORT_CALL, LONG_PUT, IRON_CONDOR, IRON_BUTTERFLY, LONG_STRADDLE, SHORT_STRADDLE, SHORT_STRANGLE, LONG_CALL_CALENDAR, LONG_PUT_CALENDAR, and DOUBLE_CALENDAR.

Product overview and pricing for this and the other Tools APIs live on the Tools APIs page.

Base URL:https://api.orats.io/backtests/intraday

Submit a Backtest

POSThttps://api.orats.io/backtests/intraday

Submits a backtest job. A successful submission returns a backtestId to use with the other endpoints.

Validation happens asynchronously: a response containing a backtestId means the job was accepted, not that the inputs are valid. A rejected submission returns a message field instead of a backtestId. Jobs with invalid inputs can remain queued rather than reaching an error status, so give up on jobs that stay queued well past their expected runtime.

Required attributes

  • Name
    email
    Type
    string
    Description

    Your email address, used to list your backtests on the status endpoint.

  • Name
    inputs
    Type
    object
    Description

    The backtest definition. Its fields are documented below.

  • Name
    inputs.symbol
    Type
    string
    Description

    The underlying to backtest. Ex: SPY

  • Name
    inputs.startDate
    Type
    string
    Description

    The first trade date, formatted by YYYY-MM-DD. Must be 2020-10-01 or later. Ex: 2026-06-01

  • Name
    inputs.entryTime
    Type
    string
    Description

    Entry time of day, formatted by HHMM (in EST) within market hours 0930 to 1600. Ex: 0934

  • Name
    inputs.strategy
    Type
    string
    Description

    The strategy, from the list above. Ex: PUT_CREDIT_SPREAD

  • Name
    inputs.legs
    Type
    array
    Description

    One object per leg. The first leg sets its own strike and expiration: optionType (put or call), ratio (negative for short legs), a delta band (deltaTarget, deltaMin, deltaMax, always positive), and a DTE band (dteTarget, dteMin, dteMax) where DTE 1 is same-day (0DTE), 2 is the next trading day, and the maximum target is 30.

    Later legs may instead be defined relative to an earlier leg with legRelation: strikeWidth (refLeg, target in strike points, optional min and max; positive widths are further out of the money) and dteDiff (refLeg, target in days, 0 for the same expiration).

Optional attributes

  • Name
    inputs.endDate
    Type
    string
    Description

    The last trade date, formatted by YYYY-MM-DD. Omit for the most recent data.

  • Name
    inputs.exitTime
    Type
    string
    Description

    Exit time of day, formatted by HHMM (in EST). Null holds to expiration.

  • Name
    inputs.expiryTod
    Type
    string
    Description

    Filters AM or PM settled expirations: both, am, or pm. Defaults to both.

  • Name
    inputs.stopLossPct
    Type
    number
    Description

    Stop loss as a percent of entry cost. Send null explicitly to disable; when the field is omitted the engine applies a 200 percent stop.

  • Name
    inputs.profitTargetPct
    Type
    number
    Description

    Profit target as a percent of entry cost. Null for no target.

  • Name
    inputs.tradePct
    Type
    number
    Description

    Slippage as a fraction of the bid-ask spread paid on each side, 0 to 1. Ex: 0.66

  • Name
    inputs.commissionPerContract
    Type
    number
    Description

    Commission in dollars per contract per leg, applied on entry and exit. Ex: 0.65

  • Name
    inputs.maxHoldDays
    Type
    number
    Description

    Maximum trading days to hold before a forced exit. Null for none.

  • Name
    inputs.badPriceFilter
    Type
    object
    Description

    Skips entries with wide markets: maxWidthPctOfStrike and maxWidthPctOfMid as fractions. Defaults to 0.05 and 0.15.

  • Name
    inputs.signals
    Type
    array
    Description

    Signal-driven entries and exits: one object per trade with entry and exit timestamps formatted by YYYYMMDDHHMM. Null to trade on entryTime every day.

POST/backtests/intraday
{
  "email": "you@example.com",
  "inputs": {
    "symbol": "SPY",
    "startDate": "2026-06-01",
    "endDate": "2026-06-12",
    "entryTime": "0934",
    "exitTime": null,
    "strategy": "PUT_CREDIT_SPREAD",
    "legs": [
      {
        "optionType": "put",
        "ratio": -1,
        "deltaTarget": 0.3,
        "deltaMin": 0.2,
        "deltaMax": 0.5,
        "dteTarget": 1,
        "dteMin": 1,
        "dteMax": 1
      },
      {
        "optionType": "put",
        "ratio": 1,
        "legRelation": {
          "strikeWidth": {
            "refLeg": 1,
            "target": 3
          },
          "dteDiff": {
            "refLeg": 1,
            "target": 0
          }
        }
      }
    ],
    "expiryTod": "both",
    "stopLossPct": null,
    "profitTargetPct": null,
    "tradePct": 0.66,
    "commissionPerContract": 0.65,
    "maxHoldDays": null,
    "badPriceFilter": {
      "maxWidthPctOfStrike": 0.05,
      "maxWidthPctOfMid": 0.15
    },
    "signals": null
  }
}

Response

{
  "backtestId": "aapg5gmoqs1r"
}

Backtest Status

GEThttps://api.orats.io/backtests/intraday/status

Retrieves the status of a backtest by id, or every backtest for an email address.

By id the response is a single object; by email it is an array of the same objects. Status values are queued, running, completed, and error. While queued the object holds the submission fields; on completion it adds progress, annReturn, annSharpe, maxDrawDown, and a condensed legs summary. Poll every 10 seconds or so until status is completed.

An unknown id returns a message of Status not found with a 200 status.

Optional attributes

  • Name
    id
    Type
    string
    Description

    The backtestId to look up. Returns a single object. Ex: aapg5gmoqs1r

  • Name
    email
    Type
    string
    Description

    Returns every backtest submitted with this email as an array.

GET/backtests/intraday/status
curl -L "https://api.orats.io/backtests/intraday/status?token=my-token&id=aapg5gmoqs1r"

Response

{
  "email": "you@example.com",
  "execution_time": 5.86,
  "id": "aapg5gmoqs1r",
  "progress": 100,
  "status": "completed",
  "strategy": "PUT_CREDIT_SPREAD",
  "submitted_at": "2026-07-16T08:04Z",
  "symbol": "SPY",
  "updated_at": "2026-07-16T08:05:34.794Z",
  "annReturn": -31.23,
  "annSharpe": -8.23,
  "maxDrawDown": 1.42,
  "legs": [
    {
      "dteTarget": 1,
      "deltaTarget": 0.3
    },
    {
      "legRelation": {
        "strikeWidth": {
          "refLeg": 1,
          "target": 3
        },
        "dteDiff": {
          "refLeg": 1,
          "target": 0
        }
      }
    }
  ]
}

Backtest Results

GEThttps://api.orats.io/backtests/intraday

Retrieves the results of a completed backtest: summary statistics, monthly returns by year, daily returns, and the per-leg trade log.

The trades array has one row per leg; each row carries that leg's profit (sum a trade's legs for the whole-trade profit), and margin is written on leg 1 only. The exitQuoteTime field is populated for non-expiration exits. Symbol and strategy are not repeated here; read them from the status or inputs endpoints.

Required attributes

  • Name
    id
    Type
    string
    Description

    The backtestId to retrieve. Ex: aapg5gmoqs1r

GET/backtests/intraday
curl -L "https://api.orats.io/backtests/intraday?token=my-token&id=aapg5gmoqs1r"

Response

{
  "summary": {
    "AnnReturn": -31.23,
    "AnnMarginReturn": -9935.18,
    "AnnReturn1Yr": -25.87,
    "AnnReturn5Yrs": -25.87,
    "AnnSharpe": -8.23,
    "AnnSortino": -5.43,
    "AnnVolatility": 3.14,
    "MaxDrawDown": 1.42,
    "DrawDownDays": 8,
    "BestMonthRtn": -1.03,
    "WorstMonthRtn": -1.03,
    "BestYearRtn": -1.03,
    "WorstYearRtn": -1.03,
    "BestTradePL": 90.06,
    "WorstTradePL": -240.62,
    "BestTradePct": 98.58,
    "WorstTradePct": -447.16,
    "PLPerTradeAvg": -76.68,
    "PLPerDayAvg": -63.9,
    "PLPerTradeAvgPct": -0.10267,
    "PLPerDayAvgPct": -0.08556,
    "StratWinRate": 50.0,
    "DaysInTradeAvg": 1.0,
    "TotStratTrades": 10,
    "TotStratPL": -766.84,
    "TotStratPLPct": -109.52,
    "CreditReceivedPerTradeAvg": 70.02,
    "marginPerTradeAvg": 229.98,
    "mostMarginUsed": 249.32,
    "leastMarginUsed": 208.64,
    "bestTradePctMargin": 43.17,
    "worstTradePctMargin": -100.59,
    "marginToStockPct": 0.31,
    "riskRewardAvg": 0.3098,
    "PctOfTimeInMarket": 100.0,
    "BestReturnOnRisk": 0.43165,
    "ProfitFactor": 0.31
  },
  "monthly": [
    {
      "year": 2026,
      "Jan": null,
      "Feb": null,
      "Mar": null,
      "Apr": null,
      "May": null,
      "Jun": -1.03,
      "Jul": null,
      "Aug": null,
      "Sep": null,
      "Oct": null,
      "Nov": null,
      "Dec": null,
      "annReturn": -1.03,
      "annSharpe": -8.23,
      "annSortino": -5.43,
      "annVolatility": 3.14
    }
  ],
  "trades": [
    {
      "date": "2026-06-01",
      "entryTime": "0934",
      "ticker": "SPY",
      "leg": 1,
      "ratio": -1,
      "optionType": "put",
      "strike": 755.0,
      "expiry": "2026-06-01",
      "expiryTod": "pm",
      "dte": 1,
      "tradeOptPx": 1.33,
      "delta": -0.3497,
      "entryStockPx": 755.67,
      "exitDate": "2026-06-01",
      "exitTime": "1600",
      "exitQuoteTime": null,
      "exitStockPx": 758.54,
      "exitOptionPx": 0.0,
      "profit": 132.69,
      "exitReason": "Expiration",
      "margin": 221.32
    },
    {
      "date": "2026-06-01",
      "entryTime": "0934",
      "ticker": "SPY",
      "leg": 2,
      "ratio": 1,
      "optionType": "put",
      "strike": 752.0,
      "expiry": "2026-06-01",
      "expiryTod": "pm",
      "dte": 1,
      "tradeOptPx": 0.55,
      "delta": -0.0391,
      "entryStockPx": 755.67,
      "exitDate": "2026-06-01",
      "exitTime": "1600",
      "exitQuoteTime": null,
      "exitStockPx": 758.54,
      "exitOptionPx": 0.0,
      "profit": -55.31,
      "exitReason": "Expiration"
    }
  ],
  "dailyReturns": [
    {
      "date": "2026-06-01",
      "return": 0.001024,
      "marginReturn": 0.349629
    },
    {
      "date": "2026-06-02",
      "return": 0.000652,
      "marginReturn": 0.198059
    }
  ]
}

Backtest Inputs

GEThttps://api.orats.io/backtests/intraday/input

Retrieves the original inputs a backtest was submitted with, exactly as they were sent. Useful for re-running or editing a backtest.

Required attributes

  • Name
    id
    Type
    string
    Description

    The backtestId to retrieve. Ex: aapg5gmoqs1r

GET/backtests/intraday/input
curl -L "https://api.orats.io/backtests/intraday/input?token=my-token&id=aapg5gmoqs1r"

Response

{
  "symbol": "SPY",
  "startDate": "2026-06-01",
  "endDate": "2026-06-12",
  "entryTime": "0934",
  "exitTime": null,
  "strategy": "PUT_CREDIT_SPREAD",
  "legs": [
    {
      "optionType": "put",
      "ratio": -1,
      "deltaTarget": 0.3,
      "deltaMin": 0.2,
      "deltaMax": 0.5,
      "dteTarget": 1,
      "dteMin": 1,
      "dteMax": 1
    },
    {
      "optionType": "put",
      "ratio": 1,
      "legRelation": {
        "strikeWidth": {
          "refLeg": 1,
          "target": 3
        },
        "dteDiff": {
          "refLeg": 1,
          "target": 0
        }
      }
    }
  ],
  "expiryTod": "both",
  "stopLossPct": null,
  "profitTargetPct": null,
  "tradePct": 0.66,
  "commissionPerContract": 0.65,
  "maxHoldDays": null,
  "badPriceFilter": {
    "maxWidthPctOfStrike": 0.05,
    "maxWidthPctOfMid": 0.15
  },
  "signals": null
}

Save a Note

POSThttps://api.orats.io/backtests/intraday/notes

Saves a note on a backtest. The note is returned on the status endpoint as the notes field and survives re-runs. Sending an empty string clears the note.

Required attributes

  • Name
    id
    Type
    string
    Description

    The backtestId to annotate. Ex: aapg5gmoqs1r

  • Name
    notes
    Type
    string
    Description

    The note text, up to 10,000 characters.

POST/backtests/intraday/notes
{
  "id": "aapg5gmoqs1r",
  "notes": "SPY 0DTE put credit spread test"
}

Response

{
  "message": "Notes updated successfully",
  "id": "aapg5gmoqs1r"
}

Delete a Backtest

DELETEhttps://api.orats.io/backtests/intraday

Deletes a backtest and its results. Deletion is idempotent: deleting an already-deleted id still returns success. After deletion the status endpoint returns a message of Status not found for the id.

Required attributes

  • Name
    id
    Type
    string
    Description

    The backtestId to delete. Ex: aapg5gmoqs1r

DELETE/backtests/intraday
curl -L -X DELETE "https://api.orats.io/backtests/intraday?token=my-token&id=aapg5gmoqs1r"

Response

{
  "message": "Backtest deleted successfully",
  "id": "aapg5gmoqs1r"
}
Contact Us
Questions about the API requirements? Want to become an affiliate? Curious about the backtester? Leave us a message and we'll get back to you shortly.
Your email
Your message
Submit
ORATS University
ORATS University
Master the art of options
Research
Implementation
Risk
Review
The opinions and ideas presented herein are for informational and educational purposes only and should not be construed to represent trading or investment advice tailored to your investment objectives. You should not rely solely on any content herein and we strongly encourage you to discuss any trades or investments with your broker or investment adviser, prior to execution. None of the information contained herein constitutes a recommendation that any particular security, portfolio, transaction, or investment strategy is suitable for any specific person. Option trading and investing involves risk and is not suitable for all investors. For more information please see our disclaimer.
Interactive Brokers is not affiliated with Option Research & Technology Services, LLC and does not endorse or recommend any information or advice provided by Option Research & Technology Services, LLC.