Strasmore Research
Learn Matt ConnorBy Matt Connor

Open-Source Trading Terminal for Python

What an open-source trading terminal for Python really is: where an agentic IDE sits between a notebook, a backtester and a live broker, and what it cannot do.

An open-source trading terminal for Python is one window holding four jobs at once: an editor for strategy code, a data layer, a backtest runner, and a log pane that prints what ran. The 2026 crop of these projects adds a chat agent with tool access to that window, which is what a README means by "agentic IDE for Python strategies". The agent writes and runs the same code a person would write by hand, and it inherits every weakness in the data feed and the fill assumptions sitting underneath it.

What an open-source trading terminal for Python actually is

Four moving parts, none of them new on its own.

  • A file layout. The strategy lives on disk as a Python module with a declared entry point, not as cell 14 of a notebook.
  • A runner. One command turns that module into a trade list, an equity curve and a stats table.
  • A tool surface for the model. The agent gets a handful of verbs: read a file, patch a file, run the backtest, read the result.
  • A pane that prints the run. Timestamps, order intents, stack traces, and the diff the agent just applied.

What is new is the loop. The model proposes an edit, the runner scores it, the pane shows the score, and the model reads the score and proposes the next edit. Our walkthrough of how to backtest a trading strategy is the manual version of that cycle, and the manual version is still the one you audit.

Where it sits between a notebook, a backtester and a broker

A notebook keeps state in memory and in the order the cells ran, which is why a notebook result is hard to reproduce a month later. A terminal project moves that state into files and commands, closer to the discipline in our reproducible backtest walkthrough. A broker connection is a third thing again: a key, an order endpoint, and a reconciliation problem.

The seam that matters most is resolution. The pane plots one bar size, and fills happen at another.

QueryApple in June 2026: full-day range against the widest single minute
21 rows (showing 20)
session_datesession_labeldaily_range_bpswidest_minute_bps
2026-06-01Jun 1193.352.9
2026-06-02Jun 2278.158.2
2026-06-03Jun 3260.742.2
2026-06-04Jun 412572.9
2026-06-05Jun 5260.953.8
2026-06-08Jun 8538.2151.6
2026-06-09Jun 9446.467.8
2026-06-10Jun 10252.856.8
2026-06-11Jun 11250.771.4
2026-06-12Jun 12258.360.7
2026-06-15Jun 15205.176.6
2026-06-16Jun 16217.640.4
2026-06-17Jun 17260.559.8
2026-06-18Jun 18166.157.6
2026-06-22Jun 22190.685.2
2026-06-23Jun 23253.5105.9
2026-06-24Jun 24230.773.8
2026-06-25Jun 25547140.9
2026-06-26Jun 26413.7132.9
2026-06-29Jun 29302.489.7
The exact SQL behind every number
SELECT
    toString(bars.session)                AS session_date,
    formatDateTime(bars.session, '%b %e') AS session_label,
    round((toFloat64(bars.high) - toFloat64(bars.low)) / toFloat64(bars.close) * 10000, 1) AS daily_range_bps,
    round(mins.widest_minute_bps, 1)      AS widest_minute_bps
FROM
(
    SELECT date AS session, high, low, close
    FROM global_markets.stocks_daily_aggs
    WHERE ticker = 'AAPL'
      AND date >= '2026-06-01'
      AND date <  '2026-07-01'
) AS bars
INNER JOIN
(
    SELECT
        toDate(toTimeZone(window_start, 'America/New_York')) AS session,
        max((toFloat64(high) - toFloat64(low)) / toFloat64(close) * 10000) AS widest_minute_bps
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'AAPL'
      AND window_start >= '2026-06-01 04:00:00'
      AND window_start <  '2026-07-01 04:00:00'
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) >= 570
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) < 960
    GROUP BY session
) AS mins ON mins.session = bars.session
ORDER BY bars.session
Run this yourself

Over 21 June 2026 sessions, Apple's full-day range measured 193.3 basis points of its close on Jun 1 and 319.5 on Jun 30. A basis point is one hundredth of one percent. Inside those same two sessions, the widest single minute covered 52.9 and 84.3 basis points. The distance between the two lines is the room a daily-bar backtest leaves to assumption. It knows the close was printed. It knows nothing about where inside the session an order would have landed. An agent iterating against daily bars is optimizing inside that gap, which is also where the trap covered in look-ahead bias in backtesting lives.

What does the terminal pane actually show?

Usually four things: a quote strip, a positions table, a run log, and a pending-intent queue the agent fills before anything is sent. The quote strip is the one readers over-trust. A bid and an ask printed to the cent look like a price you can transact at. They are the top of a queue, and their width moves on a daily rhythm.

