Runner, LiveEngine, BacktestRunner¶
Signal¶
Emitted by a strategy when it places an order.
| Field | Type | Description |
|---|---|---|
order_id |
int |
Order ID |
symbol |
int |
Symbol ID |
side |
str |
"buy" or "sell" |
order_type |
str |
"market", "limit", "stop_market", "stop_limit", "tp_market", "tp_limit", "trailing_stop", "cancel", "cancel_all", "modify" |
price |
float |
Limit price (0 for market orders) |
quantity |
float |
Order quantity |
trigger_price |
float |
Stop/take-profit trigger |
trailing_offset |
float |
Trailing stop absolute offset |
trailing_bps |
int |
Trailing stop callback rate (basis points) |
new_price |
float |
Modify: updated price |
new_quantity |
float |
Modify: updated quantity |
Runner¶
Synchronous strategy host. Push market data; strategy callbacks fire before the call returns. Pass threaded=True to use a Disruptor ring buffer with strategy callbacks running in a background C++ thread.
from flox.runner import Runner
def on_signal(sig: Signal):
print(sig.side, sig.quantity, sig.price)
runner = Runner(registry, on_signal) # synchronous
runner = Runner(registry, on_signal, True) # threaded
runner.add_strategy(my_strategy)
runner.start()
runner.on_trade(btc, 67000.0, 0.01, True, ts_ns)
runner.on_book_snapshot(btc, bid_prices, bid_qtys, ask_prices, ask_qtys, ts_ns)
runner.stop()
Constructor¶
| Parameter | Description |
|---|---|
registry |
Handle from flox_registry_create() |
on_signal |
Called when a strategy emits an order |
threaded |
If True, use Disruptor-based consumer thread |
Methods¶
| Method | Description |
|---|---|
add_strategy(strategy) |
Register a strategy instance |
start() |
Start the runner |
stop() |
Stop and clean up |
on_trade(symbol, price, qty, is_buy, ts_ns) |
Push a trade tick |
on_book_snapshot(symbol, bid_prices, bid_qtys, ask_prices, ask_qtys, ts_ns) |
Push a full L2 snapshot |
on_bar(symbol, open, high, low, close, volume=0.0, buy_volume=0.0, start_time_ns=0, end_time_ns=0, bar_type=0, bar_type_param=0, close_reason=0) |
Push a closed bar |
set_market_data_recorder(recorder_handle) |
Attach a market-data recorder handle so pushed events are also written to a tape |
symbol is typed int. Codon compiles statically, so there is no duck-typed overload accepting an
object with a symbol_id property — resolve the id yourself before calling.
BacktestRunner¶
Replays OHLCV data through a strategy. Emitted orders go to SimulatedExecutor automatically.
from flox.runner import BacktestRunner
bt = BacktestRunner(registry, fee_rate=0.0004, initial_capital=10_000.0)
bt.set_strategy(my_strategy)
stats = bt.run_csv("data/btcusdt.csv", "BTCUSDT")
stats = bt.run_ohlcv(timestamps, closes, "BTCUSDT")
print(stats.return_pct, stats.sharpe_ratio)
Constructor¶
Methods¶
| Method | Returns | Description |
|---|---|---|
set_strategy(strategy) |
None |
Attach a strategy |
run_csv(path, symbol) |
BacktestStats |
Replay a CSV file (columns: timestamp, open, high, low, close, volume) |
run_ohlcv(timestamps, closes, symbol) |
BacktestStats |
Replay raw arrays (List[int] timestamps in ns, List[float] closes) |
run_bars(start_ns, end_ns, opens, highs, lows, closes, volumes, symbol, bar_type=0, bar_type_param=0) |
BacktestStats |
Replay full OHLCV bars. Strategy.on_bar fires; on_trade does not |
run_tape(path) |
BacktestStats |
Replay one .floxlog tape directory |
run_tapes(paths) |
BacktestStats |
Replay N .floxlog tapes merged on read |
equity_curve() |
Tuple[List[int], List[float], List[float]] |
(timestamps_ns, equity, drawdown_pct) from the most recent run, all the same length. Raises if no run has completed |
trades() |
9 parallel lists | (symbol, side, entry_price, exit_price, quantity, pnl, fee, entry_time_ns, exit_time_ns) for the closed trades of the most recent run. side is 0 for long, 1 for short |
close() |
None |
Free resources |
See Backtest for the BacktestStats field reference.