Skip to main content
This example demonstrates the basic concepts of HftBacktest by creating a simple trading strategy. It covers printing the best bid and ask prices, working with market depth data, and submitting orders.

Printing the Best Bid and Best Ask

First, let’s start with a simple example that prints the best bid and best ask prices:
from numba import njit
import numpy as np

@njit
def print_bbo(hbt):
    # Iterating until hftbacktest reaches the end of data.
    # Elapses 60-sec every iteration.
    # Time unit is the same as data's timestamp's unit.
    # Timestamp of the sample data is in nanoseconds.
    while hbt.elapse(60 * 1e9) == 0:        
        # Gets the market depth for the first asset.
        depth = hbt.depth(0)

        # Prints the best bid and the best offer.
        print(
            'current_timestamp:', hbt.current_timestamp,
            ', best_bid:', np.round(depth.best_bid, 1),
            ', best_ask:', np.round(depth.best_ask, 1)
        )
    return True

Setting Up the Backtest Environment

Next, we need to configure the backtest environment with asset properties and market settings:
from hftbacktest import BacktestAsset, HashMapMarketDepthBacktest

asset = (
    BacktestAsset()
        .data(['usdm/btcusdt_20240809.npz'])
        .initial_snapshot('usdm/btcusdt_20240808_eod.npz')
        .linear_asset(1.0)
        .constant_latency(10_000_000, 10_000_000)
        .risk_adverse_queue_model()
        .no_partial_fill_exchange()
        .trading_value_fee_model(0.0002, 0.0007)
        .tick_size(0.1)
        .lot_size(0.001)
        .last_trades_capacity(0)
)

hbt = HashMapMarketDepthBacktest([asset])
You can see the best bid and best ask every 60 seconds. Since the price is a 32-bit float, there may be floating-point errors. In the example, for readability, the price is rounded based on the tick size.

Getting Market Depth

You can access market depth data beyond just the best bid and ask:
@njit
def print_3depth(hbt):
    while hbt.elapse(60 * 1e9) == 0:
        print('current_timestamp:', hbt.current_timestamp)

        depth = hbt.depth(0)

        # Iterate through bid and ask levels
        i = 0
        for tick_price in range(depth.best_ask_tick, depth.best_ask_tick + 100):
            qty = depth.ask_qty_at_tick(tick_price)
            if qty > 0:
                print('ask: ', qty, '@', np.round(tick_price * depth.tick_size, 1))
                i += 1
                if i == 3:
                    break

        i = 0
        for tick_price in range(depth.best_bid_tick, max(depth.best_bid_tick - 100, 0), -1):
            qty = depth.bid_qty_at_tick(tick_price)
            if qty > 0:
                print('bid: ', qty, '@', np.round(tick_price * depth.tick_size, 1))
                i += 1
                if i == 3:
                    break
    return True

Submitting Orders

Here’s how to submit and track orders:
from hftbacktest import LIMIT, GTC, NONE, NEW, FILLED, CANCELED, EXPIRED

@njit
def submit_order(hbt):
    is_order_submitted = False
    while hbt.elapse(30 * 1e9) == 0:
        depth = hbt.depth(0)
        
        if not is_order_submitted:
            # Submits a buy order at 300 ticks below the best bid
            order_id = 1
            order_price = depth.best_bid - 300 * depth.tick_size
            order_qty = 1
            time_in_force = GTC  # Good 'till cancel
            order_type = LIMIT
            hbt.submit_buy_order(0, order_id, order_price, order_qty, time_in_force, order_type, False)
            is_order_submitted = True
    return True

Key Concepts

  • Time Units: The timestamp unit is in nanoseconds for the sample data
  • Market Depth: Access detailed order book information using the depth API
  • Order Management: Submit, track, and cancel orders programmatically
  • Asset Configuration: Set up realistic trading parameters including fees, latency, and queue models
HftBacktest cannot be reused. After using the backtest, make sure to close it with hbt.close(). If you use the backtest after closing, it will crash.

Build docs developers (and LLMs) love