QueryApple quoted spread by 30 minute ET bucket, June 15 2026 session
et_timemedian_spread_bpsp95_spread_bps
09:301.694.44
10:001.352.03
10:301.012.03
11:000.681.35
11:300.671.35
12:000.671.34
12:300.671.01
13:000.671.35
13:300.671.35
14:000.681.35
14:300.681.02
15:000.671.01
15:300.671.01
The exact SQL behind every number
SELECT
    formatDateTime(toStartOfInterval(toTimeZone(sip_timestamp, 'America/New_York'), INTERVAL 30 MINUTE), '%H:%i') AS et_time,
    round(quantileDeterministic(0.5)(spread_bps, toUInt64(sequence_number)), 2)  AS median_spread_bps,
    round(quantileDeterministic(0.95)(spread_bps, toUInt64(sequence_number)), 2) AS p95_spread_bps
FROM
(
    SELECT
        sip_timestamp,
        sequence_number,
        (toFloat64(ask_price) - toFloat64(bid_price))
            / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000 AS spread_bps
    FROM global_markets.cache_stocks_quotes
    WHERE ticker = 'AAPL'
      AND sip_timestamp >= '2026-06-15 13:30:00'
      AND sip_timestamp <  '2026-06-15 20:00:00'
      AND bid_price > 0
      AND ask_price > bid_price
)
GROUP BY et_time
ORDER BY et_time
Run this yourself

In the 09:30 ET bucket on June 15, 2026, the median quoted spread on Apple measured 1.69 basis points, with the 95th percentile quote out at 4.44. By the 15:30 bucket, the median printed 0.67. Read the curve left to right and the shape is the whole lesson: a strip at 09:35 and the same strip at midday describe different liquidity, while a backtest charging the midpoint at every timestamp charges the same price in both. Where an order sits behind the quoted size is a separate estimate, broken down in how to estimate queue position.

Which parts need an API key or paid data?

Three tiers recur. Daily bars are usually free or nearly free, often adjusted and sometimes a day behind. Minute bars, quote ticks and full options chains sit on paid plans. The agent itself needs a model API key, billed per token on every iteration, so a terminal that loops ten times on one prompt carries a per-run cost no README benchmark covers.

Options panes make the tiering obvious. An implied-volatility reading is not a column anyone downloads. It is a per-contract field computed from a contract price, shipped with a convergence flag marking the solves that failed.

QueryApple near-the-money implied volatility by days to expiry, June 15 2026
dte_bucketatm_iv_pctcontracts
0-7d26.468
8-21d22.879
22-45d2236
46-90d2524
91d+2799
The exact SQL behind every number
SELECT
    multiIf(days_to_expiry <= 7,  '0-7d',
            days_to_expiry <= 21, '8-21d',
            days_to_expiry <= 45, '22-45d',
            days_to_expiry <= 90, '46-90d',
                                  '91d+') AS dte_bucket,
    round(avg(implied_volatility) * 100, 1) AS atm_iv_pct,
    count()                                 AS contracts
FROM global_markets.options_greeks
WHERE underlying_symbol = 'AAPL'
  AND date = '2026-06-15'
  AND iv_converged = 1
  AND volume > 0
  AND days_to_expiry >= 0
  AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.05
GROUP BY dte_bucket
ORDER BY min(days_to_expiry)
Run this yourself

Across Apple contracts struck within 5% of the underlying close on that session, the 0-7d bucket averaged 26.4% implied volatility over 68 contracts that traded, against 27% in the 91d+ bucket. That is one day, one underlying, one moneyness band. Reproducing the curve for a universe of names every day is the line where free data stops. The mechanics of the number are in how implied volatility is calculated.

No execution guarantee, and no validated fill model

Every backtest inside one of these terminals assumes a price you would have received, and most make the assumption in a single line of code. The honest version of that line is a model a reader can open: a spread cost, a size cap, a latency, a rejection path.

QueryMedian quoted spread across six large caps, 10:00 to 10:30 ET on June 15 2026
symbolmedian_spread_bpsp90_spread_bpsquote_millions
SPY0.270.40.44
KO1.232.470.04
AAPL1.352.030.14
NVDA1.431.440.3
MSFT1.763.260.05
NVR75.7592.250
The exact SQL behind every number
SELECT
    ticker AS symbol,
    round(quantileDeterministic(0.5)(spread_bps, toUInt64(sequence_number)), 2) AS median_spread_bps,
    round(quantileDeterministic(0.9)(spread_bps, toUInt64(sequence_number)), 2) AS p90_spread_bps,
    round(count() / 1e6, 2)                                           AS quote_millions
