Getting Started

Printing the best bid and the best ask

[1]:
from numba import njit

import numpy as np

# numba.njit is strongly recommended for fast backtesting.
@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
[2]:
from hftbacktest import BacktestAsset, HashMapMarketDepthBacktest

asset = (
    BacktestAsset()
        # Sets the data to feed for this asset.
        #
        # Due to the vast size of tick-by-tick market depth and trade data,
        # loading the entire dataset into memory can be challenging,
        # particularly when backtesting across multiple days.
        # HftBacktest offers lazy loading support and is compatible with npy and preferably npz.
        #
        # For details on the normalized feed data, refer to the following documents.
        # * https://hftbacktest.readthedocs.io/en/latest/data.html
        # * https://hftbacktest.readthedocs.io/en/latest/tutorials/Data%20Preparation.html
        .data(['usdm/btcusdt_20240809.npz'])
        # Sets the initial snapshot (optional).
        .initial_snapshot('usdm/btcusdt_20240808_eod.npz')
        # Asset type:
        # * Linear
        # * Inverse.
        # 1.0 represents the contract size, which is the value of the asset per quoted price.
        .linear_asset(1.0)
        # HftBacktest provides two built-in latency models.
        # * constant_latency
        # * intp_order_latency
        # To implement your own latency model, please use Rust.
        #
        # Time unit is the same as data's timestamp's unit. Timestamp of the sample data is in nanoseconds.
        # Sets the order entry latency and response latency to 10ms.
        .constant_latency(10_000_000, 10_000_000)
        # HftBacktest provides several types of built-in queue position models.
        # Please find the details in the documents below.
        # https://hftbacktest.readthedocs.io/en/latest/tutorials/Probability%20Queue%20Models.html
        #
        # To implement your own queue position model, please use Rust.
        .risk_adverse_queue_model()
        # HftBacktest provides two built-in exchange models.
        # * no_partial_fill_exchange
        # * partial_fill_exchange
        # To implement your own exchange model, please use Rust.
        .no_partial_fill_exchange()
        # HftBacktest provides several built-in fee models.
        # * trading_value_fee_model
        # * trading_qty_fee_model
        # * flat_per_trade_fee_model
        #
        # 0.02% maker fee and 0.07% taker fee. If the fee is negative, it represents a rebate.
        # For example, -0.00005 represents a 0.005% rebate for the maker order.
        .trading_value_fee_model(0.0002, 0.0007)
        # Tick size of this asset: minimum price increasement
        .tick_size(0.1)
        # Lot size of this asset: minimum trading unit.
        .lot_size(0.001)
        # Sets the capacity of the vector that stores trades occurring in the market.
        # If you set the size, you need call `clear_last_trades` to clear the vector.
        # A value of 0 indicates that no market trades are stored. (Default)
        .last_trades_capacity(0)
)

# HftBacktest provides several types of built-in market depth implementations.
# HashMapMarketDepthBacktest constructs a Backtest using a HashMap-based market depth implementation.
# Another useful implementation is ROIVectorMarketDepth, which is utilized in ROIVectorMarketDepthBacktest.
# Please find the details in the document below.
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. Be careful when using it. In the example, for readability, the price is rounded based on the tick size.

[3]:
print_bbo(hbt)
current_timestamp: 1723161661500000000 , best_bid: 61594.1 , best_ask: 61594.2
current_timestamp: 1723161721500000000 , best_bid: 61576.5 , best_ask: 61576.6
current_timestamp: 1723161781500000000 , best_bid: 61629.6 , best_ask: 61629.7
current_timestamp: 1723161841500000000 , best_bid: 61621.5 , best_ask: 61621.6
current_timestamp: 1723161901500000000 , best_bid: 61583.9 , best_ask: 61584.0
[3]:
True

HftBacktest cannot be reused. Therefore, after using the backtest, make sure to close it. If you use the backtest after closing, it will crash.

[4]:
_ = hbt.close()

Feeding the data

When you possess adequate memory, preloading the data into memory and providing it as input will be more efficient than lazy-loading during repeated backtesting.

[5]:
btcusdt_20230809 = np.load('usdm/btcusdt_20240809.npz')['data']
btcusdt_20230808_eod = np.load('usdm/btcusdt_20240808_eod.npz')['data']

asset = (
    BacktestAsset()
        .data([btcusdt_20230809])
        .initial_snapshot(btcusdt_20230808_eod)
        .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)
)
[6]:
hbt = HashMapMarketDepthBacktest([asset])

print_bbo(hbt)

_ = hbt.close()
current_timestamp: 1723161661500000000 , best_bid: 61594.1 , best_ask: 61594.2
current_timestamp: 1723161721500000000 , best_bid: 61576.5 , best_ask: 61576.6
current_timestamp: 1723161781500000000 , best_bid: 61629.6 , best_ask: 61629.7
current_timestamp: 1723161841500000000 , best_bid: 61621.5 , best_ask: 61621.6
current_timestamp: 1723161901500000000 , best_bid: 61583.9 , best_ask: 61584.0

Getting the market depth

[7]:
@njit
def print_3depth(hbt):
    while hbt.elapse(60 * 1e9) == 0:
        print('current_timestamp:', hbt.current_timestamp)

        # Gets the market depth for the first asset, in the same order as when you created the backtest.
        depth = hbt.depth(0)

        # a key of bid_depth or ask_depth is price in ticks.
        # (integer) price_tick = price / tick_size
        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
[8]:
hbt = HashMapMarketDepthBacktest([asset])

print_3depth(hbt)

_ = hbt.close()
current_timestamp: 1723161661500000000
ask:  1.759 @ 61594.2
ask:  0.006 @ 61594.4
ask:  0.114 @ 61595.2
bid:  3.526 @ 61594.1
bid:  0.016 @ 61594.0
bid:  0.002 @ 61593.9
current_timestamp: 1723161721500000000
ask:  2.575 @ 61576.6
ask:  0.004 @ 61576.7
ask:  0.455 @ 61577.0
bid:  2.558 @ 61576.5
bid:  0.002 @ 61576.0
bid:  0.515 @ 61575.5
current_timestamp: 1723161781500000000
ask:  0.131 @ 61629.7
ask:  0.005 @ 61630.1
ask:  0.005 @ 61630.5
bid:  5.742 @ 61629.6
bid:  0.247 @ 61629.4
bid:  0.034 @ 61629.3
current_timestamp: 1723161841500000000
ask:  0.202 @ 61621.6
ask:  0.002 @ 61622.5
ask:  0.003 @ 61622.6
bid:  3.488 @ 61621.5
bid:  0.86 @ 61620.0
bid:  0.248 @ 61619.6
current_timestamp: 1723161901500000000
ask:  1.397 @ 61584.0
ask:  0.832 @ 61585.1
ask:  0.132 @ 61586.0
bid:  3.307 @ 61583.9
bid:  0.01 @ 61583.8
bid:  0.002 @ 61582.0

Submitting an order

[9]:
from hftbacktest import LIMIT, GTC, NONE, NEW, FILLED, CANCELED, EXPIRED

@njit
def print_orders(hbt):
    # You can access open orders and also closed orders via hbt.orders.
    # Gets the OrderDict for the first asset.
    orders = hbt.orders(0)

    # hbt.orders is a dictionary, but be aware that it does not support all dict methods, and its keys are order_id (int).
    order_values = orders.values()
    while order_values.has_next():
        order = order_values.get()

        order_status = ''
        if order.status == NONE:
            order_status = 'NONE' # Exchange hasn't received an order yet.
        elif order.status == NEW:
            order_status = 'NEW'
        elif order.status == FILLED:
            order_status = 'FILLED'
        elif order.status == CANCELED:
            order_status = 'CANCELED'
        elif order.status == EXPIRED:
            order_status = 'EXPIRED'

        order_req = ''
        if order.req == NONE:
            order_req = 'NONE'
        elif order.req == NEW:
            order_req = 'NEW'
        elif order.req == CANCELED:
            order_req = 'CANCEL'

        print(
            'current_timestamp:', hbt.current_timestamp,
             ', order_id:', order.order_id,
             ', order_price:', np.round(order.price, 1),
             ', order_qty:', order.qty,
             ', order_status:', order_status,
             ', order_req:', order_req
        )

