Source code for hftbacktest.binding

from ctypes import (
    c_void_p,
    c_bool,
    c_double,
    c_uint8,
    c_uint64,
    c_int64,
    POINTER,
    CDLL
)
from typing import Tuple, Any

import numba
import numpy as np
from numba import (
    carray,
    uint64,
    int64,
    float64,
    uint8,
)
from numba.core.types import voidptr
from numba.experimental import jitclass

from . import _hftbacktest
from .intrinsic import ptr_from_val, address_as_void_pointer, val_from_ptr, is_null_ptr
from .order import order_dtype, Order, Order_
from .state import StateValues, StateValues_
from .types import event_dtype, state_values_dtype, EVENT_ARRAY

lib = CDLL(_hftbacktest.__file__)

hashmapdepth_best_bid_tick = lib.hashmapdepth_best_bid_tick
hashmapdepth_best_bid_tick.restype = c_int64
hashmapdepth_best_bid_tick.argtypes = [c_void_p]

hashmapdepth_best_ask_tick = lib.hashmapdepth_best_ask_tick
hashmapdepth_best_ask_tick.restype = c_int64
hashmapdepth_best_ask_tick.argtypes = [c_void_p]

hashmapdepth_best_bid = lib.hashmapdepth_best_bid
hashmapdepth_best_bid.restype = c_double
hashmapdepth_best_bid.argtypes = [c_void_p]

hashmapdepth_best_ask = lib.hashmapdepth_best_ask
hashmapdepth_best_ask.restype = c_double
hashmapdepth_best_ask.argtypes = [c_void_p]

hashmapdepth_tick_size = lib.hashmapdepth_tick_size
hashmapdepth_tick_size.restype = c_double
hashmapdepth_tick_size.argtypes = [c_void_p]

hashmapdepth_lot_size = lib.hashmapdepth_lot_size
hashmapdepth_lot_size.restype = c_double
hashmapdepth_lot_size.argtypes = [c_void_p]

hashmapdepth_bid_qty_at_tick = lib.hashmapdepth_bid_qty_at_tick
hashmapdepth_bid_qty_at_tick.restype = c_double
hashmapdepth_bid_qty_at_tick.argtypes = [c_void_p, c_int64]

hashmapdepth_ask_qty_at_tick = lib.hashmapdepth_ask_qty_at_tick
hashmapdepth_ask_qty_at_tick.restype = c_double
hashmapdepth_ask_qty_at_tick.argtypes = [c_void_p, c_int64]

hashmapdepth_snapshot = lib.hashmapdepth_snapshot
hashmapdepth_snapshot.restype = c_void_p
hashmapdepth_snapshot.argtypes = [c_void_p, POINTER(c_uint64)]

hashmapdepth_snapshot_free = lib.hashmapdepth_snapshot_free
hashmapdepth_snapshot_free.restype = c_void_p
hashmapdepth_snapshot_free.argtypes = [c_void_p, c_uint64]


