Early access

Build a strategy. Test it honestly. Run it live.

Liqport is a backtesting engine and web terminal for systematic traders: write strategies in Python or Rust, or with your AI coding tool, and the same code runs live.

Liqport / Terminal · Run → OverviewMNQ · 2019-2026
Run overview: net PnL +$147,211 from $100,000, split into longs +$85,636 and shorts +$61,575, maximum drawdown -$16,927 and win rate 51.0% over 2,448 trades, the detailed statistics for all, long and short trades, the equity curves with their drawdowns below, and a February 2026 calendar of daily PnL.Run overview: net PnL +$147,211 from $100,000, split into longs +$85,636 and shorts +$61,575, maximum drawdown -$16,927 and win rate 51.0% over 2,448 trades, the detailed statistics for all, long and short trades, the equity curves with their drawdowns below, and a February 2026 calendar of daily PnL.

How it works

From idea to live,
in one place

Charting, backtesting, Monte Carlo, prop rules, live trading. Most traders use five tools for that. In Liqport it's one codebase.

One strategy codebase · from the first idea to the live account6 steps · no rewrites
  1. 01

    Write the strategy

    Write it in Python or Rust, with ready-made indicators or your own, and set entries, exits, sizing and risk rules in code. Or describe it to Claude, Codex or another coding agent and let it write the code. Either way it's real code you can read and change.

  2. 02

    Backtest it honestly

    The engine replays history bar by bar. It decides on closed bars, fills at the next bar's open, charges each instrument's fees and the slippage you set, and knows exchange holidays and early closes.

  3. 03

    Find the robust regions

    Explore combinations of signal settings, stops, targets and trading sessions. Look for broad performance plateaus beyond a single historical optimum.

  4. 04

    Stress-test it

    Run Monte Carlo on your own trades to find the size that fits the drawdown you accept, and re-price past trades to today's contract size. The prop-firm simulator gives your chance to pass a challenge and reach a payout.

  5. 05

    Build a portfolio

    Combine strategies, set each one's size, and run them together as one backtest with a joint equity curve.

  6. 06

    Run the same code liveSoon

    When live trading opens, the code you tested is the code that trades. There's no rewrite between the backtest and live trading.

Example workflows

Ask in plain English.
Get a tested answer.

Your coding agent works inside a Liqport project. It writes the strategy, runs the engine and reads the results back to you. Here is one strategy taken from an idea to a portfolio, with the numbers each step produced.

Claude Code · Liqport projectyour agent

Here's my idea: mark the 09:30-09:45 opening range on MNQ. When a 15-minute candle closes above it, buy; below it, sell; each side once a day. Stop just past the other side of the range, target 1.5R, stop to break-even at 1R, risk 1% a trade. Write it and backtest it since 2019.

Write OrbOpenType

range 09:30-09:45 ET · 15-minute closes · stop 2 ticks past the far side · target 1.5R · break-even at 1R · 1% risk, max 30 contracts · flat by 15:58 ET · each trade tagged with the session's open type

Backtest · CME:MNQ.V.0 · 15m · 2019-05-06 to 2026-10-02

2,448 trades · net +$147,211 · max drawdown -$16,927 · fees $16,271

Done. Risking 1% a trade on a $100,000 account, it made +$147,211 after fees from May 2019 to October 2026: +$85,636 from longs and +$61,575 from shorts, with a worst drawdown of -$16,927. The run is in the terminal, with every trade on the chart.

simplified excerpt

orb_open_type.rs

use liqport::prelude::*;

/// A 15-minute close beyond the 09:30-09:45 range enters that way.
impl OrbOpenType {
    fn on_bar(&mut self, bar: &Candle) {
        self.maybe_roll_day(bar); // a new NY day re-arms both sides
        if !self.range_done_today(bar) { return; } // 09:45 to midnight
        let (Some(hi), Some(lo)) = (self.orb.high(), self.orb.low())
        else { return };
        let (side, order) = if !self.fired_long && bar.close.to_f64() > hi {
            self.fired_long = true; // each side once a day, taken or not
            (Side::LONG, Order::long(self.instrument))
        } else if !self.fired_short && bar.close.to_f64() < lo {
            self.fired_short = true;
            (Side::SHORT, Order::short(self.instrument))
        } else { return };
        if !self.positions.of(self.instrument).is_flat() { return; }
        let label = self.open_type.read(|o| o.is_final().then(|| o.label()));
        let (Some(Some(label)), Some(stop)) =
            (label, self.stop_for(side, hi, lo, bar)) // far side + 2 ticks
        else { return }; // no open type: no trade
        self.orders.place(
            order
                .stop_loss(stop)
                .take_profit(rr(1.5))             // 1.5R
                .size(limit_risk_based(0.01, 30)) // 1% risk, max 30
                .breakeven(Breakeven { trigger: rr(1.0), offset: Px::ZERO })
                .tag(label.as_str()),             // e.g. "open-drive"
        );
    }
}

const NY: &str = "America/New_York";

/// Setup: 15- and 1-minute candles, the range, its open type, three rules.
impl Strategy for OrbOpenType {
    const NAME: &'static str = "OrbOpenType";
    type Config = OrbOpenTypeConfig;