@njit
def submit_order(hbt):
    is_order_submitted = False
    while hbt.elapse(30 * 1e9) == 0:
        # Prints open orders.
        print_orders(hbt)

        depth = hbt.depth(0)

        if not is_order_submitted:
            # Submits a buy order at 300 ticks below the best bid for the first asset.
            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
[10]:
hbt = HashMapMarketDepthBacktest([asset])

submit_order(hbt)

_ = hbt.close()
current_timestamp: 1723161661500000000 , order_id: 1 , order_price: 61643.8 , order_qty: 1.0 , order_status: FILLED , order_req: NONE
current_timestamp: 1723161691500000000 , order_id: 1 , order_price: 61643.8 , order_qty: 1.0 , order_status: FILLED , order_req: NONE
current_timestamp: 1723161721500000000 , order_id: 1 , order_price: 61643.8 , order_qty: 1.0 , order_status: FILLED , order_req: NONE
current_timestamp: 1723161751500000000 , order_id: 1 , order_price: 61643.8 , order_qty: 1.0 , order_status: FILLED , order_req: NONE
current_timestamp: 1723161781500000000 , order_id: 1 , order_price: 61643.8 , order_qty: 1.0 , order_status: FILLED , order_req: NONE
current_timestamp: 1723161811500000000 , order_id: 1 , order_price: 61643.8 , order_qty: 1.0 , order_status: FILLED , order_req: NONE
current_timestamp: 1723161841500000000 , order_id: 1 , order_price: 61643.8 , order_qty: 1.0 , order_status: FILLED , order_req: NONE
current_timestamp: 1723161871500000000 , order_id: 1 , order_price: 61643.8 , order_qty: 1.0 , order_status: FILLED , order_req: NONE
current_timestamp: 1723161901500000000 , order_id: 1 , order_price: 61643.8 , order_qty: 1.0 , order_status: FILLED , order_req: NONE

Clearing inactive orders (FILLED, CANCELED, EXPIRED)

[11]:
from hftbacktest import GTC

@njit
def clear_inactive_orders(hbt):
    is_order_submitted = False
    while hbt.elapse(30 * 1e9) == 0:
        print_orders(hbt)

        # Removes inactive(FILLED, CANCELED, EXPIRED) orders from hbt.orders for the first asset.
        hbt.clear_inactive_orders(0)

        depth = hbt.depth(0)

        if not is_order_submitted:
            order_id = 1
            order_price = depth.best_bid - 300 * depth.tick_size
            order_qty = 1
            time_in_force = GTC
            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
[12]:
hbt = HashMapMarketDepthBacktest([asset])

clear_inactive_orders(hbt)

_ = hbt.close()
current_timestamp: 1723161661500000000 , order_id: 1 , order_price: 61643.8 , order_qty: 1.0 , order_status: FILLED , order_req: NONE

Watching a order status - pending due to order latency

[13]:
from hftbacktest import GTC

@njit
def watch_pending(hbt):
    is_order_submitted = False
    # Elapses 0.01-sec every iteration.
    while hbt.elapse(0.01 * 1e9) == 0:
        print_orders(hbt)

        hbt.clear_inactive_orders(0)

        depth = hbt.depth(0)

        if not is_order_submitted:
            order_id = 1
            order_price = depth.best_bid - 300 * depth.tick_size
            order_qty = 1
            time_in_force = GTC
            order_type = LIMIT
            hbt.submit_buy_order(0, order_id, order_price, order_qty, time_in_force, order_type, False)
            is_order_submitted = True

        # Prevents too many prints
        orders = hbt.orders(0)
        order = orders.get(order_id)
        if order.status == NEW:
            return False
    return True

The order_status is None until the acceptance message is received.

[14]:
hbt = HashMapMarketDepthBacktest([asset])

watch_pending(hbt)

_ = hbt.close()
current_timestamp: 1723161601520000000 , order_id: 1 , order_price: 61629.7 , order_qty: 1.0 , order_status: NONE , order_req: NEW
current_timestamp: 1723161601530000000 , order_id: 1 , order_price: 61629.7 , order_qty: 1.0 , order_status: NEW , order_req: NONE

Waiting for an order response

[15]:
from hftbacktest import GTC

@njit
def wait_for_order_response(hbt):
    order_id = 0
    is_order_submitted = False
    while hbt.elapse(0.01 * 1e9) == 0:
        print_orders(hbt)

        hbt.clear_inactive_orders(0)

        # Prevents too many prints
        orders = hbt.orders(0)
        if order_id in orders:
            if orders.get(order_id).status == NEW:
                return False

        depth = hbt.depth(0)

        if not is_order_submitted:
            order_id = 1
            order_price = depth.best_bid
            order_qty = 1
            time_in_force = GTC
            order_type = LIMIT
            hbt.submit_buy_order(0, order_id, order_price, order_qty, time_in_force, order_type, False)
            # Waits for the order response for a given order id for the first asset.
            print('an order is submitted at', hbt.current_timestamp)

            # Timeout is set 1-second.
            hbt.wait_order_response(0, order_id, 1 * 1e9)
            print('an order response is received at', hbt.current_timestamp)
            is_order_submitted = True
    return True

Since the ConstantLatency model is used, the round-trip latency is exactly 200ms. Ideally, using historical order latency data collected from the live market is the best approach. However, if this data is not available, starting with artificially generated order latency based on feed latency is another option. We will explore this in the following examples.

[16]:
hbt = HashMapMarketDepthBacktest([asset])

wait_for_order_response(hbt)

_ = hbt.close()
an order is submitted at 1723161601510000000
an order response is received at 1723161601530000000
current_timestamp: 1723161601540000000 , order_id: 1 , order_price: 61659.7 , order_qty: 1.0 , order_status: NEW , order_req: NONE

Printing position, balance, fee, and equity

[17]:
@njit
def position(hbt):
    is_order_submitted = False
    while hbt.elapse(60 * 1e9) == 0:
        print_orders(hbt)

        hbt.clear_inactive_orders(0)

        # Prints position
        print(
            'current_timestamp:', hbt.current_timestamp,
            ', position:', hbt.position(0),
            ', balance:', hbt.state_values(0).balance,
            ', fee:', hbt.state_values(0).fee
        )

        depth = hbt.depth(0)

        if not is_order_submitted:
            order_id = 1
            order_price = depth.best_bid
            order_qty = 1
            time_in_force = GTC
            order_type = LIMIT
            hbt.submit_buy_order(0, order_id, order_price, order_qty, time_in_force, order_type, False)

            # Timeout is set 1-second.
            hbt.wait_order_response(0, order_id, 1e9)
            is_order_submitted = True
    return True
[18]:
hbt = HashMapMarketDepthBacktest([asset])

position(hbt)

_ = hbt.close()
current_timestamp: 1723161661500000000 , position: 0.0 , balance: 0.0 , fee: 0.0
current_timestamp: 1723161721520000000 , order_id: 1 , order_price: 61594.1 , order_qty: 1.0 , order_status: FILLED , order_req: NONE
current_timestamp: 1723161721520000000 , position: 1.0 , balance: -61594.100000000006 , fee: 12.318820000000002
current_timestamp: 1723161781520000000 , position: 1.0 , balance: -61594.100000000006 , fee: 12.318820000000002
current_timestamp: 1723161841520000000 , position: 1.0 , balance: -61594.100000000006 , fee: 12.318820000000002
current_timestamp: 1723161901520000000 , position: 1.0 , balance: -61594.100000000006 , fee: 12.318820000000002

Canceling an open order

