← All examples
Example 08
Backtest job
A backtest as a job: submit it, look at it while it runs, wait for its
- Category
- Host: needs the terminal's data and engine
- Permissions
- market.readbacktest.run
- Language
>=0.1.1, <0.2.0- Host
>=0.1.1, <0.2.0- Needs
- market >=0.1.1, <0.2.0features >=0.1.0, <0.2.0backtest >=0.1.1, <0.2.0
Source
// Category: host // Permissions: market.read, backtest.run // A backtest as a job: submit it, look at it while it runs, wait for its // report, then read its closed trades from the run's own journal. The // strategy runs on TTT's engine; T0 only describes it. // // Grant in the T0 Lang window: market.read, backtest.run. // While it runs, "Stop job" in the window stops only the backtest (this // program carries on and sees StoppedByUser); "Stop program" stops both. lang ">=0.1.1, <0.2.0"; host "ttt" ">=0.1.1, <0.2.0"; requires "market" ">=0.1.1, <0.2.0"; requires "features" ">=0.1.0, <0.2.0"; requires "backtest" ">=0.1.1, <0.2.0"; strategy sma_breakout(window: Int, size: Quantity) version "1.0.0" { let average = features.sma(window); let px = features.price(features.Source.Trades); rule enter when cross_above(px, average) && exposure_is(Exposure.Flat) => order(Side.Buy, Intent.Open, OrderType.Market, Sizing.Fixed(size)); rule exit when cross_below(px, average) && exposure_is(Exposure.Open) => order(Side.Sell, Intent.Close, OrderType.Market, Sizing.Fixed(size)); flatten_on_stop; } fn main() -> Result<Unit, Error> { let ds = market.datasets("BTCUSDT")?.first().expect("no published BTCUSDT dataset on this machine"); let job = backtest.submit(backtest.Spec { strategy: sma_breakout(30, qty(0.01)), dataset: ds, start: None, end: None, starting_balance: money(10000, USDT), execution: backtest.Execution { maker_fee: bps(2), taker_fee: bps(5), slippage: backtest.Slippage.Fraction(bps(1)), latency: 50ms, market_fill: backtest.MarketFill.NextPrint, limit_fill: backtest.LimitFill.TradeThrough, }, })?; let first = backtest.status(job)?; print("submitted " + first.run_id + ", " + to_string(first.state) + " (" + first.phase + ")"); let report = backtest.wait(job)?; print(to_string(report.status) + ": " + to_string(report.trades) + " trades, realized " + to_string(report.realized_pnl) + ", fees " + to_string(report.fees_paid)); let trades = backtest.trades(report.run_id)?; let mut winners = 0; for t in trades { if t.realized_pnl.amount() > 0.0 { winners = winners + 1; } } print(to_string(winners) + " of " + to_string(trades.len()) + " trades made money"); match trades.first() { Some(t) => print("first: " + t.side + " " + to_string(t.qty) + " from " + to_string(t.entry_price) + " to " + to_string(t.exit_price) + " (" + t.reason + ")"), None => print("no closed trades"), } return Ok(()); }