Skip to content

Commit

Permalink
docs: update the examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
nkaz001 committed Aug 13, 2024
1 parent 0659f1e commit 358ff6f
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 276 deletions.
121 changes: 66 additions & 55 deletions examples/example.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import numpy as np

from numba import njit

from hftbacktest import HftBacktest, GTX, BUY, SELL, Linear, IntpOrderLatency, SquareProbQueueModel
from hftbacktest import BacktestAsset, HashMapMarketDepthBacktest, BUY, SELL, GTX, LIMIT


@njit
def market_making_algo(hbt):
# in microseconds
while hbt.elapse(0.1 * 1e6):
hbt.clear_inactive_orders()
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)

"""
You can find the core ideas from the following articles.
Expand All @@ -27,94 +33,99 @@ def market_making_algo(hbt):
# in hft, it could be a measurement of short-term market movement such as high - low of the last x-min.
volatility = 0
# delta risk, it also can be a combination of several risks.
risk = (c + volatility) * hbt.position
position = hbt.position(asset_no)
risk = (c + volatility) * position
half_spread = (c + volatility) * hs

max_notional_position = 1000
notional_qty = 100

mid = (hbt.best_bid + hbt.best_ask) / 2.0
depth = hbt.depth(asset_no)

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

# fair value pricing = mid + a * forecast
# fair value pricing = mid_price + a * forecast
# or underlying(correlated asset) + adjustment(basis + cost + etc) + a * forecast
# risk skewing = -b * risk
new_bid = mid + a * forecast - b * risk - half_spread
new_ask = mid + a * forecast - b * risk + half_spread
new_bid = mid_price + a * forecast - b * risk - half_spread
new_ask = mid_price + a * forecast - b * risk + half_spread

new_bid_tick = round(new_bid / hbt.tick_size)
new_ask_tick = round(new_ask / hbt.tick_size)
new_bid_tick = np.round(new_bid / tick_size)
new_ask_tick = np.round(new_ask / tick_size)

new_bid = new_bid_tick * hbt.tick_size
new_ask = new_ask_tick * hbt.tick_size
order_qty = round(notional_qty / mid / hbt.lot_size) * hbt.lot_size
order_qty = np.round(notional_qty / mid_price / lot_size) * lot_size

# Elapse a process time
if not hbt.elapse(.05 * 1e6):
# Elapses a process time.
if not hbt.elapse(1_000_000) != 0:
return False

last_order_id = -1
update_bid = True
update_ask = True
for order in hbt.orders.values():
orders = hbt.orders(asset_no)
order_values = orders.values()
while order_values.has_next():
order = order_values.get()
if order.side == BUY:
if round(order.price / hbt.tick_size) == new_bid_tick \
or hbt.position * mid > max_notional_position:
if order.price_tick == new_bid_tick or position * mid_price > max_notional_position:
update_bid = False
elif order.cancellable or hbt.position * mid > max_notional_position:
hbt.cancel(order.order_id)
elif order.cancellable or position * mid_price > max_notional_position:
hbt.cancel(asset_no, order.order_id, False)
last_order_id = order.order_id
if order.side == SELL:
if round(order.price / hbt.tick_size) == new_ask_tick \
or hbt.position * mid < -max_notional_position:
if order.price_tick == new_ask_tick or position * mid_price < -max_notional_position:
update_ask = False
if order.cancellable or hbt.position * mid < -max_notional_position:
hbt.cancel(order.order_id)
if order.cancellable or position * mid_price < -max_notional_position:
hbt.cancel(asset_no, order.order_id, False)
last_order_id = order.order_id

# It can be combined with grid trading strategy by sumitting multiple orders to capture the better spread.
# Then, it needs a more sophiscated logic to efficiently maintain resting orders in the book.
# 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 on a given price, use new_bid_tick as order Id.
hbt.submit_buy_order(new_bid_tick, new_bid, order_qty, GTX)
last_order_id = new_bid_tick
# 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, order_qty, GTX, LIMIT, False)
last_order_id = order_id
if update_ask:
# There is only one order on a given price, use new_ask_tick as order Id.
hbt.submit_sell_order(new_ask_tick, new_ask, order_qty, GTX)
last_order_id = new_ask_tick
# 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, order_qty, GTX, LIMIT, False)
last_order_id = order_id

# All order requests are considered to be requested at the same time.
# Wait until one of the order responses is received.
# Waits until one of the order responses is received.
if last_order_id >= 0:
if not hbt.wait_order_response(last_order_id):
# 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

print(hbt.local_timestamp, mid, hbt.position, hbt.position * mid + hbt.balance - hbt.fee)
return True


if __name__ == '__main__':
# data file
# https://github.com/nkaz001/collect-binancefutures

# This backtest assumes market maker rebates.
# https://www.binance.com/en/support/announcement/binance-upgrades-usd%E2%93%A2-margined-futures-liquidity-provider-program-2023-04-04-01007356e6514df3811b0c80ab8c83bf

latency_data1 = np.load('order_latency_20220831.npz')['data']
latency_data2 = np.load('order_latency_20220901.npz')['data']
latency_data = np.concatenate([latency_data1, latency_data2], axis=0)

hbt = HftBacktest(
[
'../../btcusdt_20220831.npz',
'../../btcusdt_20220901.npz'
],
tick_size=0.1,
lot_size=0.001,
maker_fee=-0.00005,
taker_fee=0.0007,
order_latency=IntpOrderLatency(latency_data),
queue_model=SquareProbQueueModel(),
asset_type=Linear,
snapshot='../../btcusdt_20220830_eod.npz'
asset = (
BacktestAsset()
.data([
'data/btcusdt_20220831.npz',
'data/btcusdt_20220901.npz',
])
.initial_snapshot('data/btcusdt_20220830_eod.npz')
.linear_asset(1.0)
.intp_order_latency([
'latency/live_order_latency_20220831.npz',
'latency/live_order_latency_20220901.npz',
])
.power_prob_queue_model(2.0)
.no_partial_fill_exchange()
.trading_value_fee_model(-0.00005, 0.0007)
.tick_size(0.1)
.lot_size(0.001)
)
hbt = HashMapMarketDepthBacktest([asset])
market_making_algo(hbt)
221 changes: 0 additions & 221 deletions examples/simple_two_sided_quote.ipynb

This file was deleted.

0 comments on commit 358ff6f

Please sign in to comment.