[19]:
@njit
def submit_and_cancel_order(hbt):
    is_order_submitted = False
    while hbt.elapse(0.1 * 1e9) == 0:
        print_orders(hbt)

        hbt.clear_inactive_orders(0)

        # Cancels if there is an open order
        orders = hbt.orders(0)
        order_values = orders.values()
        while order_values.has_next():
            order = order_values.get()

            # an order is only cancellable if order status is NEW.
            # cancel request is negated if the order is already filled or filled before cancel request is processed.
            if order.cancellable:
                hbt.cancel(0, order.order_id, False)
                # You can see status still NEW and see req CANCEL.
                print_orders(hbt)
                # cancels request also has order entry/response latencies the same as submitting.
                hbt.wait_order_response(0, order.order_id, 1e9)

        if not is_order_submitted:
            depth = hbt.depth(0)

            order_id = 1
            order_price = depth.best_bid - 100 * depth.tick_size
            order_qty = 1
            time_in_force = GTC
            order_type = LIMIT
            hbt.submit_buy_order(0, order_id, order_price, order_qty, time_in_force, order_type, False)

            # Timeout is set 1-second.
            hbt.wait_order_response(0, order_id, 1e9)
            is_order_submitted = True
        else:
            if len(hbt.orders(0)) == 0:
                return False
    return True
[20]:
hbt = HashMapMarketDepthBacktest([asset])

submit_and_cancel_order(hbt)

_ = hbt.close()
current_timestamp: 1723161601720000000 , order_id: 1 , order_price: 61649.7 , order_qty: 1.0 , order_status: NEW , order_req: NONE
current_timestamp: 1723161601720000000 , order_id: 1 , order_price: 61649.7 , order_qty: 1.0 , order_status: NEW , order_req: CANCEL
current_timestamp: 1723161601840000000 , order_id: 1 , order_price: 61649.7 , order_qty: 1.0 , order_status: CANCELED , order_req: NONE

Market order

[21]:
from hftbacktest import MARKET

@njit
def print_orders_exec_price(hbt):
    orders = hbt.orders(0)
    order_values = orders.values()
    while order_values.has_next():
        order = order_values.get()

        order_status = ''
        if order.status == NONE:
            order_status = 'NONE'
        elif order.status == NEW:
            order_status = 'NEW'
        elif order.status == FILLED:
            order_status = 'FILLED'
        elif order.status == CANCELED:
            order_status = 'CANCELED'
        elif order.status == EXPIRED:
            order_status = 'EXPIRED'

        order_req = ''
        if order.req == NONE:
            order_req = 'NONE'
        elif order.req == NEW:
            order_req = 'NEW'
        elif order.req == CANCELED:
            order_req = 'CANCEL'

        print(
            'current_timestamp:', hbt.current_timestamp,
             ', order_id:', order.order_id,
             ', order_price:', np.round(order.price, 1),
             ', order_qty:', order.qty,
             ', order_status:', order_status,
             ', exec_price:', np.round(order.exec_price, 1)
        )

@njit
def market_order(hbt):
    is_order_submitted = False
    while hbt.elapse(60 * 1e9) == 0:
        print_orders(hbt)

        hbt.clear_inactive_orders(0)

        state_values = hbt.state_values(0)

        print(
            'current_timestamp:', hbt.current_timestamp,
             ', position:', hbt.position(0),
             ', balance:', state_values.balance,
             ', fee:', state_values.fee
        )

        if not is_order_submitted:
            depth = hbt.depth(0)

            order_id = 1
            # Sets an arbitrary price, which does not affect MARKET orders.
            order_price = depth.best_bid
            order_qty = 1
            time_in_force = GTC
            order_type = MARKET
            hbt.submit_sell_order(0, order_id, order_price, order_qty, time_in_force, order_type, False)
            hbt.wait_order_response(0, order_id, 1e9)
            # You can see the order immediately filled.
            # Also you can see the order executed at the best bid which is different from what it was submitted at.
            print('best_bid:', depth.best_bid)
            print_orders_exec_price(hbt)
            is_order_submitted = True
    return True
[22]:
hbt = HashMapMarketDepthBacktest([asset])

market_order(hbt)

_ = hbt.close()
current_timestamp: 1723161661500000000 , position: 0.0 , balance: 0.0 , fee: 0.0
best_bid: 61594.100000000006
current_timestamp: 1723161661520000000 , order_id: 1 , order_price: 61594.1 , order_qty: 1.0 , order_status: FILLED , exec_price: 61594.1
current_timestamp: 1723161721520000000 , order_id: 1 , order_price: 61594.1 , order_qty: 1.0 , order_status: FILLED , order_req: NONE
current_timestamp: 1723161721520000000 , position: -1.0 , balance: 61594.100000000006 , fee: 43.11587
current_timestamp: 1723161781520000000 , position: -1.0 , balance: 61594.100000000006 , fee: 43.11587
current_timestamp: 1723161841520000000 , position: -1.0 , balance: 61594.100000000006 , fee: 43.11587
current_timestamp: 1723161901520000000 , position: -1.0 , balance: 61594.100000000006 , fee: 43.11587

GTX, Post-Only order

[23]:
from hftbacktest import GTX

@njit
def submit_gtx(hbt):
    is_order_submitted = False
    while hbt.elapse(60 * 1e9) == 0:
        print_orders(hbt)

        hbt.clear_inactive_orders(0)

        state_values = hbt.state_values(0)

        print(
            'current_timestamp:', hbt.current_timestamp,
             ', position:', hbt.position(0),
             ', balance:', state_values.balance,
             ', fee:', state_values.fee
        )

        if not is_order_submitted:
            depth = hbt.depth(0)

            order_id = 1
            # Sets a deep price in the opposite side and it will be rejected by GTX.
            order_price = depth.best_bid - 100 * depth.tick_size
            order_qty = 1
            time_in_force = GTX
            order_type = LIMIT
            hbt.submit_sell_order(0, order_id, order_price, order_qty, time_in_force, order_type, False)
            hbt.wait_order_response(0, order_id, 1e9)
            is_order_submitted = True
    return True
[24]:
hbt = HashMapMarketDepthBacktest([asset])

submit_gtx(hbt)

_ = hbt.close()
current_timestamp: 1723161661500000000 , position: 0.0 , balance: 0.0 , fee: 0.0
current_timestamp: 1723161721520000000 , order_id: 1 , order_price: 61584.1 , order_qty: 1.0 , order_status: EXPIRED , order_req: NONE
current_timestamp: 1723161721520000000 , position: 0.0 , balance: 0.0 , fee: 0.0
current_timestamp: 1723161781520000000 , position: 0.0 , balance: 0.0 , fee: 0.0
current_timestamp: 1723161841520000000 , position: 0.0 , balance: 0.0 , fee: 0.0
current_timestamp: 1723161901520000000 , position: 0.0 , balance: 0.0 , fee: 0.0

Plotting BBO

[25]:
@njit
def plot_bbo(hbt, local_timestamp, best_bid, best_ask):
    while hbt.elapse(1 * 1e9) == 0:
        # Records data points
        local_timestamp.append(hbt.current_timestamp)

        depth = hbt.depth(0)

        best_bid.append(depth.best_bid)
        best_ask.append(depth.best_ask)
    return True
[26]:
# Uses Numba list for njit.
from numba.typed import List
from numba import int64, float64

import polars as pl

local_timestamp = List.empty_list(int64, allocated=10000)
best_bid = List.empty_list(float64, allocated=10000)
best_ask = List.empty_list(float64, allocated=10000)

hbt = HashMapMarketDepthBacktest([asset])

plot_bbo(hbt, local_timestamp, best_bid, best_ask)

hbt.close()

df = pl.DataFrame({'timestamp': local_timestamp, 'best_bid': best_bid, 'best_ask': best_ask})
df = df.with_columns(
    pl.from_epoch('timestamp', time_unit='ns')
)

df.plot(x='timestamp')
[26]:

Printing stats

