### Install hftbacktest using pip Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/index.md Install the hftbacktest package using pip. Ensure you have Python 3.10+ installed. ```console pip install hftbacktest ``` -------------------------------- ### Market Making Algorithm Example Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/index.md This snippet demonstrates a market making algorithm using hftbacktest. It includes logic for managing orders, calculating prices, and handling risk. Ensure necessary imports and setup for hftbacktest are done prior to execution. ```python @njit def market_making_algo(hbt): asset_no = 0 tick_size = hbt.depth(asset_no).tick_size lot_size = hbt.depth(asset_no).lot_size # in nanoseconds while hbt.elapse(10_000_000) == 0: hbt.clear_inactive_orders(asset_no) a = 1 b = 1 c = 1 hs = 1 # Alpha, it can be a combination of several indicators. forecast = 0 # In HFT, it can be various measurements of short-term market movements, # such as the high-low range in the last X minutes. volatility = 0 # Delta risk, it can be a combination of several risks. position = hbt.position(asset_no) risk = (c + volatility) * position half_spread = (c + volatility) * hs max_notional_position = 1000 notional_qty = 100 depth = hbt.depth(asset_no) mid_price = (depth.best_bid + depth.best_ask) / 2.0 # fair value pricing = mid_price + a * forecast # or underlying(correlated asset) + adjustment(basis + cost + etc) + a * forecast # risk skewing = -b * risk reservation_price = mid_price + a * forecast - b * risk new_bid = reservation_price - half_spread new_ask = reservation_price + half_spread new_bid_tick = min(np.round(new_bid / tick_size), depth.best_bid_tick) new_ask_tick = max(np.round(new_ask / tick_size), depth.best_ask_tick) order_qty = np.round(notional_qty / mid_price / lot_size) * lot_size # Elapses a process time. if not hbt.elapse(1_000_000) != 0: return False last_order_id = -1 update_bid = True update_ask = True buy_limit_exceeded = position * mid_price > max_notional_position sell_limit_exceeded = position * mid_price < -max_notional_position orders = hbt.orders(asset_no) order_values = orders.values() while order_values.has_next(): order = order_values.get() if order.side == BUY: if order.price_tick == new_bid_tick or buy_limit_exceeded: update_bid = False if order.cancellable and (update_bid or buy_limit_exceeded): hbt.cancel(asset_no, order.order_id, False) last_order_id = order.order_id elif order.side == SELL: if order.price_tick == new_ask_tick or sell_limit_exceeded: update_ask = False if order.cancellable and (update_ask or sell_limit_exceeded): hbt.cancel(asset_no, order.order_id, False) last_order_id = order.order_id # It can be combined with a grid trading strategy by submitting multiple orders to capture better spreads and # have queue position. # This approach requires more sophisticated logic to efficiently manage resting orders in the order book. if update_bid: # There is only one order at a given price, with new_bid_tick used as the order ID. order_id = new_bid_tick hbt.submit_buy_order(asset_no, order_id, new_bid_tick * tick_size, order_qty, GTX, LIMIT, False) last_order_id = order_id if update_ask: # There is only one order at a given price, with new_ask_tick used as the order ID. order_id = new_ask_tick hbt.submit_sell_order(asset_no, order_id, new_ask_tick * tick_size, order_qty, GTX, LIMIT, False) last_order_id = order_id # All order requests are considered to be requested at the same time. # Waits until one of the order responses is received. if last_order_id >= 0: # Waits for the order response for a maximum of 5 seconds. timeout = 5_000_000_000 if not hbt.wait_order_response(asset_no, last_order_id, timeout): return False return True ``` -------------------------------- ### Install hftbacktest from Git Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/index.md Clone the latest development version of hftbacktest from its Git repository. ```console git clone https://github.com/nkaz001/hftbacktest ``` -------------------------------- ### Backtesting Setup and Execution Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/High-Frequency Grid Trading.ipynb Initializes the backtesting environment, sets up the recorder, runs the grid trading strategy, and calculates performance statistics. Assumes necessary classes like `ROIVectorMarketDepthBacktest` and `Recorder` are available. ```python hbt = ROIVectorMarketDepthBacktest([asset]) skew = 1 recorder = Recorder(1, 5_000_000) gridtrading(hbt, recorder.recorder, skew) hbt.close() stats = LinearAssetRecord(recorder.get(0)).stats(book_size=10_000) stats.summary() ``` -------------------------------- ### Backtest Asset and APT Market Making Setup Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Market Making with Alpha - APT.ipynb Configures a backtest asset with historical data, latency, fees, and tick/lot sizes. It then initializes the APT market making algorithm with specified parameters. ```python %%time roi_lb = 50000 roi_ub = 150000 latency_data = [] date = start_date while date <= end_date: latency_data.append('latency/order_latency_{}.npz'.format(date.strftime('%Y%m%d'))) date += datetime.timedelta(days=1) data = [] date = start_date while date <= end_date: data.append('data2/btcusdt_{}.npz'.format(date.strftime("%Y%m%d"))) date += datetime.timedelta(days=1) asset = ( BacktestAsset() .data(data) .initial_snapshot('data2/btcusdt_20241231_eod.npz') .linear_asset(1.0) .intp_order_latency(latency_data) .power_prob_queue_model(3) .no_partial_fill_exchange() .trading_value_fee_model(-0.00005, 0.0007) .tick_size(0.1) .lot_size(0.001) .roi_lb(roi_lb) .roi_ub(roi_ub) ) hbt = ROIVectorMarketDepthBacktest([asset]) recorder = Recorder(1, 60_000_000) half_spread = 0.0003 # a ratio relative to the fair price skew = half_spread / 20 interval = 100_000_000 # in nanoseconds. 100ms order_qty_dollar = 50_000 max_position_dollar = order_qty_dollar * 20 grid_num = 5 grid_interval = 0.0003 # a ratio relative to the fair price beta = np.asarray([-0.0117, 1.0164]) apt_multi_mm( hbt, recorder.recorder, half_spread, skew, beta, precompute_data, interval, order_qty_dollar, max_position_dollar, grid_num, grid_interval, roi_lb, roi_ub ) hbt.close() recorder.to_npz('stats/underlying_btcspot2_return_5m_2025.npz') ``` -------------------------------- ### Initialize Market Making Backtest Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Queue-Based Market Making in Large Tick Size Assets.ipynb Initializes the backtest environment and recorder for performance tracking. This setup is required before running the market making strategy. ```python hbt = ROIVectorMarketDepthBacktest([asset]) recorder = Recorder(1, 100_000_000) ``` -------------------------------- ### Raw Data Examples Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/data.md These examples show the raw data format received from the exchange for depth updates and trades. Ensure your parser can handle the nested JSON structure. ```default 1676419207212527000 {'stream': 'btcusdt@depth@0ms', 'data': {'e': 'depthUpdate', 'E': 1676419206974, 'T': 1676419205108, 's': 'BTCUSDT', 'U': 2505118837831, 'u': 2505118838224, 'pu': 2505118837821, 'b': [['2218.80', '0.603'], ['5000.00', '2.641'], ['22160.60', '0.008'], ['22172.30', '0.551'], ['22173.40', '0.073'], ['22174.50', '0.006'], ['22176.80', '0.157'], ['22177.90', '0.425'], ['22181.20', '0.260'], ['22182.30', '3.918'], ['22182.90', '0.000'], ['22183.40', '0.014'], ['22203.00', '0.000']], 'a': [['22171.70', '0.000'], ['22187.30', '0.000'], ['22194.30', '0.270'], ['22194.70', '0.423'], ['22195.20', '2.075'], ['22209.60', '4.506']]}} 1676419207212584000 {'stream': 'btcusdt@trade', 'data': {'e': 'trade', 'E': 1676419206976, 'T': 1676419205116, 's': 'BTCUSDT', 't': 3288803053, 'p': '22177.90', 'q': '0.001', 'X': 'MARKET', 'm': True}} ``` -------------------------------- ### Backtest Setup and Execution Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Fusing Depth Data.ipynb Configures the backtesting environment, including asset data, order latency, fee models, and market depth simulation. It then initializes the backtester and runs the market-making strategy. ```python roi_lb = 50000 roi_ub = 150000 half_spread = 0.0005 # a ratio relative to the fair price skew = half_spread / 20 interval = 100_000_000 # in nanoseconds. 100ms order_qty_dollar = 50_000 max_position_dollar = 1_000_000 grid_num = 1 grid_interval = 0.1 asset = ( BacktestAsset() .data(['BTCUSDT_nonfused_20250501.npz']) .linear_asset(1.0) .intp_order_latency(['../latency/order_latency_20250501.npz']) .power_prob_queue_model(3) .no_partial_fill_exchange() .trading_value_fee_model(-0.00005, 0.0007) .tick_size(0.1) .lot_size(0.001) .roi_lb(roi_lb) .roi_ub(roi_ub) ) hbt = ROIVectorMarketDepthBacktest([asset]) recorder = Recorder(1, 60_000_000) basic_mm( hbt, recorder.recorder, half_spread, skew, interval, order_qty_dollar, max_position_dollar, grid_num, grid_interval ) _ = hbt.close() ``` -------------------------------- ### Backtest Execution and Setup Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Accelerated Backtesting.ipynb Sets up and runs the backtest simulation using the ROIVectorMarketDepthBacktest engine. This includes defining asset data, fee models, and order latency, then executing the market making strategy. ```python %%time roi_lb = 50000 roi_ub = 150000 grid_num = 1 grid_interval_tick = 1 asset = ( BacktestAsset() .data(['BTCUSDT_20250801.npz']) .linear_asset(1.0) .intp_order_latency(['feed_order_latency_20250801.npz']) .power_prob_queue_model(3) .no_partial_fill_exchange() .trading_value_fee_model(-0.00005, 0.0007) .tick_size(0.1) .lot_size(0.001) .roi_lb(roi_lb) .roi_ub(roi_ub) ) hbt = ROIVectorMarketDepthBacktest([asset]) recorder = Recorder(1, 60_000_000) basic_mm( hbt, recorder.recorder, relative_half_spread, skew, running_interval, order_notional_value, max_notional_position, grid_num, grid_interval_tick ) _ = hbt.close() ``` -------------------------------- ### Backtest Setup and Execution Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Making Multiple Markets.ipynb Configures and runs a backtest for a trading strategy. It loads historical data, initializes the backtest environment, defines asset parameters, and executes the trading logic. ```python def backtest(args): asset_name, asset_info = args # Obtains the mid-price of the assset to determine the order quantity. snapshot = np.load('data/{}_20230630_eod.npz'.format(asset_name))['data'] best_bid = max(snapshot[snapshot['ev'] & BUY_EVENT == BUY_EVENT]['px']) best_ask = min(snapshot[snapshot['ev'] & SELL_EVENT == SELL_EVENT]['px']) mid_price = (best_bid + best_ask) / 2.0 latency_data = np.concatenate( [np.load('latency/live_order_latency_{}.npz'.format(date))['data'] for date in range(20230701, 20230732)] ) asset = ( BacktestAsset() .data(['data/{}_{}.npz'.format(asset_name, date) for date in range(20230701, 20230732)]) .initial_snapshot('data/{}_20230630_eod.npz'.format(asset_name)) .linear_asset(1.0) .intp_order_latency(latency_data) .power_prob_queue_model(2.0) .no_partial_fill_exchange() .trading_value_fee_model(-0.00005, 0.0007) .tick_size(asset_info['tick_size']) .lot_size(asset_info['lot_size']) .roi_lb(0.0) .roi_ub(mid_price * 5) .last_trades_capacity(10000) ) hbt = ROIVectorMarketDepthBacktest([asset]) # Sets the order quantity to be equivalent to a notional value of $100. order_qty = max(round((100 / mid_price) / asset_info['lot_size']), 1) * asset_info['lot_size'] recorder = Recorder(1, 30_000_000) gamma = 0.00005 gridtrading_glft_mm(hbt, recorder.recorder, gamma, order_qty) hbt.close() recorder.to_npz('stats/gridtrading_simple_glft_mm1_{}.npz'.format(asset_name)) ``` -------------------------------- ### Backtest Asset and Market Depth Backtest Setup Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/GLFT Market Making Model and Grid Trading.ipynb Configures a backtesting asset with historical data, latency, fee models, and order parameters. Initializes the ROIVectorMarketDepthBacktest and Recorder. ```python from hftbacktest import Recorder from hftbacktest.stats import LinearAssetRecord asset = ( BacktestAsset() .data([ 'data/ethusdt_20221003.npz' ]) .initial_snapshot('data/ethusdt_20221002_eod.npz') .linear_asset(1.0) .intp_order_latency([ 'latency/feed_latency_20221003.npz' ]) .power_prob_queue_model(2.0) .no_partial_fill_exchange() .trading_value_fee_model(-0.00005, 0.0007) .tick_size(0.01) .lot_size(0.001) .roi_lb(0.0) .roi_ub(3000.0) .last_trades_capacity(10000) ) hbt = ROIVectorMarketDepthBacktest([asset]) recorder = Recorder(1, 5_000_000) out = glft_market_maker(hbt, recorder.recorder) hbt.close() stats = LinearAssetRecord(recorder.get(0)).stats(book_size=30_000) stats.summary() ``` -------------------------------- ### Initialize Backtest and APT Market Making Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Market Making with Alpha - APT.ipynb Sets up the backtesting environment, defines the asset, and initializes the APT market making algorithm. This includes configuring data sources, fees, and market parameters. ```python %%time roi_lb = 10000 roi_ub = 90000 latency_data = [] date = start_date while date <= end_date: latency_data.append('latency/order_latency_{}.npz'.format(date.strftime('%Y%m%d'))) date += datetime.timedelta(days=1) data = [] date = start_date while date <= end_date: data.append('data2/btcusdt_{}.npz'.format(date.strftime("%Y%m%d"))) date += datetime.timedelta(days=1) asset = ( BacktestAsset() .data(data) .initial_snapshot('data2/btcusdt_20240831_eod.npz') .linear_asset(1.0) .intp_order_latency(latency_data) .power_prob_queue_model(3) .no_partial_fill_exchange() .trading_value_fee_model(-0.00005, 0.0007) .tick_size(0.1) .lot_size(0.001) .roi_lb(roi_lb) .roi_ub(roi_ub) ) hbt = ROIVectorMarketDepthBacktest([asset]) recorder = Recorder(1, 60_000_000) half_spread = 0.0003 # a ratio relative to the fair price skew = half_spread / 20 interval = 100_000_000 # in nanoseconds. 100ms order_qty_dollar = 50_000 max_position_dollar = order_qty_dollar * 20 grid_num = 1 grid_interval = hbt.depth(0).tick_size apt_mm( hbt, recorder.recorder, half_spread, skew, precompute_data, interval, order_qty_dollar, max_position_dollar, grid_num, grid_interval, roi_lb, roi_ub ) hbt.close() recorder.to_npz('stats/underlying_btcusdt_return_5m.npz') ``` -------------------------------- ### IntpOrderLatency Data Example Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/latency_models.md Example data format for IntpOrderLatency, including request timestamp, exchange timestamp, and receipt timestamp. ```default req_ts (request timestamp at local), exch_ts (exchange timestamp), resp_ts (receipt timestamp at local), _padding 1670026844751525000, 1670026844759000000, 1670026844762122000, 0 1670026845754020000, 1670026845762000000, 1670026845770003000, 0 ``` -------------------------------- ### Configure and Run APT Market Making Strategy Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Market Making with Alpha - APT.ipynb Sets up the backtest environment, defines asset parameters, and executes the APT market making strategy. Ensure all necessary data files and parameters are correctly configured before running. ```python %%time roi_lb = 50000 roi_ub = 150000 latency_data = [] date = start_date while date <= end_date: latency_data.append('latency/order_latency_{}.npz'.format(date.strftime('%Y%m%d'))) date += datetime.timedelta(days=1) data = [] date = start_date while date <= end_date: data.append('data2/btcusdt_{}.npz'.format(date.strftime("%Y%m%d"))) date += datetime.timedelta(days=1) asset = ( BacktestAsset() .data(data) .initial_snapshot('data2/btcusdt_20241231_eod.npz') .linear_asset(1.0) .intp_order_latency(latency_data) .power_prob_queue_model(3) .no_partial_fill_exchange() .trading_value_fee_model(-0.00005, 0.0007) .tick_size(0.1) .lot_size(0.001) .roi_lb(roi_lb) .roi_ub(roi_ub) ) hbt = ROIVectorMarketDepthBacktest([asset]) recorder = Recorder(1, 60_000_000) half_spread = 0.0003 # a ratio relative to the fair price skew = half_spread / 20 interval = 100_000_000 # in nanoseconds. 100ms order_qty_dollar = 50_000 max_position_dollar = order_qty_dollar * 20 grid_num = 5 grid_interval = 0.0003 # a ratio relative to the fair price beta = np.asarray([0.5, 0.5]) apt_multi_mm( hbt, recorder.recorder, half_spread, skew, beta, precompute_data, interval, order_qty_dollar, max_position_dollar, grid_num, grid_interval, roi_lb, roi_ub ) hbt.close() recorder.to_npz('stats/underlying_btcspot_return_5m_2025.npz') ``` -------------------------------- ### Example of Unordered Events Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/data.md This example shows raw event data where timestamps might not be in strict chronological order, illustrating the need for validation. ```default 1676419207212385000 {'stream': 'btcusdt@trade', 'data': {'e': 'trade', 'E': 1676419206968, 'T': 1676419205111, 's': 'BTCUSDT', 't': 3288803051, 'p': '22177.90', 'q': '0.300', 'X': 'MARKET', 'm': True}} 1676419207212480000 {'stream': 'btcusdt@trade', 'data': {'e': 'trade', 'E': 1676419206968, 'T': 1676419205111, 's': 'BTCUSDT', 't': 3288803052, 'p': '22177.90', 'q': '0.119', 'X': 'MARKET', 'm': True}} 1676419207212527000 {'stream': 'btcusdt@depth@0ms', 'data': {'e': 'depthUpdate', 'E': 1676419206974, 'T': 1676419205108, 's': 'BTCUSDT', 'U': 2505118837831, 'u': 2505118838224, 'pu': 2505118837821, 'b': [['2218.80', '0.603'], ['5000.00', '2.641'], ['22160.60', '0.008'], ['22172.30', '0.551'], ['22173.40', '0.073'], ['22174.50', '0.006'], ['22176.80', '0.157'], ['22177.90', '0.425'], ['22181.20', '0.260'], ['22182.30', '3.918'], ['22182.90', '0.000'], ['22183.40', '0.014'], ['22203.00', '0.000']], 'a': [['22171.70', '0.000'], ['22187.30', '0.000'], ['22194.30', '0.270'], ['22194.70', '0.423'], ['22195.20', '2.075'], ['22209.60', '4.506']]}} 1676419207212584000 {'stream': 'btcusdt@trade', 'data': {'e': 'trade', 'E': 1676419206976, 'T': 1676419205116, 's': 'BTCUSDT', 't': 3288803053, 'p': '22177.90', 'q': '0.001', 'X': 'MARKET', 'm': True}} 1676419207212621000 {'stream': 'btcusdt@trade', 'data': {'e': 'trade', 'E': 1676419206976, 'T': 1676419205116, 's': 'BTCUSDT', 't': 3288803054, 'p': '22177.90', 'q': '0.005', 'X': 'MARKET', 'm': True}} ``` -------------------------------- ### Corrected Event Order Example Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/data.md This example demonstrates how event data is represented after applying corrections for chronological order, using flags like EXCH_EVENT and LOCAL_EVENT. ```default EXCH_EVENT 1676419207212527000 {'stream': 'btcusdt@depth@0ms', 'data': {'e': 'depthUpdate', 'E': 1676419206974, 'T': 1676419205108, 's': 'BTCUSDT', 'U': 2505118837831, 'u': 2505118838224, 'pu': 2505118837821, 'b': [['2218.80', '0.603'], ['5000.00', '2.641'], ['22160.60', '0.008'], ['22172.30', '0.551'], ['22173.40', '0.073'], ['22174.50', '0.006'], ['22176.80', '0.157'], ['22177.90', '0.425'], ['22181.20', '0.260'], ['22182.30', '3.918'], ['22182.90', '0.000'], ['22183.40', '0.014'], ['22203.00', '0.000']], 'a': [['22171.70', '0.000'], ['22187.30', '0.000'], ['22194.30', '0.270'], ['22194.70', '0.423'], ['22195.20', '2.075'], ['22209.60', '4.506']]}} EXCH_EVENT | LOCAL_EVENT 1676419207212385000 {'stream': 'btcusdt@trade', 'data': {'e': 'trade', 'E': 1676419206968, 'T': 1676419205111, 's': 'BTCUSDT', 't': 3288803051, 'p': '22177.90', 'q': '0.300', 'X': 'MARKET', 'm': True}} EXCH_EVENT | LOCAL_EVENT 1676419207212480000 {'stream': 'btcusdt@trade', 'data': {'e': 'trade', 'E': 1676419206968, 'T': 1676419205111, 's': 'BTCUSDT', 't': 3288803052, 'p': '22177.90', 'q': '0.119', 'X': 'MARKET', 'm': True}} ``` -------------------------------- ### Initialize and Run APT Market Maker Backtest Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Market Making with Alpha - APT.ipynb Sets up the backtesting environment, configures the market making strategy parameters, and runs the APT market maker simulation. This includes defining order latency, fees, and ROI bounds. ```python %%time roi_lb = 50000 roi_ub = 150000 latency_data = [] date = start_date while date <= end_date: latency_data.append('latency/order_latency_{}.npz'.format(date.strftime('%Y%m%d'))) date += datetime.timedelta(days=1) data = [] date = start_date while date <= end_date: data.append('data2/btcusdt_{}.npz'.format(date.strftime("%Y%m%d"))) date += datetime.timedelta(days=1) asset = ( BacktestAsset() .data(data) .initial_snapshot('data2/btcusdt_20241231_eod.npz') .linear_asset(1.0) .intp_order_latency(latency_data) .power_prob_queue_model(3) .no_partial_fill_exchange() .trading_value_fee_model(-0.00005, 0.0007) .tick_size(0.1) .lot_size(0.001) .roi_lb(roi_lb) .roi_ub(roi_ub) ) hbt = ROIVectorMarketDepthBacktest([asset]) recorder = Recorder(1, 60_000_000) half_spread = 0.0003 # a ratio relative to the fair price skew = half_spread / 20 interval = 100_000_000 # in nanoseconds. 100ms order_qty_dollar = 50_000 max_position_dollar = order_qty_dollar * 20 grid_num = 5 grid_interval = 0.0003 # a ratio relative to the fair price apt_mm( hbt, recorder.recorder, half_spread, skew, precompute_data, interval, order_qty_dollar, max_position_dollar, grid_num, grid_interval, roi_lb, roi_ub ) hbt.close() recorder.to_npz('stats/underlying_btcfdusd_return_5m_202502.npz') ``` ```text CPU times: user 1h 31min 38s, sys: 2min 56s, total: 1h 34min 34s Wall time: 1h 8s ``` -------------------------------- ### Configure and Run Market Making Backtest (APT) - Second Run Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Market Making with Alpha - APT.ipynb Configures and runs another market making backtest with different ROI bounds and grid settings. This demonstrates parameter tuning for the APT model. ```python %%time roi_lb = 50000 roi_ub = 150000 latency_data = [] date = start_date while date <= end_date: latency_data.append('latency/order_latency_{}.npz'.format(date.strftime('%Y%m%d'))) date += datetime.timedelta(days=1) data = [] date = start_date while date <= end_date: data.append('data2/btcusdt_{}.npz'.format(date.strftime("%Y%m%d"))) date += datetime.timedelta(days=1) asset = ( BacktestAsset() .data(data) .initial_snapshot('data2/btcusdt_20241231_eod.npz') .linear_asset(1.0) .intp_order_latency(latency_data) .power_prob_queue_model(3) .no_partial_fill_exchange() .trading_value_fee_model(-0.00005, 0.0007) .tick_size(0.1) .lot_size(0.001) .roi_lb(roi_lb) .roi_ub(roi_ub) ) hbt = ROIVectorMarketDepthBacktest([asset]) recorder = Recorder(1, 60_000_000) half_spread = 0.0003 # a ratio relative to the fair price skew = half_spread / 20 interval = 100_000_000 # in nanoseconds. 100ms order_qty_dollar = 50_000 max_position_dollar = order_qty_dollar * 20 grid_num = 5 ``` -------------------------------- ### Configure and Run Market Making Backtest (APT) Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Market Making with Alpha - APT.ipynb Sets up and runs a market making backtest using the APT model. This involves defining assets, latency, fees, and simulation parameters. ```python %%time roi_lb = 10000 roi_ub = 90000 latency_data = [] date = start_date while date <= end_date: latency_data.append('latency/order_latency_{}.npz'.format(date.strftime('%Y%m%d'))) date += datetime.timedelta(days=1) data = [] date = start_date while date <= end_date: data.append('data2/btcusdt_{}.npz'.format(date.strftime("%Y%m%d"))) date += datetime.timedelta(days=1) asset = ( BacktestAsset() .data(data) .initial_snapshot('data2/btcusdt_20240831_eod.npz') .linear_asset(1.0) .intp_order_latency(latency_data) .power_prob_queue_model(3) .no_partial_fill_exchange() .trading_value_fee_model(-0.00005, 0.0007) .tick_size(0.1) .lot_size(0.001) .roi_lb(roi_lb) .roi_ub(roi_ub) ) hbt = ROIVectorMarketDepthBacktest([asset]) recorder = Recorder(1, 60_000_000) half_spread = 0.0003 # a ratio relative to the fair price skew = half_spread / 20 interval = 100_000_000 # in nanoseconds. 100ms order_qty_dollar = 50_000 max_position_dollar = order_qty_dollar * 20 grid_num = 1 grid_interval = hbt.depth(0).tick_size apt_mm( hbt, recorder.recorder, half_spread, skew, precompute_data, interval, order_qty_dollar, max_position_dollar, grid_num, grid_interval, roi_lb, roi_ub ) hbt.close() recorder.to_npz('stats/underlying_btcfdusd_return_5m.npz') ``` -------------------------------- ### Iterate Order Values with has_next() and get() Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/reference/backtester.md Use `has_next()` to check for the next element and `get()` to retrieve it. Note that `has_next()` advances the iterator internally, so it should not be used solely for checking existence. ```python values = order_dict.values() while values.has_next(): order = values.get() # Do what you need with the order. ``` -------------------------------- ### Binance Futures Raw Feed File Format Example Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/reference/hftbacktest.data.utils.binancefutures.md This is an example of the raw Binance Futures feed stream file format, showing local timestamps and JSON data for different streams. ```text local_timestamp raw_stream 1660228023037049 {"stream":"btcusdt@depth@0ms","data":{"e":"depthUpdate","E":1660228023941,"T":1660228023931,"s":"BTCUSDT","U":1801732831593,"u":1801732832589,"pu":1801732831561,"b":[["2467.10","0.000"],["12006.00","0.001"],["24427.70","4.350"],["24620.30","0.172"],["24644.00","44.832"],["24645.40","0.203"],["24652.80","4.900"],["24664.10","4.279"],["24666.50","0.554"],["24666.80","6.764"],["24668.70","7.428"],["24670.90","2.000"],["24671.00","0.000"],["24672.70","0.000"],["24688.30","0.000"]],"a":[["24653.60","0.000"],["24669.80","0.000"],["24670.20","0.000"],["24670.70","0.000"],["24670.90","0.000"],["24671.00","20.812"],["24672.10","0.000"],["24672.30","0.001"],["24674.60","1.520"],["24674.80","0.000"],["24684.20","4.519"],["24684.30","0.202"],["24685.00","0.937"],["24690.90","4.827"],["24693.60","1.500"],["24729.10","0.171"]]} 1660228023038319 {"stream":"btcusdt@depth@0ms","data":{"e":"depthUpdate","E":1660228023977,"T":1660228023966,"s":"BTCUSDT","U":1801732832805,"u":1801732834115,"pu":1801732832589,"b":[["2467.10","0.008"],["24643.00","4.457"],["24656.30","0.010"],["24657.70","0.005"],["24658.80","1.000"],["24658.90","1.500"],["24659.50","3.781"],["24659.70","1.806"],["24659.90","0.105"],["24660.60","0.787"],["24666.30","5.033"],["24666.40","0.012"],["24666.50","0.556"],["24668.70","7.426"],["24668.90","0.000"],["24670.90","2.535"],["24680.00","0.000"],["24688.30","0.000"]],"a":[["24653.60","0.000"],["24670.10","0.000"],["24670.60","0.000"],["24670.70","0.000"],["24670.90","0.000"],["24671.00","20.642"],["24672.00","0.000"],["24672.10","0.000"],["24673.50","0.145"],["24673.60","1.567"],["24674.50","3.746"],["24674.60","1.520"],["24678.30","1.304"],["24678.40","0.001"],["24678.80","0.546"],["24678.90","0.002"],["24681.60","0.020"],["24681.70","0.613"],["24681.90","0.077"],["24682.10","3.000"],["24682.20","0.000"],["24683.70","0.163"],["24683.80","4.162"],["24684.00","1.227"],["24684.20","4.519"],["24684.30","0.202"],["24684.90","1.331"],["24685.70","0.156"],["24685.80","0.325"],["24686.70","0.648"],["24692.60","0.040"],["24700.00","47.420"],["24729.10","0.006"]]} 1660228023043260 {"stream":"btcusdt@trade","data":{"e":"trade","E":1660228023980,"T":1660228023973,"s":"BTCUSDT","t":2691833663,"p":"24670.90","q":"0.022","X":"MARKET","m":true}} 1660228023052991 {"stream":"btcusdt@trade","data":{"e":"trade","E":1660228023991,"T":1660228023983,"s":"BTCUSDT","t":2691833664,"p":"24671.00","q":"0.001","X":"MARKET","m":false}} 1660228023071108 {"stream":"btcusdt@depth@0ms","data":{"e":"depthUpdate","E":1660228024010,"T":1660228024002,"s":"BTCUSDT","U":1801732834136,"u":1801732835323,"pu":1801732834115,"b":[["2467.10","0.000"],["12006.00","0.000"],["24599.40","0.641"],["24603.20","0.104"],["24625.50","0.152"],["24645.20","0.476"],["24646.80","0.081"],["24652.60","0.254"],["24664.10","4.279"],["24666.50","0.878"],["24668.80","0.004"],["24670.90","2.513"],["24688.30","0.000"],["24787.00","0.000"]],"a":[["24653.60","0.000"],["24668.10","0.000"],["24668.70","0.000"],["24669.50","0.000"],["24669.80","0.000"],["24670.00","0.000"],["24670.60","0.000"],["24670.70","0.000"],["24670.90","0.000"],["24671.00","20.641"],["24672.20","0.000"],["24672.30","0.001"],["24673.50","0.040"],["24673.90","0.105"],["24674.70","2.139"],["24674.80","0.000"],["24683.70","0.963"],["24683.90","0.009"],["24685.70","0.556"],["24709.30","0.254"],["24723.80","0.000"],["24728.30","0.193"],["24729.50","4.477"],["24739.40","0.807"],["24743.20","0.235"],["24795.00","0.130"]]} ``` -------------------------------- ### Initialize Backtest Environment Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Working with Market Depth and Trades.ipynb Sets up a HashMapMarketDepthBacktest instance with a single asset, configuring its data, initial snapshot, fees, and latency. The `print_3depth` function is then called to display market data. ```python from hftbacktest import BacktestAsset, HashMapMarketDepthBacktest asset = ( BacktestAsset() .data(btcusdt_20240809) .initial_snapshot(btcusdt_20240808_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) ) hbt = HashMapMarketDepthBacktest([asset]) print_3depth(hbt) _ = hbt.close() ``` -------------------------------- ### Get Order by ID Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/reference/backtester.md Retrieves a specific order using its unique order ID. ```APIDOC ## get(order_id) ### Description Retrieves an order by its unique identifier. ### Parameters #### Path Parameters - **order_id** (uint64) – Required - The ID of the order to retrieve. ### Returns Order with the specified order ID; None if it does not exist. ### Return type: [*Order*](#hftbacktest.order.Order) | None ``` -------------------------------- ### Backtesting Setup Source: https://github.com/nkaz001/hftbacktest/blob/master/examples/Probability Queue Models.ipynb This function sets up the backtesting environment for a given asset. It loads historical data, calculates initial mid-prices, and configures the backtest asset with various parameters like fees, tick size, and lot size. ```python def backtest(args): asset_name, asset_info, model = args # Obtains the mid-price of the assset to determine the order quantity. snapshot = np.load('data/{}_20230730_eod.npz'.format(asset_name))['data'] best_bid = max(snapshot[snapshot['ev'] & BUY_EVENT == BUY_EVENT]['px']) best_ask = min(snapshot[snapshot['ev'] & SELL_EVENT == SELL_EVENT]['px']) mid_price = (best_bid + best_ask) / 2.0 latency_data = np.concatenate( [np.load('latency/live_order_latency_{}.npz'.format(date))['data'] for date in range(20230731, 20230732)] ) asset = ( BacktestAsset() .data(['data/{}_{}.npz'.format(asset_name, date) for date in range(20230731, 20230732)]) .initial_snapshot('data/{}_20230730_eod.npz'.format(asset_name)) .linear_asset(1.0) .intp_order_latency(latency_data) .no_partial_fill_exchange() .trading_value_fee_model(-0.00005, 0.0007) .tick_size(asset_info['tick_size']) .lot_size(asset_info['lot_size']) ``` -------------------------------- ### Get ask quantity at a specific tick Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/reference/backtester.md Returns the quantity at the ask market depth for a given price in ticks. ```APIDOC ## ask_qty_at_tick(price_tick) ### Description Returns the quantity at the ask market depth for a given price in ticks. ### Parameters #### Path Parameters - **price_tick** (*int64*) – Price in ticks. ### Returns The quantity at the specified price. ### Return type float64 ``` -------------------------------- ### Get bid quantity at a specific tick Source: https://github.com/nkaz001/hftbacktest/blob/master/docs/reference/backtester.md Returns the quantity at the bid market depth for a given price in ticks. ```APIDOC ## bid_qty_at_tick(price_tick) ### Description Returns the quantity at the bid market depth for a given price in ticks. ### Parameters #### Path Parameters - **price_tick** (*int64*) – Price in ticks. ### Returns The quantity at the specified price. ### Return type float64 ```