hawk-bt
A library for controlling the browser-based WASM simulation engine from Python.
The Role of hawk-bt in the Overall System Architecture»
During simulation, Python and the browser are directly connected via WebSocket. hawk-bt sits between them, handling all connection management, protocol translation, and synchronization control.
Make trading decisions in step(ctx)
Sync policy application / Loop execution
Position management / P&L
Report generation
Quick Start»
* hawk-backtester on PyPI is a separate, unrelated package.
Strategyクラスを書く(下の例 を参照)- Open the simulation screen in the browser
python my_strategy.pyを実行- Press "Start" on the browser side
When a session ends, the results are output to the log. Even if the browser disconnects and reconnects, the next session is automatically accepted.
Example: SMA Crossover»
Buy when the short SMA crosses above the long SMA; Sell when it crosses below.Buy when the short-term SMA crosses above the long-term SMA, Sell when it crosses below. Auto-close via TP/SL. No manual closing.
Code Walkthrough»
Explains how hawk-bt works, using the SMA crossover example above.Using the SMA crossover example above, we explain how hawk-bt operates.
Simulation Loop
A HawkEngine().start(SMACross()) When executed, it waits for a connection from the browser. Once connected, the backtest begins and repeats the following 3 steps for each bar:
ctx.state.snapshot
balance, equity, price …
Trading decision -> Order submission
TP/SL evaluation and fill processing
Inside step()
B async def step(self, ctx: Context) is the entry point called every bar. Read prices, make decisions, and place orders here.
- C ctx.state.snapshot.price — Get the current price and calculate SMA
- D place_ticket(side="buy", ...) — Place a market order on golden cross detection
- D take_profit=self.tp, stop_loss=self.sl — Specify TP/SL as absolute price differences
Sync Policy: eager vs deferred
D place_ticket() changes the state on the WASM side. The sync policy controls when those changes are reflected on the Python side.The sync policy controls when those changes are reflected on the Python side.
deferred (default)
eager (UI "High Precision" button ON)
eager syncs with WASM on every operation, so the state is always up to date. Safer, but incurs more communication overhead.
TP/SL Evaluation Timing
D take_profit=self.tp
TP/SL set here are not evaluated on the bar where the order was placed.TP/SL values set here are not evaluated on the bar where the order was placed.
They are evaluated against the high/low of the bar when step_next() advances to the next bar.
API -- Retrieving Information»
Account and market state auto-updated at the start of every step. No call needed.Account and market state, automatically updated at the beginning of each step. No explicit call needed.
| Field | Type | Description |
|---|---|---|
| balance | float | Account balance |
| equity | float | Equity (balance + unrealized P&L) |
| used_margin | float | Used margin |
| margin_level | float | Margin level |
| price | float | Current price |
| timestamp_ms | float | Timestamp (ms) |
| step | int | Bar number (0-indexed) |
| pending_orders | float | Number of pending orders |
| tickets_num | float | Number of open positions |
| ticket_all_num | float | Total positions (including closed) |
| bar_count | int | Number of processed bars |
| ticket_stat_0..3 | float | Position Statistics |
| ticket_long_count | float | Number of long positions |
| ticket_short_count | float | Number of short positions |
| pending_long_count | float | Number of pending long orders |
| pending_short_count | float | Number of pending short orders |
| total_steps | int | Total number of bars in the simulation |
Full-period OHLC + timestamps. Bulk-loaded at session start.OHLC + timestamps for the entire period. Fetched in bulk at session start. No further communication occurs after that. Since the data is a numpy array, slicing and arithmetic operations work directly.
candles.close[:step] for indicator calculations, and never reference data beyond the current bar. Strategies that use future prices will invalidate backtest results.
| Field | Description |
|---|---|
| time | Timestamp |
| open | Open |
| high | High |
| low | Low |
| close | Close |
List of open positions. Communication occurs on each call.
Returns
np.ndarray — Each row represents one position
Events since the last retrieval (closures, margin calls, etc.). Terminal state detection is also handled internally.
Returns
np.ndarray — shape (N, 5)
Manually re-fetches only the snapshot. Does not retrieve events.
API — Orders & Closing»
Market order. Fills immediately at the current market price.
| Param | Type | Note |
|---|---|---|
| side | str | "buy" / "sell" |
| units | int | Lot size (1 or more) |
| take_profit | float? | TP distance (absolute value) |
| stop_loss | float? | SL distance (absolute value) |
| trailing_stop | float? | Trailing stop distance |
take_profit=5.0 means "take profit when price moves 5.0 from entry." Not a percentage.
Limit ("limit") / Stop ("stop") order. Fills when the specified price is reached.
| Param | Type | Note |
|---|---|---|
| side | str | "buy" / "sell" |
| order_type | str | "limit" / "stop" |
| price | float | Order Price |
| units | int | Lot Size |
| take_profit | float? | TP Distance |
| stop_loss | float? | SL Distance |
| trailing_stop | float? | Trailing stop distance |
| time_limit | float? | Expiration (number of bars) |
Position closing. Full or partial.
| Param | Type | Note |
|---|---|---|
| position_ids | list[int] | Target position ID |
| actions | list[int] | Action code (see table below) |
| ratios | list[float] | Close ratio (0.0–1.0). Used only when action=2Close ratio (0.0-1.0). Used only when action=2 |
Action codes
| Code | Behavior | Handling of ratios |
|---|---|---|
| 1 | Full Close | Ignored |
| 2 | Partial Close | 1.0 = full close, 0.5 = half close |
action=1 immediately closes the entire position. action=2, ratio=1.0 also results in a full close, but action=1 is simpler.
Terminates the simulation mid-way. Normally ends automatically when all bars are consumed or on margin call.
Settings»
HawkEngine
| Param | Default | Note |
|---|---|---|
| host | "127.0.0.1" | Bind Address |
| port | 8787 | Port Number |
| on_result | None | Result callback (receives BacktestResult) |
BacktestResult
The result object passed to the on_result callback after session completion.
| Field / Method | Type | Description |
|---|---|---|
| steps | int | Completed Bar Count |
| balance | ndarray | Balance per bar |
| equity | ndarray | Equity per bar |
| price | ndarray | Price per bar |
| total_orders | int | Total Orders |
| win_count | int | Winning Trades |
| loss_count | int | Losing Trades |
| gross_profit | float | Gross Profit (sum of winning trades) |
| gross_loss | float | Gross Loss (sum of losing trades) |
| final_balance() | float | Final Balance |
| max_drawdown() | float | Max DD (e.g., -0.15) |
| max_drawdown_before_end() | float | Max DD (up to balance reaching 0) |
configure_logging(level)
| Level | Output |
|---|---|
| 1 | WARNING only |
| 2 | INFO — Connection/disconnection/result reports |
| 3 | DEBUG — Detailed log per order |
ctx.user
A dictionary for carrying data between steps. Can hold indicator buffers, trade count counters, or anything else.
Reference: Strategy Using Custom Indicators»
Since ctx.state.candles holds the entire period's OHLC as a numpy array, you can compute any indicator on the fly by slicing up to the current bar position.
Since candles is a numpy array, any indicator such as RSI, ATR, MACD, etc. can be implemented in the same manner.
Reference: Matching with External Data»
To use data other than OHLC (volume, fundamentals, etc.), load your own data and match it by timestamp with candles.time.
The simulator provides only OHLC + timestamps. Any other data can be freely brought in.
Security»
WebSocket Connection
- hawk-bt's WS server binds to
127.0.0.1:8787. It is not exposed to external networks. - Origin header validation is performed on connection; connections from origins not on the allow list are rejected with
403 Forbidden. - The Agent and browser must be running on the same machine.