[27]:
@njit
def submit_order_stats(hbt, recorder):
    buy_order_id = 1
    sell_order_id = 2
    half_spread = 5 * hbt.depth(0).tick_size

    while hbt.elapse(1 * 1e9) == 0:
        hbt.clear_inactive_orders(0)

        depth = hbt.depth(0)

        mid_price = (depth.best_bid + depth.best_ask) / 2.0

        if buy_order_id not in hbt.orders(0):
            order_price = round((mid_price - half_spread) / depth.tick_size) * depth.tick_size
            order_qty = 1
            time_in_force = GTX
            order_type = LIMIT
            hbt.submit_buy_order(0, buy_order_id, order_price, order_qty, time_in_force, order_type, False)
        else:
            hbt.cancel(0, buy_order_id, False)

        if sell_order_id not in hbt.orders(0):
            order_price = round((mid_price + half_spread) / depth.tick_size) * depth.tick_size
            order_qty = 1
            time_in_force = GTX
            order_type = LIMIT
            hbt.submit_sell_order(0, sell_order_id, order_price, order_qty, time_in_force, order_type, False)
        else:
            hbt.cancel(0, sell_order_id, False)

        recorder.record(hbt)
    return True
[28]:
from hftbacktest import Recorder

hbt = HashMapMarketDepthBacktest([asset])

recorder = Recorder(
    # The number of assets
    hbt.num_assets,
    # The buffer size for records
    1000000
)

submit_order_stats(hbt, recorder.recorder)

_ = hbt.close()

You can get recorded states using the get method with the asset number.