    fn build(config: Self::Config, run: &mut Run<Self>)
        -> Result<Self, BuildError> {
        let instrument = run.instrument(&config.symbol)?;
        let m15 = Candles::on(instrument, Timeframe::Mins(15));
        run.subscribe(m15.calls(Self::on_bar))?;
        let m1 = run.subscribe(Candles::on(instrument, Timeframe::Mins(1)))?;
        let orb = run.subscribe(
            Tbl::new((9, 30, 0), (9, 45, 0), AnchorTz::new(NY)).on(m1))?;
        let open_type = run.subscribe(OpenType::new(OpenTypeConfig {
            from_time: (9, 30, 0), to_time: (9, 45, 0), tz: NY.into(),
            band_frac: 0.10, test_frac: 0.35, hold_frac: 0.25,
        }).on(m1))?;
        let flat_at = WallTime::hm(15, 58);
        run.subscribe(ExecRuleConfig::CloseAtTime { // flat by 15:58
            tz: NY.into(), time: flat_at, cancel_open_orders: true,
            order_comment: "OrbOpenType EOD flat".into(),
        })?;
        run.subscribe(ExecRuleConfig::SessionEntryWindow { // then wait
            tz: NY.into(), time: flat_at, close_buffer_minutes: 2,
            fallback_resume: WallTime::hm(18, 0), // for the next session
        })?;
        // Flat, with no entries, from 8 hours before each contract roll.
        run.subscribe(ExecRuleConfig::ContractRoll { lead_minutes: 480 })?;
        let (orders, positions) = (run.orders(), run.positions());
        Ok(Self::new(config, orders, positions, instrument, orb, open_type))
    }
}
Hear when example runs open

What's built

Built for our own trading. Ready for yours.

Test it honestly

Results you can rely on before money is at risk.

  • Backtests you can trust

    Decisions on closed bars, fills at the next bar's open, each instrument's fees, the slippage you set, and exchange holidays and early closes.

  • Every run on record

    Each run keeps the exact settings and strategy code it ran with, so you can open it later and run it again.

  • Stress tests

    Monte Carlo on your own trades, past trades re-priced to today's contract size, and parameter sweeps across your settings.

Know your risk

Size, stops and prop rules, settled before the trade.

  • Your risk rules, in code

    Fixed size or a share of the account at risk, with a contract cap. Stops by price, ticks, percent or an ATR distance, targets in R, and break-even moves.

  • Know your prop odds

    Pick a firm's account with its real rules: trailing drawdown, profit target, consistency, payouts and fees. See your chance to pass, the chance of a payout, the cost and the best size.

  • Portfolios

    Combine strategies, set each one's size and run them together as one backtest, with one joint equity curve.

See every detail

From one trade to every market.

  • Every trade on the chart

    Jump to any trade and see its entries and exits. Split PnL by exit reason, month, weekday, half hour or your own tags, such as regime or setup.

  • Sessions and calendars

    Trade windows, no-trade windows and a flat-by time are built-in rules. Exchange calendars cover holidays and early closes.

  • Any market

    Futures, equities, crypto and forex on the same engine, with each instrument's contract specs and fees. Options are coming soon.

Build and run

Real code, your AI, and the same code live.

  • Bring your AI

    Work with the AI coding tools you prefer, such as Claude or Codex, on Liqport's strategy framework. You get real code you can read and change.

  • Build anything on top

    Strategies are real code in Python or Rust. Add your own sizing, exits, filters or indicators, or ask your AI to.

  • Same code, liveSoon

    When live trading opens to you, the code you backtested is the code that trades. Connect brokers such as Interactive Brokers, Tradovate and Rithmic, crypto exchanges such as Binance and Kraken, and prop firm accounts at Topstep, Lucid, Tradeify, Apex, FTMO and more.

More than price data.
Every input your strategy needs.

Research across futures, forex, equities and crypto starts with the right inputs. Liqport's engine is designed to bring market prices, trade events, economic releases, fundamentals and alternative datasets into a shared timeline.

Different sources. One research foundation.Illustrative inputs · No live feed

Market and execution data

Prices, transactions and the state of the market.

OHLCV bars

Price and volume, organized into intervals.

Individual trades

Trade prints as discrete tick events.

Bid/ask quotes · L1

Best prices and available sizes on each side.

Order-book data

Collected depth snapshots and updates.

Contextual and custom data

The information surrounding a trading decision.

Economic calendar

Scheduled releases and economic-event context.

Fundamental data

Reported measures that add context over time.

Alternative data

Specialized research inputs beyond market prices.

Custom series & events

Your own inputs through compatible data adapters.

Source-specific adaptersSchema & time alignmentLiqport engine

Used internally. Built for connected research. Our team works with market, economic, fundamental and alternative inputs. Each source needs an appropriate schema, time alignment and integration; execution modeling depends on the data and model in use.

Customer data access is being prepared. Supported markets, datasets, historical coverage and access rights will be confirmed as the research experience opens. Availability varies by market and provider, with source licensing and entitlements applying.

Take your
research further.

Liqport is preparing its first research experience.

Join early access to be notified when you can develop, test and investigate your own systematic strategies in one connected workspace.

By signing up, you agree to receive Liqport early-access emails. Withdraw at any time using the link in our emails. Privacy policy.

Before you begin.

A few things to know about Liqport and early access.

Is Liqport ready?

Not for customers yet. We use it every day to research and trade our own strategies. Join early access and we'll email you when you can start.

Do I need to code?

No, but you can. Strategies are real Python or Rust code. Write them yourself, or describe the idea to an AI coding agent such as Claude or Codex and let it write them. Either way you can read, check and change every line.

Which AI tools work with Liqport?

Coding agents that can edit files and run commands, such as Claude Code and Codex. The agent writes the strategy, runs the backtest and reads the results back to you.

Which markets can I test?

Futures, equities, crypto and forex, each with its own contract specs and fees. Options are coming soon.

Can I trade live?

Not yet. Live trading is coming. When it opens, the code you backtested is the code that trades, with no rewrite in between.

Will my backtest match live trading?

Not exactly; no backtest does. Liqport narrows the gap: decisions on closed bars, fills at the next bar's open, and each instrument's fees and the slippage you set. Running the same code live removes the gap a rewrite would add.