FROM
(
    SELECT
        ticker,
        sequence_number,
        (toFloat64(ask_price) - toFloat64(bid_price))
            / ((toFloat64(ask_price) + toFloat64(bid_price)) / 2) * 10000 AS spread_bps
    FROM global_markets.cache_stocks_quotes
    WHERE ticker IN ('SPY', 'AAPL', 'MSFT', 'NVDA', 'KO', 'NVR')
      AND sip_timestamp >= '2026-06-15 14:00:00'
      AND sip_timestamp <  '2026-06-15 14:30:00'
      AND bid_price > 0
      AND ask_price > bid_price
)
GROUP BY ticker
ORDER BY median_spread_bps
Run this yourself

Inside one 30 minute window, median quoted spreads across 6 large caps ran from 0.27 basis points on SPY to 75.75 on NVR, whose 90th percentile quote measured 92.25. The tightest name on the list alone printed 0.44 million quote updates in that half hour. A flat per-trade cost applied across names like these is off by more than an order of magnitude at one end of the chart. High-priced stocks with few shares changing hands quote wider in relative terms than an index ETF does, every hour of every session.

Four limits travel with this genre, and a README rarely states them. There is no execution guarantee: a broker API accepts an intent, then rejections, partial fills and halts arrive on their own schedule, a topic we cover in agentic trading bots on retail brokerages. There is no validated fill model unless the project publishes one and tests it against tick data, and backtesting in illiquid markets plus latency models in HFT backtests cover what validation involves. The demo data tier is rarely the tier a strategy needs. And early-stage project risk is real: a single-maintainer repository with no tagged release and no test suite is a prototype being adopted, not a product being bought.

How to judge the claim in the README

Pin the version before anything else. A fast-moving repository changes its entry points between Sundays, and any install line written down today drifts. Clone at a tag rather than at a branch, in the shape git clone --branch <tag> --depth 1 <repo-url>, or for a published package pip install "<package>==<tag>", and record the resolved commit beside your results. Where a project publishes no tags at all, that absence is itself a finding.

Then test the claim instead of quoting it. "Agentic IDE" asserts that the agent can edit and run a strategy end to end. Four checks settle it.

  1. From a fresh clone and one prompt, does it produce an equity curve using the data it ships?
  2. Is the fill model a readable file, or a hardcoded midpoint?
  3. Do the backtest path and the live path share one code path, or two that can disagree?
  4. When the agent is wrong, does the pane show the diff it applied and the command it ran?

A yes is a capability. An adjective is not. The same four checks are how we read an open-source TradingView optimizer or a model-facing data layer, as in market data skills for AI agents. These tools occupy different seats rather than a ranking. A notebook explores. An optimizer searches a parameter grid. A terminal agent edits and reruns. A broker bridge sends.

FAQ

What is an agentic IDE for Python strategies?

It is a code workspace where a language model holds tools for reading and patching your strategy files and running the backtest, with a pane printing each edit and each run. The strategy stays ordinary Python on disk, which separates it from a chat window that hands back a code block.

Is an open-source trading terminal for Python free to run?

The code is free. The inputs usually are not. Daily bars are often free, while minute bars, quote ticks and options chains sit on paid plans, and the agent needs its own model API key, billed per token on every iteration.

Can an open-source trading terminal place real orders?

Some connect to a broker API with keys you supply, and most ship with live trading switched off by default. A connection is not an execution guarantee: the broker accepts an intent, and rejections, partial fills and venue halts follow afterward.

How accurate are the fills in these backtesters?

As accurate as the fill model, which is frequently a midpoint assumption with a fixed cost. Measured quoted spreads vary by more than an order of magnitude across large caps in the same half hour, so one flat cost flatters some names and penalizes others.

What is the difference between a notebook and a trading terminal?

A notebook keeps state in memory and in the order the cells ran. A terminal project keeps the strategy in files and runs it with a command, which is what makes a result someone else can reproduce.

Data notes and the pinned window

Every panel here is pinned to a fixed historical window in June 2026, so the same SQL returns the same numbers years from now. The quote panels aggregate tick quotes for named tickers inside a narrow clock window, measured in basis points of the quote midpoint, with zero-priced and crossed quotes dropped. Percentiles use a deterministic estimator, so two renderings of one statistic cannot drift apart. The implied-volatility panel keeps contracts within 5% of the underlying close that traded at least once, with the vendor convergence flag set.


Every panel on this page carries the exact SQL beneath it, so open one and the measurement is visible. To check a spread, a session range or an implied-volatility curve for your own window before trusting a backtester's fill assumption, ask the question in plain English on the Strasmore terminal.

#open-source#tooling#python#backtesting#ai-agents