[29]:
recorder.get(0)
[29]:
array([(1723161602500000000, 61659.85,  0.,  0.000000e+00,    0.     ,   0,   0.,        0. ),
       (1723161603500000000, 61659.95,  1., -6.165940e+04,   12.33188,   1,   1.,    61659.4),
       (1723161604500000000, 61670.85,  1., -6.165940e+04,   12.33188,   1,   1.,    61659.4),
       (1723161605500000000, 61692.45,  0.,  1.200000e+01,   24.66616,   2,   2.,   123330.8),
       (1723161606500000000, 61693.95,  0.,  1.300000e+01,   49.34312,   4,   4.,   246715.6),
       (1723161607500000000, 61695.45, -1.,  6.170740e+04,   61.682  ,   5,   5.,   308410. ),
       (1723161608500000000, 61709.95, -2.,  1.234033e+05,   74.02118,   6,   6.,   370105.9),
       (1723161609500000000, 61707.35, -1.,  6.169390e+04,   86.36306,   7,   7.,   431815.3),
       (1723161610500000000, 61715.85, -1.,  6.169390e+04,   86.36306,   7,   7.,   431815.3),
       (1723161611500000000, 61711.85, -2.,  1.234103e+05,   98.70634,   8,   8.,   493531.7),
       (1723161612500000000, 61713.95, -3.,  1.851227e+05,  111.04882,   9,   9.,   555244.1),
       (1723161613500000000, 61706.15, -4.,  2.468371e+05,  123.3917 ,  10,  10.,   616958.5),
       (1723161614500000000, 61708.25, -5.,  3.085437e+05,  135.73302,  11,  11.,   678665.1),
       (1723161615500000000, 61699.75, -6.,  3.702525e+05,  148.07478,  12,  12.,   740373.9),
       (1723161616500000000, 61700.95, -7.,  4.319527e+05,  160.41482,  13,  13.,   802074.1),
       (1723161617500000000, 61698.05, -7.,  4.319527e+05,  160.41482,  13,  13.,   802074.1),
       (1723161618500000000, 61706.95, -7.,  4.319527e+05,  160.41482,  13,  13.,   802074.1),
       (1723161619500000000, 61695.85, -7.,  4.319527e+05,  160.41482,  13,  13.,   802074.1),
       (1723161620500000000, 61713.45, -7.,  4.319527e+05,  160.41482,  13,  13.,   802074.1),
       (1723161621500000000, 61707.65, -7.,  4.319527e+05,  160.41482,  13,  13.,   802074.1),
       (1723161622500000000, 61713.45, -7.,  4.319527e+05,  160.41482,  13,  13.,   802074.1),
       (1723161623500000000, 61704.05, -6.,  3.702455e+05,  172.75626,  14,  14.,   863781.3),
       (1723161624500000000, 61702.45, -5.,  3.085419e+05,  185.09698,  15,  15.,   925484.9),
       (1723161625500000000, 61704.65, -6.,  3.702448e+05,  197.43756,  16,  16.,   987187.8),
       (1723161626500000000, 61704.65, -6.,  3.702448e+05,  197.43756,  16,  16.,   987187.8),
       (1723161627500000000, 61695.35, -5.,  3.085406e+05,  209.7784 ,  17,  17.,  1048892. ),
       (1723161628500000000, 61693.75, -4.,  2.468458e+05,  222.11736,  18,  18.,  1110586.8),
       (1723161629500000000, 61693.75, -4.,  2.468458e+05,  222.11736,  18,  18.,  1110586.8),
       (1723161630500000000, 61682.35, -4.,  2.468458e+05,  222.11736,  18,  18.,  1110586.8),
       (1723161631500000000, 61673.85, -3.,  1.851640e+05,  234.45372,  19,  19.,  1172268.6),
       (1723161632500000000, 61666.05, -2.,  1.234906e+05,  246.7884 ,  20,  20.,  1233942. ),
       (1723161633500000000, 61671.05, -2.,  1.234906e+05,  246.7884 ,  20,  20.,  1233942. ),
       (1723161634500000000, 61673.75, -3.,  1.851622e+05,  259.12272,  21,  21.,  1295613.6),
       (1723161635500000000, 61673.75, -3.,  1.851622e+05,  259.12272,  21,  21.,  1295613.6),
       (1723161636500000000, 61666.05, -3.,  1.851622e+05,  259.12272,  21,  21.,  1295613.6),
       (1723161637500000000, 61670.45, -4.,  2.468288e+05,  271.45604,  22,  22.,  1357280.2),
       (1723161638500000000, 61664.05, -4.,  2.468288e+05,  271.45604,  22,  22.,  1357280.2),
       (1723161639500000000, 61649.05, -3.,  1.851652e+05,  283.78876,  23,  23.,  1418943.8),
       (1723161640500000000, 61645.05, -3.,  1.851652e+05,  283.78876,  23,  23.,  1418943.8),
       (1723161641500000000, 61640.05, -2.,  1.235206e+05,  296.11768,  24,  24.,  1480588.4),
       (1723161642500000000, 61638.45, -1.,  6.188100e+04,  308.4456 ,  25,  25.,  1542228. ),
       (1723161643500000000, 61636.05,  0.,  2.431000e+02,  320.77318,  26,  26.,  1603865.9),
       (1723161644500000000, 61641.95, -1.,  6.187970e+04,  333.1005 ,  27,  27.,  1665502.5),
       (1723161645500000000, 61641.95, -1.,  6.187970e+04,  333.1005 ,  27,  27.,  1665502.5),
       (1723161646500000000, 61644.35, -1.,  6.187970e+04,  333.1005 ,  27,  27.,  1665502.5),
       (1723161647500000000, 61636.45, -1.,  6.187970e+04,  333.1005 ,  27,  27.,  1665502.5),
       (1723161648500000000, 61630.05,  0.,  2.438000e+02,  345.42768,  28,  28.,  1727138.4),
       (1723161649500000000, 61630.05,  0.,  2.438000e+02,  345.42768,  28,  28.,  1727138.4),
       (1723161650500000000, 61631.65,  0.,  2.438000e+02,  345.42768,  28,  28.,  1727138.4),
       (1723161651500000000, 61639.05, -1.,  6.187600e+04,  357.75412,  29,  29.,  1788770.6),
       (1723161652500000000, 61632.05, -1.,  6.187600e+04,  357.75412,  29,  29.,  1788770.6),
       (1723161653500000000, 61633.95, -1.,  6.187600e+04,  357.75412,  29,  29.,  1788770.6),
       (1723161654500000000, 61632.05, -2.,  1.235104e+05,  370.081  ,  30,  30.,  1850405. ),
       (1723161655500000000, 61604.05, -1.,  6.187880e+04,  382.40732,  31,  31.,  1912036.6),
       (1723161656500000000, 61604.05, -1.,  6.187880e+04,  382.40732,  31,  31.,  1912036.6),
       (1723161657500000000, 61607.05, -1.,  6.187880e+04,  382.40732,  31,  31.,  1912036.6),
       (1723161658500000000, 61603.15,  0.,  2.722000e+02,  394.72864,  32,  32.,  1973643.2),
       (1723161659500000000, 61601.15,  1., -6.133040e+04,  407.04916,  33,  33.,  2035245.8),
       (1723161660500000000, 61595.35,  2., -1.229310e+05,  419.36928,  34,  34.,  2096846.4),
       (1723161661500000000, 61594.15,  3., -1.845258e+05,  431.68824,  35,  35.,  2158441.2),
       (1723161662500000000, 61578.15,  4., -2.461194e+05,  444.00696,  36,  36.,  2220034.8),
       (1723161663500000000, 61565.25,  5., -3.076970e+05,  456.32248,  37,  37.,  2281612.4),
       (1723161664500000000, 61563.65,  5., -3.076960e+05,  480.9486 ,  39,  39.,  2404743. ),
       (1723161665500000000, 61555.05,  6., -3.692592e+05,  493.26124,  40,  40.,  2466306.2),
       (1723161666500000000, 61530.85,  7., -4.308138e+05,  505.57216,  41,  41.,  2527860.8),
       (1723161667500000000, 61522.25,  8., -4.923442e+05,  517.87824,  42,  42.,  2589391.2),
       (1723161668500000000, 61543.  ,  7., -4.308214e+05,  530.1828 ,  43,  43.,  2650914. ),
       (1723161669500000000, 61528.05,  7., -4.308214e+05,  530.1828 ,  43,  43.,  2650914. ),
       (1723161670500000000, 61539.85,  8., -4.923490e+05,  542.48832,  44,  44.,  2712441.6),
       (1723161671500000000, 61524.15,  9., -5.538884e+05,  554.7962 ,  45,  45.,  2773981. ),
       (1723161672500000000, 61524.25,  9., -5.538884e+05,  554.7962 ,  45,  45.,  2773981. ),
       (1723161673500000000, 61535.95,  8., -4.923636e+05,  567.10116,  46,  46.,  2835505.8),
       (1723161674500000000, 61531.45,  9., -5.538990e+05,  579.40824,  47,  47.,  2897041.2),
       (1723161675500000000, 61538.85,  9., -5.538990e+05,  579.40824,  47,  47.,  2897041.2),
       (1723161676500000000, 61536.95,  9., -5.538990e+05,  579.40824,  47,  47.,  2897041.2),
       (1723161677500000000, 61538.85,  9., -5.538990e+05,  579.40824,  47,  47.,  2897041.2),
       (1723161678500000000, 61534.75,  9., -5.538990e+05,  579.40824,  47,  47.,  2897041.2),
       (1723161679500000000, 61538.85,  9., -5.538990e+05,  579.40824,  47,  47.,  2897041.2),
       (1723161680500000000, 61538.05,  9., -5.538990e+05,  579.40824,  47,  47.,  2897041.2),
       (1723161681500000000, 61549.25,  9., -5.538990e+05,  579.40824,  47,  47.,  2897041.2),
       (1723161682500000000, 61552.45,  8., -4.923492e+05,  591.7182 ,  48,  48.,  2958591. ),
       (1723161683500000000, 61552.45,  8., -4.923492e+05,  591.7182 ,  48,  48.,  2958591. ),
       (1723161684500000000, 61552.45,  8., -4.923492e+05,  591.7182 ,  48,  48.,  2958591. ),
       (1723161685500000000, 61565.95,  7., -4.307963e+05,  604.02878,  49,  49.,  3020143.9),
       (1723161686500000000, 61574.45,  6., -3.692299e+05,  616.34206,  50,  50.,  3081710.3),
       (1723161687500000000, 61587.55,  6., -3.692299e+05,  616.34206,  50,  50.,  3081710.3),
       (1723161688500000000, 61592.95,  5., -3.076419e+05,  628.65966,  51,  51.,  3143298.3),
       (1723161689500000000, 61592.95,  5., -3.076419e+05,  628.65966,  51,  51.,  3143298.3),
       (1723161690500000000, 61594.15,  5., -3.076419e+05,  628.65966,  51,  51.,  3143298.3),
       (1723161691500000000, 61598.95,  4., -2.460473e+05,  640.97858,  52,  52.,  3204892.9),
       (1723161692500000000, 61593.05,  3., -1.844479e+05,  653.29846,  53,  53.,  3266492.3),
       (1723161693500000000, 61582.55,  3., -1.844479e+05,  653.29846,  53,  53.,  3266492.3),
       (1723161694500000000, 61582.55,  4., -2.460299e+05,  665.61486,  54,  54.,  3328074.3),
       (1723161695500000000, 61582.55,  4., -2.460299e+05,  665.61486,  54,  54.,  3328074.3),
       (1723161696500000000, 61587.15,  4., -2.460299e+05,  665.61486,  54,  54.,  3328074.3),
       (1723161697500000000, 61587.15,  4., -2.460299e+05,  665.61486,  54,  54.,  3328074.3),
       (1723161698500000000, 61588.75,  4., -2.460299e+05,  665.61486,  54,  54.,  3328074.3),
       (1723161699500000000, 61586.75,  4., -2.460289e+05,  690.25034,  56,  56.,  3451251.7),
       (1723161700500000000, 61582.05,  5., -3.076151e+05,  702.56758,  57,  57.,  3512837.9),
       (1723161701500000000, 61572.05,  6., -3.691967e+05,  714.8839 ,  58,  58.,  3574419.5),
       (1723161702500000000, 61587.45,  5., -3.076241e+05,  727.19842,  59,  59.,  3635992.1),
       (1723161703500000000, 61577.95,  5., -3.076241e+05,  727.19842,  59,  59.,  3635992.1),
       (1723161704500000000, 61582.05,  5., -3.076241e+05,  727.19842,  59,  59.,  3635992.1),
       (1723161705500000000, 61572.05,  5., -3.076189e+05,  751.83042,  61,  61.,  3759152.1),
       (1723161706500000000, 61574.05,  4., -2.460463e+05,  764.14494,  62,  62.,  3820724.7),
       (1723161707500000000, 61574.05,  4., -2.460463e+05,  764.14494,  62,  62.,  3820724.7),
       (1723161708500000000, 61576.05,  3., -1.844717e+05,  776.45986,  63,  63.,  3882299.3),
       (1723161709500000000, 61577.55,  2., -1.228951e+05,  788.77518,  64,  64.,  3943875.9),
       (1723161710500000000, 61581.95,  1., -6.131710e+04,  801.09078,  65,  65.,  4005453.9),
       (1723161711500000000, 61565.65,  1., -6.131710e+04,  801.09078,  65,  65.,  4005453.9),
       (1723161712500000000, 61561.15,  2., -1.228823e+05,  813.40382,  66,  66.,  4067019.1),
       (1723161713500000000, 61570.45,  2., -1.228813e+05,  838.02826,  68,  68.,  4190141.3),
       (1723161714500000000, 61572.45,  1., -6.131040e+04,  850.34244,  69,  69.,  4251712.2),
       (1723161715500000000, 61565.65,  1., -6.131040e+04,  850.34244,  69,  69.,  4251712.2),
       (1723161716500000000, 61561.95,  2., -1.228756e+05,  862.65548,  70,  70.,  4313277.4),
       (1723161717500000000, 61557.05,  3., -1.844370e+05,  874.96776,  71,  71.,  4374838.8),
       (1723161718500000000, 61561.95,  3., -1.844370e+05,  874.96776,  71,  71.,  4374838.8),
       (1723161719500000000, 61568.05,  2., -1.228746e+05,  887.28024,  72,  72.,  4436401.2),
       (1723161720500000000, 61576.55,  1., -6.130600e+04,  899.59396,  73,  73.,  4497969.8),
       (1723161721500000000, 61576.55,  1., -6.130600e+04,  899.59396,  73,  73.,  4497969.8),
       (1723161722500000000, 61589.95,  1., -6.130600e+04,  899.59396,  73,  73.,  4497969.8),
       (1723161723500000000, 61593.95,  0.,  2.844000e+02,  911.91204,  74,  74.,  4559560.2),
       (1723161724500000000, 61615.15, -1.,  6.187880e+04,  924.23092,  75,  75.,  4621154.6),
       (1723161725500000000, 61615.15, -1.,  6.187880e+04,  924.23092,  75,  75.,  4621154.6),
       (1723161726500000000, 61615.15, -1.,  6.187880e+04,  924.23092,  75,  75.,  4621154.6),
       (1723161727500000000, 61617.05, -2.,  1.234944e+05,  936.55404,  76,  76.,  4682770.2),
       (1723161728500000000, 61618.15, -3.,  1.851120e+05,  948.87756,  77,  77.,  4744387.8),
       (1723161729500000000, 61612.55, -3.,  1.851120e+05,  948.87756,  77,  77.,  4744387.8),
       (1723161730500000000, 61609.95, -2.,  1.235000e+05,  961.19996,  78,  78.,  4805999.8),
       (1723161731500000000, 61607.95, -1.,  6.189060e+04,  973.52184,  79,  79.,  4867609.2),
       (1723161732500000000, 61608.95, -1.,  6.189060e+04,  973.52184,  79,  79.,  4867609.2),
       (1723161733500000000, 61606.05, -1.,  6.189060e+04,  973.52184,  79,  79.,  4867609.2),
       (1723161734500000000, 61608.45, -1.,  6.189060e+04,  973.52184,  79,  79.,  4867609.2),
       (1723161735500000000, 61615.95, -2.,  1.234995e+05,  985.84362,  80,  80.,  4929218.1),
       (1723161736500000000, 61618.15, -3.,  1.851159e+05,  998.1669 ,  81,  81.,  4990834.5),
       (1723161737500000000, 61605.55, -3.,  1.851159e+05,  998.1669 ,  81,  81.,  4990834.5),
       (1723161738500000000, 61613.85, -3.,  1.851159e+05,  998.1669 ,  81,  81.,  4990834.5),
       (1723161739500000000, 61619.95, -4.,  2.467303e+05, 1010.48978,  82,  82.,  5052448.9),
       (1723161740500000000, 61636.65, -4.,  2.467303e+05, 1010.48978,  82,  82.,  5052448.9),
       (1723161741500000000, 61649.75, -5.,  3.083675e+05, 1022.81722,  83,  83.,  5114086.1),
       (1723161742500000000, 61653.45, -6.,  3.700177e+05, 1035.14726,  84,  84.,  5175736.3),
       (1723161743500000000, 61668.55, -7.,  4.316716e+05, 1047.47804,  85,  85.,  5237390.2),
       (1723161744500000000, 61668.55, -7.,  4.316716e+05, 1047.47804,  85,  85.,  5237390.2),
       (1723161745500000000, 61673.45, -6.,  3.700036e+05, 1059.81164,  86,  86.,  5299058.2),
       (1723161746500000000, 61675.55, -7.,  4.316775e+05, 1072.14642,  87,  87.,  5360732.1),
       (1723161747500000000, 61671.35, -8.,  4.933535e+05, 1084.48162,  88,  88.,  5422408.1),
       (1723161748500000000, 61656.75, -7.,  4.316827e+05, 1096.81578,  89,  89.,  5484078.9),
       (1723161749500000000, 61660.05, -7.,  4.316827e+05, 1096.81578,  89,  89.,  5484078.9),
       (1723161750500000000, 61662.05, -8.,  4.933433e+05, 1109.1479 ,  90,  90.,  5545739.5),
       (1723161751500000000, 61652.05, -7.,  4.316817e+05, 1121.48022,  91,  91.,  5607401.1),
       (1723161752500000000, 61673.45, -7.,  4.316817e+05, 1121.48022,  91,  91.,  5607401.1),
       (1723161753500000000, 61680.65, -8.,  4.933556e+05, 1133.815  ,  92,  92.,  5669075. ),
       (1723161754500000000, 61672.45, -7.,  4.316754e+05, 1146.15104,  93,  93.,  5730755.2),
       (1723161755500000000, 61659.95, -6.,  3.700035e+05, 1158.48542,  94,  94.,  5792427.1),
       (1723161756500000000, 61661.25, -7.,  4.316639e+05, 1170.8175 ,  95,  95.,  5854087.5),
       (1723161757500000000, 61654.25, -7.,  4.316639e+05, 1170.8175 ,  95,  95.,  5854087.5),
       (1723161758500000000, 61650.05, -6.,  3.700101e+05, 1183.14826,  96,  96.,  5915741.3),
       (1723161759500000000, 61650.05, -6.,  3.700101e+05, 1183.14826,  96,  96.,  5915741.3),
       (1723161760500000000, 61654.25, -6.,  3.700101e+05, 1183.14826,  96,  96.,  5915741.3),
       (1723161761500000000, 61652.65, -5.,  3.083563e+05, 1195.47902,  97,  97.,  5977395.1),
       (1723161762500000000, 61663.95, -5.,  3.083563e+05, 1195.47902,  97,  97.,  5977395.1),
       (1723161763500000000, 61656.05, -5.,  3.083563e+05, 1195.47902,  97,  97.,  5977395.1),
       (1723161764500000000, 61656.05, -6.,  3.700129e+05, 1207.81034,  98,  98.,  6039051.7),
       (1723161765500000000, 61626.35, -6.,  3.700129e+05, 1207.81034,  98,  98.,  6039051.7),
       (1723161766500000000, 61629.85, -6.,  3.700129e+05, 1207.81034,  98,  98.,  6039051.7),
       (1723161767500000000, 61629.85, -6.,  3.700129e+05, 1207.81034,  98,  98.,  6039051.7),
       (1723161768500000000, 61633.05, -6.,  3.700129e+05, 1207.81034,  98,  98.,  6039051.7),
       (1723161769500000000, 61645.45, -7.,  4.316465e+05, 1220.13706,  99,  99.,  6100685.3),
       (1723161770500000000, 61645.45, -7.,  4.316465e+05, 1220.13706,  99,  99.,  6100685.3),
       (1723161771500000000, 61649.75, -7.,  4.316465e+05, 1220.13706,  99,  99.,  6100685.3),
       (1723161772500000000, 61640.85, -7.,  4.316465e+05, 1220.13706,  99,  99.,  6100685.3),
       (1723161773500000000, 61642.05, -7.,  4.316465e+05, 1220.13706,  99,  99.,  6100685.3),
       (1723161774500000000, 61629.85, -7.,  4.316465e+05, 1220.13706,  99,  99.,  6100685.3),
       (1723161775500000000, 61629.75, -7.,  4.316465e+05, 1220.13706,  99,  99.,  6100685.3),
       (1723161776500000000, 61635.25, -8.,  4.932767e+05, 1232.4631 , 100, 100.,  6162315.5),
       (1723161777500000000, 61618.75, -7.,  4.316419e+05, 1244.79006, 101, 101.,  6223950.3),
       (1723161778500000000, 61615.75, -6.,  3.700237e+05, 1257.1137 , 102, 102.,  6285568.5),
       (1723161779500000000, 61602.7 , -5.,  3.084085e+05, 1269.43674, 103, 103.,  6347183.7),
       (1723161780500000000, 61609.75, -4.,  2.468063e+05, 1281.75718, 104, 104.,  6408785.9),
       (1723161781500000000, 61629.65, -5.,  3.084165e+05, 1294.07922, 105, 105.,  6470396.1),
       (1723161782500000000, 61634.15, -6.,  3.700467e+05, 1306.40526, 106, 106.,  6532026.3),
       (1723161783500000000, 61631.95, -5.,  3.084131e+05, 1318.73198, 107, 107.,  6593659.9),
       (1723161784500000000, 61625.55, -4.,  2.467817e+05, 1331.05826, 108, 108.,  6655291.3),
       (1723161785500000000, 61617.05, -3.,  1.851567e+05, 1343.38326, 109, 109.,  6716916.3),
       (1723161786500000000, 61620.05, -2.,  1.235401e+05, 1355.70658, 110, 110.,  6778532.9),
       (1723161787500000000, 61620.05, -2.,  1.235401e+05, 1355.70658, 110, 110.,  6778532.9),
       (1723161788500000000, 61620.05, -2.,  1.235401e+05, 1355.70658, 110, 110.,  6778532.9),
       (1723161789500000000, 61617.05, -1.,  6.192050e+04, 1368.0305 , 111, 111.,  6840152.5),
       (1723161790500000000, 61616.15,  0.,  3.039000e+02, 1380.35382, 112, 112.,  6901769.1),
       (1723161791500000000, 61616.15,  0.,  3.039000e+02, 1380.35382, 112, 112.,  6901769.1),
       (1723161792500000000, 61618.05,  0.,  3.039000e+02, 1380.35382, 112, 112.,  6901769.1),
       (1723161793500000000, 61642.05, -1.,  6.192250e+04, 1392.67754, 113, 113.,  6963387.7),
       (1723161794500000000, 61649.95, -2.,  1.235651e+05, 1405.00606, 114, 114.,  7025030.3),
       (1723161795500000000, 61666.45, -3.,  1.852155e+05, 1417.33614, 115, 115.,  7086680.7),
       (1723161796500000000, 61658.05, -3.,  1.852155e+05, 1417.33614, 115, 115.,  7086680.7),
       (1723161797500000000, 61648.45, -2.,  1.235579e+05, 1429.66766, 116, 116.,  7148338.3),
       (1723161798500000000, 61642.05, -2.,  1.235589e+05, 1454.32702, 118, 118.,  7271635.1),
       (1723161799500000000, 61638.85, -1.,  6.191730e+04, 1466.65534, 119, 119.,  7333276.7),
       (1723161800500000000, 61631.95,  0.,  2.789000e+02, 1478.98302, 120, 120.,  7394915.1),
       (1723161801500000000, 61623.05,  1., -6.135250e+04, 1491.3093 , 121, 121.,  7456546.5),
       (1723161802500000000, 61626.65,  1., -6.135250e+04, 1491.3093 , 121, 121.,  7456546.5),
       (1723161803500000000, 61625.05,  1., -6.135250e+04, 1491.3093 , 121, 121.,  7456546.5),
       (1723161804500000000, 61612.05,  2., -1.229771e+05, 1503.63422, 122, 122.,  7518171.1),
       (1723161805500000000, 61618.05,  1., -6.136450e+04, 1515.95674, 123, 123.,  7579783.7),
       (1723161806500000000, 61616.15,  1., -6.136450e+04, 1515.95674, 123, 123.,  7579783.7),
       (1723161807500000000, 61616.15,  1., -6.136450e+04, 1515.95674, 123, 123.,  7579783.7),
       (1723161808500000000, 61602.45,  1., -6.136450e+04, 1515.95674, 123, 123.,  7579783.7),
       (1723161809500000000, 61592.05,  2., -1.229664e+05, 1528.27712, 124, 124.,  7641385.6),
       (1723161810500000000, 61580.25,  3., -1.845580e+05, 1540.59544, 125, 125.,  7702977.2),
       (1723161811500000000, 61580.25,  3., -1.845580e+05, 1540.59544, 125, 125.,  7702977.2),
       (1723161812500000000, 61586.25,  2., -1.229772e+05, 1552.9116 , 126, 126.,  7764558. ),
       (1723161813500000000, 61594.45,  1., -6.139040e+04, 1565.22896, 127, 127.,  7826144.8),
       (1723161814500000000, 61606.85,  0.,  2.045000e+02, 1577.54794, 128, 128.,  7887739.7),
       (1723161815500000000, 61630.35, -1.,  6.181190e+04, 1589.86942, 129, 129.,  7949347.1),
       (1723161816500000000, 61638.05, -2.,  1.234427e+05, 1602.19558, 130, 130.,  8010977.9),
       (1723161817500000000, 61626.25, -2.,  1.234427e+05, 1602.19558, 130, 130.,  8010977.9),
       (1723161818500000000, 61626.25, -2.,  1.234427e+05, 1602.19558, 130, 130.,  8010977.9),
       (1723161819500000000, 61613.65, -2.,  1.234427e+05, 1602.19558, 130, 130.,  8010977.9),
       (1723161820500000000, 61608.15, -1.,  6.182950e+04, 1614.51822, 131, 131.,  8072591.1),
       (1723161821500000000, 61624.65, -2.,  1.234381e+05, 1626.83994, 132, 132.,  8134199.7),
       (1723161822500000000, 61624.65, -2.,  1.234381e+05, 1626.83994, 132, 132.,  8134199.7),
       (1723161823500000000, 61624.65, -2.,  1.234381e+05, 1626.83994, 132, 132.,  8134199.7),
       (1723161824500000000, 61624.65, -2.,  1.234381e+05, 1626.83994, 132, 132.,  8134199.7),
       (1723161825500000000, 61622.55, -1.,  6.181390e+04, 1639.16478, 133, 133.,  8195823.9),
       (1723161826500000000, 61622.55, -1.,  6.181390e+04, 1639.16478, 133, 133.,  8195823.9),
       (1723161827500000000, 61621.65, -1.,  6.181390e+04, 1639.16478, 133, 133.,  8195823.9),
       (1723161828500000000, 61615.95,  0.,  1.927000e+02, 1651.48902, 134, 134.,  8257445.1),
       (1723161829500000000, 61621.55,  1., -6.142270e+04, 1663.8121 , 135, 135.,  8319060.5),
       (1723161830500000000, 61621.55,  1., -6.142270e+04, 1663.8121 , 135, 135.,  8319060.5),
       (1723161831500000000, 61614.05,  1., -6.142270e+04, 1663.8121 , 135, 135.,  8319060.5),
       (1723161832500000000, 61611.55,  2., -1.230363e+05, 1676.13482, 136, 136.,  8380674.1),
       (1723161833500000000, 61620.05,  2., -1.230363e+05, 1676.13482, 136, 136.,  8380674.1),
       (1723161834500000000, 61622.55,  1., -6.141570e+04, 1688.45894, 137, 137.,  8442294.7),
       (1723161835500000000, 61621.55,  1., -6.141470e+04, 1713.10794, 139, 139.,  8565539.7),
       (1723161836500000000, 61630.35,  0.,  2.073000e+02, 1725.43234, 140, 140.,  8627161.7),
       (1723161837500000000, 61613.75, -1.,  6.183810e+04, 1737.7585 , 141, 141.,  8688792.5),
       (1723161838500000000, 61613.75, -1.,  6.183810e+04, 1737.7585 , 141, 141.,  8688792.5),
       (1723161839500000000, 61605.05, -1.,  6.183810e+04, 1737.7585 , 141, 141.,  8688792.5),
       (1723161840500000000, 61616.05, -2.,  1.234437e+05, 1750.07962, 142, 142.,  8750398.1),
       (1723161841500000000, 61621.55, -3.,  1.850603e+05, 1762.40294, 143, 143.,  8812014.7),
       (1723161842500000000, 61633.95, -4.,  2.466823e+05, 1774.72734, 144, 144.,  8873636.7),
       (1723161843500000000, 61638.05, -5.,  3.083167e+05, 1787.05422, 145, 145.,  8935271.1),
       (1723161844500000000, 61634.95, -4.,  2.466791e+05, 1799.38174, 146, 146.,  8996908.7),
       (1723161845500000000, 61634.95, -4.,  2.466791e+05, 1799.38174, 146, 146.,  8996908.7),
       (1723161846500000000, 61638.05, -5.,  3.083145e+05, 1811.70882, 147, 147.,  9058544.1),
       (1723161847500000000, 61634.95, -5.,  3.083155e+05, 1836.36406, 149, 149.,  9181820.3),
       (1723161848500000000, 61626.05, -4.,  2.466811e+05, 1848.69094, 150, 150.,  9243454.7),
       (1723161849500000000, 61629.95, -4.,  2.466811e+05, 1848.69094, 150, 150.,  9243454.7),
       (1723161850500000000, 61629.95, -4.,  2.466811e+05, 1848.69094, 150, 150.,  9243454.7),
       (1723161851500000000, 61632.25, -4.,  2.466811e+05, 1848.69094, 150, 150.,  9243454.7),
       (1723161852500000000, 61635.95, -5.,  3.083139e+05, 1861.0175 , 151, 151.,  9305087.5),
       (1723161853500000000, 61635.95, -5.,  3.083139e+05, 1861.0175 , 151, 151.,  9305087.5),
       (1723161854500000000, 61638.05, -5.,  3.083139e+05, 1861.0175 , 151, 151.,  9305087.5),
       (1723161855500000000, 61636.25, -4.,  2.466763e+05, 1873.34502, 152, 152.,  9366725.1),
       (1723161856500000000, 61638.05, -4.,  2.466763e+05, 1873.34502, 152, 152.,  9366725.1),
       (1723161857500000000, 61636.05, -5.,  3.083149e+05, 1885.67274, 153, 153.,  9428363.7),
       (1723161858500000000, 61641.45, -6.,  3.699515e+05, 1898.00006, 154, 154.,  9490000.3),
       (1723161859500000000, 61641.45, -6.,  3.699515e+05, 1898.00006, 154, 154.,  9490000.3),
       (1723161860500000000, 61643.25, -6.,  3.699515e+05, 1898.00006, 154, 154.,  9490000.3),
       (1723161861500000000, 61657.25, -7.,  4.315953e+05, 1910.32882, 155, 155.,  9551644.1),
       (1723161862500000000, 61671.45, -8.,  4.932531e+05, 1922.66038, 156, 156.,  9613301.9),
       (1723161863500000000, 61668.05, -8.,  4.932531e+05, 1922.66038, 156, 156.,  9613301.9),
       (1723161864500000000, 61669.15, -8.,  4.932531e+05, 1922.66038, 156, 156.,  9613301.9),
       (1723161865500000000, 61666.75, -8.,  4.932531e+05, 1922.66038, 156, 156.,  9613301.9),
       (1723161866500000000, 61665.05, -7.,  4.315869e+05, 1934.99362, 157, 157.,  9674968.1),
       (1723161867500000000, 61657.15, -6.,  3.699223e+05, 1947.32654, 158, 158.,  9736632.7),
       (1723161868500000000, 61657.15, -6.,  3.699223e+05, 1947.32654, 158, 158.,  9736632.7),
       (1723161869500000000, 61657.15, -6.,  3.699223e+05, 1947.32654, 158, 158.,  9736632.7),
       (1723161870500000000, 61657.15, -6.,  3.699223e+05, 1947.32654, 158, 158.,  9736632.7),
       (1723161871500000000, 61666.75, -7.,  4.315799e+05, 1959.65806, 159, 159.,  9798290.3),
       (1723161872500000000, 61651.55, -6.,  3.699137e+05, 1971.9913 , 160, 160.,  9859956.5),
       (1723161873500000000, 61638.05, -5.,  3.082627e+05, 1984.3215 , 161, 161.,  9921607.5),
       (1723161874500000000, 61634.35, -4.,  2.466251e+05, 1996.64902, 162, 162.,  9983245.1),
       (1723161875500000000, 61638.85, -4.,  2.466251e+05, 1996.64902, 162, 162.,  9983245.1),
       (1723161876500000000, 61638.15, -5.,  3.082645e+05, 2008.9769 , 163, 163., 10044884.5),
       (1723161877500000000, 61621.65, -4.,  2.466269e+05, 2021.30442, 164, 164., 10106522.1),
       (1723161878500000000, 61611.65, -3.,  1.850057e+05, 2033.62866, 165, 165., 10168143.3),
       (1723161879500000000, 61614.95, -4.,  2.466179e+05, 2045.9511 , 166, 166., 10229755.5),
       (1723161880500000000, 61614.15, -4.,  2.466179e+05, 2045.9511 , 166, 166., 10229755.5),
       (1723161881500000000, 61614.15, -4.,  2.466179e+05, 2045.9511 , 166, 166., 10229755.5),
       (1723161882500000000, 61614.15, -4.,  2.466179e+05, 2045.9511 , 166, 166., 10229755.5),
       (1723161883500000000, 61616.15, -4.,  2.466179e+05, 2045.9511 , 166, 166., 10229755.5),
       (1723161884500000000, 61623.95, -5.,  3.082345e+05, 2058.27442, 167, 167., 10291372.1),
       (1723161885500000000, 61627.95, -6.,  3.698589e+05, 2070.5993 , 168, 168., 10352996.5),
       (1723161886500000000, 61621.45, -6.,  3.698589e+05, 2070.5993 , 168, 168., 10352996.5),
       (1723161887500000000, 61620.45, -5.,  3.082380e+05, 2082.92348, 169, 169., 10414617.4),
       (1723161888500000000, 61617.55, -4.,  2.466181e+05, 2095.24746, 170, 170., 10476237.3),
       (1723161889500000000, 61609.45, -3.,  1.850011e+05, 2107.57086, 171, 171., 10537854.3),
       (1723161890500000000, 61609.45, -3.,  1.850011e+05, 2107.57086, 171, 171., 10537854.3),
       (1723161891500000000, 61605.95, -3.,  1.850011e+05, 2107.57086, 171, 171., 10537854.3),
       (1723161892500000000, 61605.95, -3.,  1.850011e+05, 2107.57086, 171, 171., 10537854.3),
       (1723161893500000000, 61596.55, -3.,  1.850011e+05, 2107.57086, 171, 171., 10537854.3),
       (1723161894500000000, 61595.65, -2.,  1.234051e+05, 2119.89006, 172, 172., 10599450.3),
       (1723161895500000000, 61580.75, -1.,  6.180990e+04, 2132.2091 , 173, 173., 10661045.5),
       (1723161896500000000, 61575.05,  0.,  2.297000e+02, 2144.52514, 174, 174., 10722625.7),
       (1723161897500000000, 61585.05,  0.,  2.297000e+02, 2144.52514, 174, 174., 10722625.7),
       (1723161898500000000, 61578.25,  0.,  2.297000e+02, 2144.52514, 174, 174., 10722625.7),
       (1723161899500000000, 61578.25,  0.,  2.297000e+02, 2144.52514, 174, 174., 10722625.7),
       (1723161900500000000, 61583.95, -1.,  6.180850e+04, 2156.8409 , 175, 175., 10784204.5),
       (1723161901500000000, 61583.95, -1.,  6.180850e+04, 2156.8409 , 175, 175., 10784204.5),
       (1723161902500000000, 61583.95, -1.,  6.180850e+04, 2156.8409 , 175, 175., 10784204.5),
       (1723161903500000000, 61585.05, -2.,  1.233929e+05, 2169.15778, 176, 176., 10845788.9)],
      dtype={'names': ['timestamp', 'price', 'position', 'balance', 'fee', 'num_trades', 'trading_volume', 'trading_value'], 'formats': ['<i8', '<f8', '<f8', '<f8', '<f8', '<i8', '<f8', '<f8'], 'offsets': [0, 8, 16, 24, 32, 40, 48, 56], 'itemsize': 64, 'aligned': True})

Additionally, the to_npz method saves all records into an npz file, with the asset number as the key for the data.

[30]:
recorder.to_npz('example_record.npz')

HftBacktest also provides a performance reporting tool based on the records. Please see the details here.

[31]:
from hftbacktest.stats import LinearAssetRecord

# Constructs the LinearAssetRecord from the recorded data.
record = LinearAssetRecord(recorder.get(0))

# Generates the statistics.
# You can generate monthly and daily statistics, as well as custom metrics.
stats = record.stats()

# Prints the summary.
stats.summary()
[31]:
shape: (1, 11)
startendSRSortinoReturnMaxDrawdownDailyNumberOfTradesDailyTradingValueReturnOverMDDReturnOverTradeMaxPositionValue
datetime[μs]datetime[μs]f64f64f64f64f64f64f64f64f64
2024-08-09 00:00:002024-08-09 00:05:00-624.497686-664.628958-1846.544721902.1877850688.03.1236e9-0.970748-0.00017553849.65
[32]:
stats.plot()
../_images/tutorials_Getting_Started_53_0.png

Bokeh using Holoviews is also supported.

[33]:
import holoviews as hv
hv.extension('bokeh')

stats.plot(backend='holoviews')
[33]: