Skip to content
← All examples

Example 17

Trade pages

read a run's closed trades page by page (`trades_page`), the

Category
Host: needs the terminal's data and engine
Permissions
market.readbacktest.run
Before you run it
a published BTCUSDT dataset on this machine
What it does
runs one backtest on TTT's engine (one job, waited for)
How to run it
in TTT, open "T0 Lang", open this file, grant market.read and
Language
>=0.1.1, <0.2.0
Host
>=0.1.3, <0.2.0
Needs
market >=0.1.1, <0.2.0features >=0.1.0, <0.2.0backtest >=0.1.3, <0.2.0

Source

// Purpose: read a run's closed trades page by page (`trades_page`), the
// way to read a run too large for one `trades` call, and check the pages
// add up to the whole.
// Category: host
// Permissions: market.read, backtest.run
// Preconditions: a published BTCUSDT dataset on this machine
// Side effects: runs one backtest on TTT's engine (one job, waited for)
// Run: in TTT, open "T0 Lang", open this file, grant market.read and
// backtest.run, Run.

lang ">=0.1.1, <0.2.0";
host "ttt" ">=0.1.3, <0.2.0";
requires "market" ">=0.1.1, <0.2.0";
requires "features" ">=0.1.0, <0.2.0";
requires "backtest" ">=0.1.3, <0.2.0";

strategy flip(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 report = backtest.run(backtest.Spec {
        strategy: flip(2, 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.None,
            latency: 0ms,
            market_fill: backtest.MarketFill.NextPrint,
            limit_fill: backtest.LimitFill.TradeThrough,
        },
    })?;
    let mut read = 0;
    let mut pages = 0;
    let mut from = 0;
    let mut more = true;
    while more {
        let page = backtest.trades_page(report.run_id, from, 1)?;
        read = read + page.trades.len();
        pages = pages + 1;
        match page.next {
            Some(next) => {
                from = next;
            }
            None => {
                more = false;
            }
        }
    }
    let all = backtest.trades(report.run_id)?;
    print(to_string(read) + " trades in " + to_string(pages) + " page(s); trades() has " + to_string(all.len()));
    print(if read == all.len() { "the pages add up to the whole" } else { "the pages DO NOT add up" });
    match backtest.trades_page(report.run_id, 0, 0) {
        Ok(_) => print("unexpected: an empty page was accepted"),
        Err(e) => print("refused as it should be: " + e.code),
    }
    return Ok(());
}