本文へ移動
← すべてのサンプル

サンプル 45

Orderflow strategy

an order-flow strategy, described in T0 and run by TTT's engine. It buys when sellers were absorbed -- heavy one-sided selling that did not

カテゴリ
Host:ターミナルのデータとエンジンが必要
権限
market.readbacktest.run
実行する前に
at least one published BTCUSDT dataset on this machine (Datasets window)
何をするか
starts two backtest jobs (they appear in the Jobs panel); writes their runs under the terminal's runs folder.
実行方法
grant market.read and backtest.run in the T0 Lang window, Run. "Stop job" stops only the backtest; "Stop program" stops both.
言語
>=0.1.1, <0.2.0
ホスト
>=0.1.1, <0.2.0
必要なもの
market >=0.1.1, <0.2.0features >=0.1.0, <0.2.0backtest >=0.1.1, <0.2.0

ソース

// Purpose: an order-flow strategy, described in T0 and run by TTT's engine. It buys when sellers were absorbed -- heavy one-sided selling that did not
// move price (`inferred_absorption_sell_side`: INFERRED from the tape, never observed) -- while price is under the session VWAP, and sells when price
// crosses back up through the VWAP. It is run twice on the newest published BTCUSDT dataset, with a loose and a strict notion of "heavy", and the two
// reports are printed side by side: the point of a backtest is the comparison, and a rule that only works at one threshold is a curve fit.
// `min_volume` is in units of the instrument, like an order's size: 1.0 and 5.0 below are one and five bitcoin sold into the bar.
// Category: host
// Permissions: market.read, backtest.run
// Preconditions: at least one published BTCUSDT dataset on this machine (Datasets window)
// Side effects: starts two backtest jobs (they appear in the Jobs panel); writes their runs under the terminal's runs folder.
// Run: grant market.read and backtest.run in the T0 Lang window, Run. "Stop job" stops only the backtest; "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 vwap_absorption(min_volume: Decimal, imbalance_bps: Decimal, size: Quantity) version "1.0.0" {
    let px = features.price(features.Source.AggTrades);
    let vw = features.vwap(features.Source.AggTrades);
    let absorbed = features.inferred_absorption_sell_side(features.Source.AggTrades, min_volume, imbalance_bps);
    rule enter when absorbed && px < vw && exposure_is(Exposure.Flat)
        => order(Side.Buy, Intent.Open, OrderType.Market, Sizing.Fixed(size));
    rule exit when cross_above(px, vw) && exposure_is(Exposure.Open)
        => order(Side.Sell, Intent.Close, OrderType.Market, Sizing.Fixed(size));
    flatten_on_stop;
}

fn run(ds: market.Dataset, min_volume: Decimal, imbalance_bps: Decimal) -> Result<Unit, Error> {
    let job = backtest.submit(backtest.Spec {
        strategy: vwap_absorption(min_volume, imbalance_bps, 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 report = backtest.wait(job)?;
    print("heavy from " + to_string(min_volume) + " at " + to_string(imbalance_bps) + " bps: " + to_string(report.status) + ", " + to_string(report.trades) + " trades, realized " + to_string(report.realized_pnl) + ", fees " + to_string(report.fees_paid));
    return Ok(());
}

fn main() -> Result<Unit, Error> {
    let ds = market.datasets("BTCUSDT")?.first().expect("no published BTCUSDT dataset on this machine");
    run(ds, 1.0, 6000.0)?;
    run(ds, 5.0, 8000.0)?;
    return Ok(());
}