[docs] class HashMapMarketDepth: ptr: voidptr def __init__(self, ptr: voidptr): self.ptr = ptr @property def best_bid_tick(self) -> int64: """ Returns the best bid price in ticks. """ return hashmapdepth_best_bid_tick(self.ptr) @property def best_ask_tick(self) -> int64: """ Returns the best ask price in ticks. """ return hashmapdepth_best_ask_tick(self.ptr) @property def best_bid(self) -> float64: """ Returns the best bid price. """ return hashmapdepth_best_bid(self.ptr) @property def best_ask(self) -> float64: """ Returns the best ask price. """ return hashmapdepth_best_ask(self.ptr) @property def tick_size(self) -> float64: """ Returns the tick size. """ return hashmapdepth_tick_size(self.ptr) @property def lot_size(self) -> float64: """ Returns the lot size. """ return hashmapdepth_lot_size(self.ptr)
[docs] def bid_qty_at_tick(self, price_tick: int64) -> float64: """ Returns the quantity at the bid market depth for a given price in ticks. Args: price_tick: Price in ticks. Returns: The quantity at the specified price. """ return hashmapdepth_bid_qty_at_tick(self.ptr, price_tick)
[docs] def ask_qty_at_tick(self, price_tick: int64) -> float64: """ Returns the quantity at the ask market depth for a given price in ticks. Args: price_tick: Price in ticks. Returns: The quantity at the specified price. """ return hashmapdepth_ask_qty_at_tick(self.ptr, price_tick)
def snapshot(self) -> EVENT_ARRAY: length = uint64(0) len_ptr = ptr_from_val(length) ptr = hashmapdepth_snapshot(self.ptr, len_ptr) return numba.carray( address_as_void_pointer(ptr), val_from_ptr(len_ptr), event_dtype ) def snapshot_free(self, arr: EVENT_ARRAY): hashmapdepth_snapshot_free(arr.ctypes.data, len(arr))
HashMapMarketDepth_ = jitclass(HashMapMarketDepth) roivecdepth_best_bid_tick = lib.roivecdepth_best_bid_tick roivecdepth_best_bid_tick.restype = c_int64 roivecdepth_best_bid_tick.argtypes = [c_void_p] roivecdepth_best_ask_tick = lib.roivecdepth_best_ask_tick roivecdepth_best_ask_tick.restype = c_int64 roivecdepth_best_ask_tick.argtypes = [c_void_p] roivecdepth_best_bid = lib.roivecdepth_best_bid roivecdepth_best_bid.restype = c_double roivecdepth_best_bid.argtypes = [c_void_p] roivecdepth_best_ask = lib.roivecdepth_best_ask roivecdepth_best_ask.restype = c_double roivecdepth_best_ask.argtypes = [c_void_p] roivecdepth_tick_size = lib.roivecdepth_tick_size roivecdepth_tick_size.restype = c_double roivecdepth_tick_size.argtypes = [c_void_p] roivecdepth_lot_size = lib.roivecdepth_lot_size roivecdepth_lot_size.restype = c_double roivecdepth_lot_size.argtypes = [c_void_p] roivecdepth_bid_qty_at_tick = lib.roivecdepth_bid_qty_at_tick roivecdepth_bid_qty_at_tick.restype = c_double roivecdepth_bid_qty_at_tick.argtypes = [c_void_p, c_int64] roivecdepth_ask_qty_at_tick = lib.roivecdepth_ask_qty_at_tick roivecdepth_ask_qty_at_tick.restype = c_double roivecdepth_ask_qty_at_tick.argtypes = [c_void_p, c_int64] roivecdepth_bid_depth = lib.roivecdepth_bid_depth roivecdepth_bid_depth.restype = c_void_p roivecdepth_bid_depth.argtypes = [c_void_p, POINTER(c_uint64)] roivecdepth_ask_depth = lib.roivecdepth_ask_depth roivecdepth_ask_depth.restype = c_void_p roivecdepth_ask_depth.argtypes = [c_void_p, POINTER(c_uint64)]
[docs] class ROIVectorMarketDepth: ptr: voidptr def __init__(self, ptr: voidptr): self.ptr = ptr @property def best_bid_tick(self) -> int64: """ Returns the best bid price in ticks. """ return roivecdepth_best_bid_tick(self.ptr) @property def best_ask_tick(self) -> int64: """ Returns the best ask price in ticks. """ return roivecdepth_best_ask_tick(self.ptr) @property def best_bid(self) -> float64: """ Returns the best bid price. """ return roivecdepth_best_bid(self.ptr) @property def best_ask(self) -> float64: """ Returns the best ask price. """ return roivecdepth_best_ask(self.ptr) @property def tick_size(self) -> float64: """ Returns the tick size. """ return roivecdepth_tick_size(self.ptr) @property def lot_size(self) -> float64: """ Returns the lot size. """ return roivecdepth_lot_size(self.ptr)
[docs] def bid_qty_at_tick(self, price_tick: int64) -> float64: """ Returns the quantity at the bid market depth for a given price in ticks. Args: price_tick: Price in ticks. Returns: The quantity at the specified price. """ return roivecdepth_bid_qty_at_tick(self.ptr, price_tick)
[docs] def ask_qty_at_tick(self, price_tick: int64) -> float64: """ Returns the quantity at the ask market depth for a given price in ticks. Args: price_tick: Price in ticks. Returns: The quantity at the specified price. """ return roivecdepth_ask_qty_at_tick(self.ptr, price_tick)
@property def bid_depth(self) -> np.ndarray[Any, float64]: """ Returns the bid market depth array, which contains the quantity at each price. Its length is `ROI upper bound in ticks + 1 - ROI lower bound in ticks`, the array contains the quantities at prices from the ROI lower bound to the ROI upper bound. The index is calculated as `price in ticks - ROI lower bound in ticks`. Respectively, the price is `(index + ROI lower bound in ticks) * tick_size`. """ length = uint64(0) len_ptr = ptr_from_val(length) ptr = roivecdepth_bid_depth(self.ptr, len_ptr) return numba.carray( address_as_void_pointer(ptr), val_from_ptr(len_ptr), float64 ) @property def ask_depth(self) -> np.ndarray[Any, float64]: """ Returns the ask market depth array, which contains the quantity at each price. Its length is `ROI upper bound in ticks + 1 - ROI lower bound in ticks`, the array contains the quantities at prices from the ROI lower bound to the ROI upper bound. The index is calculated as `price in ticks - ROI lower bound in ticks`. Respectively, the price is `(index + ROI lower bound in ticks) * tick_size`. """ length = uint64(0) len_ptr = ptr_from_val(length) ptr = roivecdepth_ask_depth(self.ptr, len_ptr) return numba.carray( address_as_void_pointer(ptr), val_from_ptr(len_ptr), float64 )
ROIVectorMarketDepth_ = jitclass(ROIVectorMarketDepth) orders_get = lib.orders_get orders_get.restype = c_void_p orders_get.argtypes = [c_void_p, c_uint64] orders_contains = lib.orders_contains orders_contains.restype = c_bool orders_contains.argtypes = [c_void_p, c_uint64] orders_len = lib.orders_len orders_len.restype = c_uint64 orders_len.argtypes = [c_void_p] orders_values = lib.orders_values orders_values.restype = c_void_p orders_values.argtypes = [c_void_p] orders_values_next = lib.orders_values_next orders_values_next.restype = c_void_p orders_values_next.argtypes = [c_void_p] class Values: ptr: voidptr order_ptr: voidptr def __init__(self, ptr: voidptr): self.ptr = ptr self.order_ptr = 0 # def __next__(self) -> Order: # if is_null_ptr(self.ptr): # return None # order_ptr = orders_values_next(self.ptr) # if is_null_ptr(order_ptr): # self.ptr = 0 # raise StopIteration # else: # arr = carray( # address_as_void_pointer(order_ptr), # 1, # dtype=order_dtype # ) # return Order_(arr) def next(self) -> Order | None: if is_null_ptr(self.ptr): return None order_ptr = orders_values_next(self.ptr) if is_null_ptr(order_ptr): self.ptr = 0 return None else: arr = carray( address_as_void_pointer(order_ptr), 1, dtype=order_dtype ) return Order_(arr) def has_next(self) -> bool: if is_null_ptr(self.ptr): return False self.order_ptr = orders_values_next(self.ptr) if is_null_ptr(self.order_ptr): self.ptr = 0 return False return True def get(self) -> Order: if is_null_ptr(self.order_ptr): raise RuntimeError arr = carray( address_as_void_pointer(self.order_ptr), 1, dtype=order_dtype ) return Order_(arr) Values_ = jitclass(Values)
[docs] class OrderDict: """ This is a wrapper for the order dictionary. It only supports :func:`get` method, ``in`` operator through :func:`__contains__`, and :func:`values` method for iterating over values. Please note the limitations of the values iterator. """ ptr: voidptr def __init__(self, ptr: voidptr): self.ptr = ptr
[docs] def values(self) -> Values: """ Since `numba` does not support ``__next__`` method in `njit`, you need to manually iterate using the ``next``, which returns the next order value if it exists; otherwise, it returns `None`. **Example** .. code-block:: python values = order_dict.values() while True: order = values.next() if order is None: break # Do what you need with the order. Alternatively, ``has_next`` returns ``True`` if there is a next element and ``False`` otherwise, while also moving the iterator to the next element internally. ``get`` method then returns the element moved to by the ``has_next`` method. Since ``has_next`` internally moves the iterator, it should not be used solely to check if there is a next element. **Example** .. code-block:: python values = order_dict.values() while values.has_next(): order = values.get() # Do what you need with the order. """ return Values_(orders_values(self.ptr))
[docs] def get(self, order_id: uint64) -> Order | None: """ Args: order_id: Order ID Returns: Order with the specified order ID; `None` if it does not exist. """ order_ptr = orders_get(self.ptr, order_id) if is_null_ptr(order_ptr): return None else: arr = carray( address_as_void_pointer(order_ptr), 1, dtype=order_dtype ) return Order_(arr)
def __len__(self) -> uint64: return orders_len(self.ptr) def __contains__(self, order_id: uint64) -> bool: """ Args: order_id: Order ID Returns: `True` if the order with the specified order ID exists; otherwise, `False`. """ return orders_contains(self.ptr, order_id)
OrderDict_ = jitclass(OrderDict) hashmapbt_elapse = lib.hashmapbt_elapse hashmapbt_elapse.restype = c_int64 hashmapbt_elapse.argtypes = [c_void_p, c_uint64] hashmapbt_elapse_bt = lib.hashmapbt_elapse_bt hashmapbt_elapse_bt.restype = c_int64 hashmapbt_elapse_bt.argtypes = [c_void_p, c_uint64] hashmapbt_hashmapbt_wait_order_response = lib.hashmapbt_wait_order_response hashmapbt_hashmapbt_wait_order_response.restype = c_int64 hashmapbt_hashmapbt_wait_order_response.argtypes = [c_void_p, c_uint64, c_uint64, c_int64] hashmapbt_wait_next_feed = lib.hashmapbt_wait_next_feed hashmapbt_wait_next_feed.restype = c_int64 hashmapbt_wait_next_feed.argtypes = [c_void_p, c_bool, c_int64] hashmapbt_close = lib.hashmapbt_close hashmapbt_close.restype = c_int64 hashmapbt_close.argtypes = [c_void_p] hashmapbt_position = lib.hashmapbt_position hashmapbt_position.restype = c_double hashmapbt_position.argtypes = [c_void_p, c_uint64] hashmapbt_current_timestamp = lib.hashmapbt_current_timestamp hashmapbt_current_timestamp.restype = c_int64 hashmapbt_current_timestamp.argtypes = [c_void_p] hashmapbt_depth = lib.hashmapbt_depth hashmapbt_depth.restype = c_void_p hashmapbt_depth.argtypes = [c_void_p, c_uint64] hashmapbt_last_trades = lib.hashmapbt_last_trades hashmapbt_last_trades.restype = c_void_p hashmapbt_last_trades.argtypes = [c_void_p, c_uint64, POINTER(c_uint64)] hashmapbt_num_assets = lib.hashmapbt_num_assets hashmapbt_num_assets.restype = c_uint64 hashmapbt_num_assets.argtypes = [c_void_p] hashmapbt_submit_buy_order = lib.hashmapbt_submit_buy_order hashmapbt_submit_buy_order.restype = c_int64 hashmapbt_submit_buy_order.argtypes = [ c_void_p, c_uint64, c_uint64, c_double, c_double, c_uint8, c_uint8, c_bool ] hashmapbt_submit_sell_order = lib.hashmapbt_submit_sell_order hashmapbt_submit_sell_order.restype = c_int64 hashmapbt_submit_sell_order.argtypes = [ c_void_p, c_uint64, c_uint64, c_double, c_double, c_uint8, c_uint8, c_bool ] hashmapbt_cancel = lib.hashmapbt_cancel hashmapbt_cancel.restype = c_int64 hashmapbt_cancel.argtypes = [c_void_p, c_uint64, c_uint64, c_bool] hashmapbt_clear_last_trades = lib.hashmapbt_clear_last_trades hashmapbt_clear_last_trades.restype = c_void_p hashmapbt_clear_last_trades.argtypes = [c_void_p, c_uint64] hashmapbt_clear_inactive_orders = lib.hashmapbt_clear_inactive_orders hashmapbt_clear_inactive_orders.restype = c_void_p hashmapbt_clear_inactive_orders.argtypes = [c_void_p, c_uint64] hashmapbt_orders = lib.hashmapbt_orders hashmapbt_orders.restype = c_void_p hashmapbt_orders.argtypes = [c_void_p, c_uint64] hashmapbt_state_values = lib.hashmapbt_state_values hashmapbt_state_values.restype = c_void_p hashmapbt_state_values.argtypes = [c_void_p, c_uint64] hashmapbt_feed_latency = lib.hashmapbt_feed_latency hashmapbt_feed_latency.restype = c_bool hashmapbt_feed_latency.argtypes = [c_void_p, c_uint64, POINTER(c_int64), POINTER(c_int64)] hashmapbt_order_latency = lib.hashmapbt_order_latency hashmapbt_order_latency.restype = c_bool hashmapbt_order_latency.argtypes = [c_void_p, c_uint64, POINTER(c_int64), POINTER(c_int64), POINTER(c_int64)] hashmapbt_goto_end = lib.hashmapbt_goto_end hashmapbt_goto_end.restype = c_int64 hashmapbt_goto_end.argtypes = [c_void_p]
[docs] class HashMapMarketDepthBacktest: ptr: voidptr def __init__(self, ptr: voidptr): self.ptr = ptr @property def current_timestamp(self) -> int64: """ In backtesting, this timestamp reflects the time at which the backtesting is conducted within the provided data. """ return hashmapbt_current_timestamp(self.ptr)
[docs] def depth(self, asset_no: uint64) -> HashMapMarketDepth: """ Args: asset_no: Asset number from which the market depth will be retrieved. Returns: The depth of market of the specific asset. """ return HashMapMarketDepth_(hashmapbt_depth(self.ptr, asset_no))
@property def num_assets(self) -> uint64: """ Returns the number of assets. """ return hashmapbt_num_assets(self.ptr)
[docs] def position(self, asset_no: uint64) -> float64: """ Args: asset_no: Asset number from which the position will be retrieved. Returns: The quantity of the held position. """ return hashmapbt_position(self.ptr, asset_no)
[docs] def state_values(self, asset_no: uint64) -> StateValues: """ Args: asset_no: Asset number from which the state values will be retrieved. Returns: The state’s values. """ ptr = hashmapbt_state_values(self.ptr, asset_no) arr = numba.carray( address_as_void_pointer(ptr), 1, state_values_dtype ) return StateValues_(arr)
[docs] def last_trades(self, asset_no: uint64) -> EVENT_ARRAY: """ Args: asset_no: Asset number from which the trades will be retrieved. Returns: An array of `Event` representing trades occurring in the market for the specific asset. """ length = uint64(0) len_ptr = ptr_from_val(length) ptr = hashmapbt_last_trades(self.ptr, asset_no, len_ptr) return numba.carray( address_as_void_pointer(ptr), val_from_ptr(len_ptr), event_dtype )
[docs] def clear_last_trades(self, asset_no: uint64) -> None: """ Clears the last trades occurring in the market from the buffer for :func:`last_trades`. Args: asset_no: Asset number at which this command will be executed. If :const:`ALL_ASSETS <hftbacktest.types.ALL_ASSETS>`, all last trades in any assets will be cleared. """ hashmapbt_clear_last_trades(self.ptr, asset_no)
[docs] def orders(self, asset_no: uint64) -> OrderDict: """ Args: asset_no: Asset number from which orders will be retrieved. Returns: An order dictionary where the keys are order IDs and the corresponding values are :class:`Order <hftbacktest.order.Order>`. """ return OrderDict_(hashmapbt_orders(self.ptr, asset_no))
[docs] def submit_buy_order( self, asset_no: uint64, order_id: uint64, price: float64, qty: float64, time_in_force: uint8, order_type: uint8, wait: bool ) -> int64: """ Submits a buy order. Args: asset_no: Asset number at which this command will be executed. order_id: The unique order ID; there should not be any existing order with the same ID on both local and exchange sides. price: Order price. qty: Quantity to buy. time_in_force: Available options vary depending on the exchange model. See to the exchange model for details. * :const:`GTC <hftbacktest.order.GTC>` * :const:`GTX <hftbacktest.order.GTX>` * :const:`FOK <hftbacktest.order.FOK>` * :const:`IOC <hftbacktest.order.IOC>` order_type: Available options vary depending on the exchange model. See to the exchange model for details. * :const:`LIMIT <hftbacktest.order.LIMIT>` * :const:`MARKET <hftbacktest.order.MARKET>` wait: If `True`, wait until the order placement response is received. Returns: * `0` when it successfully submits an order. * `1` when it reaches the end of the data, if `wait` is `True`. * Otherwise, an error occurred. """ return hashmapbt_submit_buy_order(self.ptr, asset_no, order_id, price, qty, time_in_force, order_type, wait)
[docs] def submit_sell_order( self, asset_no: uint64, order_id: uint64, price: float64, qty: float64, time_in_force: uint8, order_type: uint8, wait: bool ) -> int64: """ Submits a sell order. Args: asset_no: Asset number at which this command will be executed. order_id: The unique order ID; there should not be any existing order with the same ID on both local and exchange sides. price: Order price. qty: Quantity to sell. time_in_force: Available options vary depending on the exchange model. See to the exchange model for details. * :const:`GTC <hftbacktest.order.GTC>` * :const:`GTX <hftbacktest.order.GTX>` * :const:`FOK <hftbacktest.order.FOK>` * :const:`IOC <hftbacktest.order.IOC>` order_type: Available options vary depending on the exchange model. See to the exchange model for details. * :const:`LIMIT <hftbacktest.order.LIMIT>` * :const:`MARKET <hftbacktest.order.MARKET>` wait: If `True`, wait until the order placement response is received. Returns: * `0` when it successfully submits an order. * `1` when it reaches the end of the data, if `wait` is `True`. * Otherwise, an error occurred. """ return hashmapbt_submit_sell_order(self.ptr, asset_no, order_id, price, qty, time_in_force, order_type, wait)
[docs] def cancel(self, asset_no: uint64, order_id: uint64, wait: bool) -> int64: """ Cancels the specified order. Args: asset_no: Asset number at which this command will be executed. order_id: Order ID to cancel. wait: If `True`, wait until the order cancel response is received. Returns: * `0` when it successfully cancels an order. * `1` when it reaches the end of the data, if `wait` is `True`. * Otherwise, an error occurred. """ return hashmapbt_cancel(self.ptr, asset_no, order_id, wait)
[docs] def clear_inactive_orders(self, asset_no: uint64) -> None: """ Clears inactive orders from the local order dictionary whose status is neither :const:`NEW <hftbacktest.order.NEW>` nor :const:`PARTIALLY_FILLED <hftbacktest.order.PARTIALLY_FILLED>`. Args: asset_no: Asset number at which this command will be executed. If :const:`ALL_ASSETS <hftbacktest.types.ALL_ASSETS>`, all inactive orders in any assets will be cleared. """ hashmapbt_clear_inactive_orders(self.ptr, asset_no)
[docs] def wait_order_response(self, asset_no: uint64, order_id: uint64, timeout: int64) -> int64: """ Waits for the response of the order with the given order ID until timeout. Args: asset_no: Asset number where an order with `order_id` exists. order_id: Order ID to wait for the response. timeout: Timeout for waiting for the order response. Nanoseconds is the default unit. However, unit should be the same as the data’s timestamp unit. Returns: * `0` when it receives an order response for the specified order ID of the specified asset number, or reaches the timeout. * `1` when it reaches the end of the data. * Otherwise, an error occurred. """ return hashmapbt_hashmapbt_wait_order_response(self.ptr, asset_no, order_id, timeout)
[docs] def wait_next_feed(self, include_order_resp: bool, timeout: int64) -> int64: """ Waits until the next feed is received, or until timeout. Args: include_order_resp: If set to `True`, it will return when any order response is received, in addition to the next feed. timeout: Timeout for waiting for the next feed or an order response. Nanoseconds is the default unit. However, unit should be the same as the data’s timestamp unit. Returns: * `0` when it receives a feed or an order response, or reaches the timeout. * `1` when it reaches the end of the data. * Otherwise, an error occurred. """ return hashmapbt_wait_next_feed(self.ptr, include_order_resp, timeout)
[docs] def elapse(self, duration: uint64) -> int64: """ Elapses the specified duration. Args: duration: Duration to elapse. Nanoseconds is the default unit. However, unit should be the same as the data’s timestamp unit. Returns: * `0` when it successfully elapses the given duration. * `1` when it reaches the end of the data. * Otherwise, an error occurred. """ return hashmapbt_elapse(self.ptr, duration)
[docs] def elapse_bt(self, duration: int64) -> int64: """ Elapses time only in backtesting. In live mode, it is ignored. (Supported only in the Rust implementation) The `elapse` method exclusively manages time during backtesting, meaning that factors such as computing time are not properly accounted for. So, this method can be utilized to simulate such processing times. Args: duration: Duration to elapse. Nanoseconds is the default unit. However, unit should be the same as the data’s timestamp unit. Returns: * `0` when it successfully elapses the given duration. * `1` when it reaches the end of the data. * Otherwise, an error occurred. """ return hashmapbt_elapse_bt(self.ptr, duration)
[docs] def close(self) -> int64: """ Closes this backtester or bot. Returns: * `0` when it successfully closes the bot. * Otherwise, an error occurred. """ return hashmapbt_close(self.ptr)
[docs] def feed_latency(self, asset_no: uint64) -> Tuple[int64, int64] | None: """ Args: asset_no: Asset number from which the last feed latency will be retrieved. Returns: The last feed’s exchange timestamp and local receipt timestamp if a feed has been received; otherwise, returns `None`. """ exch_ts = int64(0) local_ts = int64(0) exch_ts_ptr = ptr_from_val(exch_ts) local_ts_ptr = ptr_from_val(local_ts) if hashmapbt_feed_latency(self.ptr, asset_no, exch_ts_ptr, local_ts_ptr): return val_from_ptr(exch_ts_ptr), val_from_ptr(local_ts_ptr) return None
[docs] def order_latency(self, asset_no: uint64) -> Tuple[int64, int64, int64] | None: """ Args: asset_no: Asset number from which the last order latency will be retrieved. Returns: The last order’s request timestamp, exchange timestamp, and response receipt timestamp if there has been an order submission; otherwise, returns `None`. """ req_ts = int64(0) exch_ts = int64(0) resp_ts = int64(0) req_ts_ptr = ptr_from_val(req_ts) exch_ts_ptr = ptr_from_val(exch_ts) resp_ts_ptr = ptr_from_val(resp_ts) if hashmapbt_order_latency(self.ptr, asset_no, req_ts_ptr, exch_ts_ptr, resp_ts_ptr): return val_from_ptr(req_ts_ptr), val_from_ptr(exch_ts_ptr), val_from_ptr(resp_ts_ptr) return None
def _goto_end(self) -> int64: return hashmapbt_goto_end(self.ptr)
HashMapMarketDepthBacktest_ = jitclass(HashMapMarketDepthBacktest) roivecbt_elapse = lib.roivecbt_elapse roivecbt_elapse.restype = c_int64 roivecbt_elapse.argtypes = [c_void_p, c_uint64] roivecbt_elapse_bt = lib.roivecbt_elapse_bt roivecbt_elapse_bt.restype = c_int64 roivecbt_elapse_bt.argtypes = [c_void_p, c_uint64] roivecbt_roivecbt_wait_order_response = lib.roivecbt_wait_order_response roivecbt_roivecbt_wait_order_response.restype = c_int64 roivecbt_roivecbt_wait_order_response.argtypes = [c_void_p, c_uint64, c_uint64, c_int64] roivecbt_wait_next_feed = lib.roivecbt_wait_next_feed roivecbt_wait_next_feed.restype = c_int64 roivecbt_wait_next_feed.argtypes = [c_void_p, c_bool, c_int64] roivecbt_close = lib.roivecbt_close roivecbt_close.restype = c_int64 roivecbt_close.argtypes = [c_void_p] roivecbt_position = lib.roivecbt_position roivecbt_position.restype = c_double roivecbt_position.argtypes = [c_void_p, c_uint64] roivecbt_current_timestamp = lib.roivecbt_current_timestamp roivecbt_current_timestamp.restype = c_int64 roivecbt_current_timestamp.argtypes = [c_void_p] roivecbt_depth = lib.roivecbt_depth roivecbt_depth.restype = c_void_p roivecbt_depth.argtypes = [c_void_p, c_uint64] roivecbt_last_trades = lib.roivecbt_last_trades roivecbt_last_trades.restype = c_void_p roivecbt_last_trades.argtypes = [c_void_p, c_uint64, POINTER(c_uint64)] roivecbt_num_assets = lib.roivecbt_num_assets roivecbt_num_assets.restype = c_uint64 roivecbt_num_assets.argtypes = [c_void_p] roivecbt_submit_buy_order = lib.roivecbt_submit_buy_order roivecbt_submit_buy_order.restype = c_int64 roivecbt_submit_buy_order.argtypes = [ c_void_p, c_uint64, c_uint64, c_double, c_double, c_uint8, c_uint8, c_bool ] roivecbt_submit_sell_order = lib.roivecbt_submit_sell_order roivecbt_submit_sell_order.restype = c_int64 roivecbt_submit_sell_order.argtypes = [ c_void_p, c_uint64, c_uint64, c_double, c_double, c_uint8, c_uint8, c_bool ] roivecbt_cancel = lib.roivecbt_cancel roivecbt_cancel.restype = c_int64 roivecbt_cancel.argtypes = [c_void_p, c_uint64, c_uint64, c_bool] roivecbt_clear_last_trades = lib.roivecbt_clear_last_trades roivecbt_clear_last_trades.restype = c_void_p roivecbt_clear_last_trades.argtypes = [c_void_p, c_uint64] roivecbt_clear_inactive_orders = lib.roivecbt_clear_inactive_orders roivecbt_clear_inactive_orders.restype = c_void_p roivecbt_clear_inactive_orders.argtypes = [c_void_p, c_uint64] roivecbt_orders = lib.roivecbt_orders roivecbt_orders.restype = c_void_p roivecbt_orders.argtypes = [c_void_p, c_uint64] roivecbt_state_values = lib.roivecbt_state_values roivecbt_state_values.restype = c_void_p roivecbt_state_values.argtypes = [c_void_p, c_uint64] roivecbt_feed_latency = lib.roivecbt_feed_latency roivecbt_feed_latency.restype = c_bool roivecbt_feed_latency.argtypes = [c_void_p, c_uint64, POINTER(c_int64), POINTER(c_int64)] roivecbt_order_latency = lib.roivecbt_order_latency roivecbt_order_latency.restype = c_bool roivecbt_order_latency.argtypes = [c_void_p, c_uint64, POINTER(c_int64), POINTER(c_int64), POINTER(c_int64)]
[docs] class ROIVectorMarketDepthBacktest: ptr: voidptr def __init__(self, ptr: voidptr): self.ptr = ptr @property def current_timestamp(self) -> int64: """ In backtesting, this timestamp reflects the time at which the backtesting is conducted within the provided data. """ return roivecbt_current_timestamp(self.ptr)
[docs] def depth(self, asset_no: uint64) -> ROIVectorMarketDepth: """ Args: asset_no: Asset number from which the market depth will be retrieved. Returns: The depth of market of the specific asset. """ return ROIVectorMarketDepth_(roivecbt_depth(self.ptr, asset_no))
@property def num_assets(self) -> uint64: """ Returns the number of assets. """ return roivecbt_num_assets(self.ptr)
[docs] def position(self, asset_no: uint64) -> float64: """ Args: asset_no: Asset number from which the position will be retrieved. Returns: The quantity of the held position. """ return roivecbt_position(self.ptr, asset_no)
[docs] def state_values(self, asset_no: uint64) -> StateValues: """ Args: asset_no: Asset number from which the state values will be retrieved. Returns: The state’s values. """ ptr = roivecbt_state_values(self.ptr, asset_no) arr = numba.carray( address_as_void_pointer(ptr), 1, state_values_dtype ) return StateValues_(arr)
[docs] def last_trades(self, asset_no: uint64) -> EVENT_ARRAY: """ Args: asset_no: Asset number from which the trades will be retrieved. Returns: An array of `Event` representing trades occurring in the market for the specific asset. """ length = uint64(0) len_ptr = ptr_from_val(length) ptr = roivecbt_last_trades(self.ptr, asset_no, len_ptr) return numba.carray( address_as_void_pointer(ptr), val_from_ptr(len_ptr), event_dtype )
[docs] def clear_last_trades(self, asset_no: uint64) -> None: """ Clears the last trades occurring in the market from the buffer for :func:`last_trades`. Args: asset_no: Asset number at which this command will be executed. If :const:`ALL_ASSETS <hftbacktest.types.ALL_ASSETS>`, all last trades in any assets will be cleared. """ roivecbt_clear_last_trades(self.ptr, asset_no)
[docs] def orders(self, asset_no: uint64) -> OrderDict: """ Args: asset_no: Asset number from which orders will be retrieved. Returns: An order dictionary where the keys are order IDs and the corresponding values are :class:`Order <hftbacktest.order.Order>`. """ return OrderDict_(roivecbt_orders(self.ptr, asset_no))
[docs] def submit_buy_order( self, asset_no: uint64, order_id: uint64, price: float64, qty: float64, time_in_force: uint8, order_type: uint8, wait: bool ) -> int64: """ Submits a buy order. Args: asset_no: Asset number at which this command will be executed. order_id: The unique order ID; there should not be any existing order with the same ID on both local and exchange sides. price: Order price. qty: Quantity to buy. time_in_force: Available options vary depending on the exchange model. See to the exchange model for details. * :const:`GTC <hftbacktest.order.GTC>` * :const:`GTX <hftbacktest.order.GTX>` * :const:`FOK <hftbacktest.order.FOK>` * :const:`IOC <hftbacktest.order.IOC>` order_type: Available options vary depending on the exchange model. See to the exchange model for details. * :const:`LIMIT <hftbacktest.order.LIMIT>` * :const:`MARKET <hftbacktest.order.MARKET>` wait: If `True`, wait until the order placement response is received. Returns: * `0` when it successfully submits an order. * `1` when it reaches the end of the data, if `wait` is `True`. * Otherwise, an error occurred. """ return roivecbt_submit_buy_order(self.ptr, asset_no, order_id, price, qty, time_in_force, order_type, wait)
[docs] def submit_sell_order( self, asset_no: uint64, order_id: uint64, price: float64, qty: float64, time_in_force: uint8, order_type: uint8, wait: bool ) -> int64: """ Submits a sell order. Args: asset_no: Asset number at which this command will be executed. order_id: The unique order ID; there should not be any existing order with the same ID on both local and exchange sides. price: Order price. qty: Quantity to sell. time_in_force: Available options vary depending on the exchange model. See to the exchange model for details. * :const:`GTC <hftbacktest.order.GTC>` * :const:`GTX <hftbacktest.order.GTX>` * :const:`FOK <hftbacktest.order.FOK>` * :const:`IOC <hftbacktest.order.IOC>` order_type: Available options vary depending on the exchange model. See to the exchange model for details. * :const:`LIMIT <hftbacktest.order.LIMIT>` * :const:`MARKET <hftbacktest.order.MARKET>` wait: If `True`, wait until the order placement response is received. Returns: * `0` when it successfully submits an order. * `1` when it reaches the end of the data, if `wait` is `True`. * Otherwise, an error occurred. """ return roivecbt_submit_sell_order(self.ptr, asset_no, order_id, price, qty, time_in_force, order_type, wait)
[docs] def cancel(self, asset_no: uint64, order_id: uint64, wait: bool) -> int64: """ Cancels the specified order. Args: asset_no: Asset number at which this command will be executed. order_id: Order ID to cancel. wait: If `True`, wait until the order cancel response is received. Returns: * `0` when it successfully cancels an order. * `1` when it reaches the end of the data, if `wait` is `True`. * Otherwise, an error occurred. """ return roivecbt_cancel(self.ptr, asset_no, order_id, wait)
[docs] def clear_inactive_orders(self, asset_no: uint64) -> None: """ Clears inactive orders from the local order dictionary whose status is neither :const:`NEW <hftbacktest.order.NEW>` nor :const:`PARTIALLY_FILLED <hftbacktest.order.PARTIALLY_FILLED>`. Args: asset_no: Asset number at which this command will be executed. If :const:`ALL_ASSETS <hftbacktest.types.ALL_ASSETS>`, all inactive orders in any assets will be cleared. """ roivecbt_clear_inactive_orders(self.ptr, asset_no)
[docs] def wait_order_response(self, asset_no: uint64, order_id: uint64, timeout: int64) -> int64: """ Waits for the response of the order with the given order ID until timeout. Args: asset_no: Asset number where an order with `order_id` exists. order_id: Order ID to wait for the response. timeout: Timeout for waiting for the order response. Nanoseconds is the default unit. However, unit should be the same as the data’s timestamp unit. Returns: * `0` when it receives an order response for the specified order ID of the specified asset number, or reaches the timeout. * `1` when it reaches the end of the data. * Otherwise, an error occurred. """ return roivecbt_roivecbt_wait_order_response(self.ptr, asset_no, order_id, timeout)
[docs] def wait_next_feed(self, include_order_resp: bool, timeout: int64) -> int64: """ Waits until the next feed is received, or until timeout. Args: include_order_resp: If set to `True`, it will return when any order response is received, in addition to the next feed. timeout: Timeout for waiting for the next feed or an order response. Nanoseconds is the default unit. However, unit should be the same as the data’s timestamp unit. Returns: * `0` when it receives a feed or an order response, or reaches the timeout. * `1` when it reaches the end of the data. * Otherwise, an error occurred. """ return roivecbt_wait_next_feed(self.ptr, include_order_resp, timeout)
[docs] def elapse(self, duration: uint64) -> int64: """ Elapses the specified duration. Args: duration: Duration to elapse. Nanoseconds is the default unit. However, unit should be the same as the data’s timestamp unit. Returns: * `0` when it successfully elapses the given duration. * `1` when it reaches the end of the data. * Otherwise, an error occurred. """ return roivecbt_elapse(self.ptr, duration)
[docs] def elapse_bt(self, duration: int64) -> int64: """ Elapses time only in backtesting. In live mode, it is ignored. (Supported only in the Rust implementation) The `elapse` method exclusively manages time during backtesting, meaning that factors such as computing time are not properly accounted for. So, this method can be utilized to simulate such processing times. Args: duration: Duration to elapse. Nanoseconds is the default unit. However, unit should be the same as the data’s timestamp unit. Returns: * `0` when it successfully elapses the given duration. * `1` when it reaches the end of the data. * Otherwise, an error occurred. """ return roivecbt_elapse_bt(self.ptr, duration)
[docs] def close(self) -> int64: """ Closes this backtester or bot. Returns: * `0` when it successfully closes the bot. * Otherwise, an error occurred. """ return roivecbt_close(self.ptr)
[docs] def feed_latency(self, asset_no: uint64) -> Tuple[int64, int64] | None: """ Args: asset_no: Asset number from which the last feed latency will be retrieved. Returns: The last feed’s exchange timestamp and local receipt timestamp if a feed has been received; otherwise, returns `None`. """ exch_ts = int64(0) local_ts = int64(0) exch_ts_ptr = ptr_from_val(exch_ts) local_ts_ptr = ptr_from_val(local_ts) if roivecbt_feed_latency(self.ptr, asset_no, exch_ts_ptr, local_ts_ptr): return val_from_ptr(exch_ts_ptr), val_from_ptr(local_ts_ptr) return None
[docs] def order_latency(self, asset_no: uint64) -> Tuple[int64, int64, int64] | None: """ Args: asset_no: Asset number from which the last order latency will be retrieved. Returns: The last order’s request timestamp, exchange timestamp, and response receipt timestamp if there has been an order submission; otherwise, returns `None`. """ req_ts = int64(0) exch_ts = int64(0) resp_ts = int64(0) req_ts_ptr = ptr_from_val(req_ts) exch_ts_ptr = ptr_from_val(exch_ts) resp_ts_ptr = ptr_from_val(resp_ts) if roivecbt_order_latency(self.ptr, asset_no, req_ts_ptr, exch_ts_ptr, resp_ts_ptr): return val_from_ptr(req_ts_ptr), val_from_ptr(exch_ts_ptr), val_from_ptr(resp_ts_ptr) return None
ROIVectorMarketDepthBacktest_ = jitclass(ROIVectorMarketDepthBacktest)