← 모든 예제
예제 59
Handler with context
a handler that reads what the strategy holds. `handler bar(5) = on_bar(ctx, px, average)` gives the function a `handlers.Context` -- the open positions
- 분류
- Host: 터미널의 데이터와 엔진 필요
- 권한
- market.readbacktest.run
- 실행하기 전에
- at least one published BTCUSDT dataset on this machine (Datasets window)
- 하는 일
- starts a backtest job (it appears in the Jobs panel); writes its run under the terminal's runs folder.
- 실행 방법
- grant market.read and backtest.run in the T0 Lang window, Run. Put on a replay or the live market, the same handlers run there.
- 언어
>=0.2.0, <0.3.0- 호스트
>=0.1.15, <0.2.0- 필요한 것
- market >=0.1.1, <0.2.0features >=0.1.0, <0.2.0handlers >=0.1.1, <0.2.0backtest >=0.1.1, <0.2.0
소스
// Purpose: a handler that reads what the strategy holds. `handler bar(5) = on_bar(ctx, px, average)` gives the function a `handlers.Context` -- the open positions // of every book, the orders still working, the equity -- as of the bar that closed, so it keeps no copy of that in its state. The state it does keep is a `Map` // from a price level (to the dollar, written as text) to how many bars closed there; `for (level, bars) in memory.visits` walks it in price order. // // BUY when flat, with nothing working, price over its average, and the level it is at has been visited before (the market came back to it). // SELL when it holds a long and price falls under the average. // // What a handler cannot do is look ahead: it sees the signals and the context as of the event that closed the bar, and only when every signal is known. // HONEST NOTE: written to show the shape; its edge has not been measured. // Category: host // Permissions: market.read, backtest.run // Preconditions: at least one published BTCUSDT dataset on this machine (Datasets window) // Side effects: starts a backtest job (it appears in the Jobs panel); writes its run under the terminal's runs folder. // Run: grant market.read and backtest.run in the T0 Lang window, Run. Put on a replay or the live market, the same handlers run there. lang ">=0.2.0, <0.3.0"; host "ttt" ">=0.1.15, <0.2.0"; requires "market" ">=0.1.1, <0.2.0"; requires "features" ">=0.1.0, <0.2.0"; requires "handlers" ">=0.1.1, <0.2.0"; requires "backtest" ">=0.1.1, <0.2.0"; struct Memory { visits: Map<String, Int>, } struct Step { state: Memory, actions: List<handlers.Act>, } fn begin() -> Memory { return Memory { visits: Map.new() }; } fn order(side: handlers.Side, intent: handlers.Intent, size: Quantity) -> handlers.Act { return handlers.Act.Submit(handlers.Order { book: "main", side: side, intent: intent, qty: size, limit: None, stop: None, take_profit: None, stop_loss: None, tag: 0, post_only: false, immediate: false, expire_minutes: 0 }); } fn level_of(px: Float) -> String { return to_string(decimal_from_float(px, 0)); } fn most_visited(visits: Map<String, Int>) -> Int { let mut best = 0; for (level, bars) in visits { if bars > best { best = bars; } } return best; } fn on_bar(memory: Memory, ctx: handlers.Context, px: Float, average: Float) -> Step { let level = level_of(px); let seen = match memory.visits.get(level) { Some(bars) => bars, None => 0, }; let mut visits = memory.visits; visits.insert(level, seen + 1); let next = Memory { visits: visits }; if ctx.positions.len() == 0 && ctx.orders.len() == 0 && px > average && seen > 0 && seen < most_visited(memory.visits) + 1 { return Step { state: next, actions: [order(handlers.Side.Buy, handlers.Intent.Open, qty(0.1))] }; } if ctx.positions.len() > 0 && px < average { return Step { state: next, actions: [order(handlers.Side.Sell, handlers.Intent.Close, qty(0.1))] }; } return Step { state: next, actions: [] }; } strategy returning_to_levels(period: Int) version "1.0.0" { let px = features.price(features.Source.AggTrades); let average = features.sma(period); state = begin(); handler bar(5) = on_bar(ctx, px, average); } 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: returning_to_levels(3), dataset: ds, start: None, end: None, starting_balance: money(100000, 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, }, })?; print(report.status); print(report.trades); print(report.final_equity); return Ok(()); }