Market Making Replay (part 2; agent based quant infrastructure)
A few days ago, we released our market data replay agents:
Note that there are just 2 days remaining on our quantpylib repo pass:
We also released template code for multi-exchange market making using quantpylib’s oms and data feed:
In this post, we want to demonstrate how simple it is to perform a event-driven backtest starting from the market maker code. Now, here is the original market maker code:
Essentially, there is no change to the code from previous post. We did add a few lines to save some data to the disk. I want to show you precisely how simple it is to run a backtest:
change these lines of code:
oms = OMS(gateway=gateway)
feed = Feed(gateway=gateway)
play = lambda : asyncio.sleep(100)
to
simulated = True
if simulated:
from quantpylib.hft.mocks import Replayer
quoted_trades,market_trades,quoted_book = load_pickle('data.pickle')
l2_data = {
exc:{configs[exc]['quote_tickers'][0]:quoted_book.buffer_as_list()}
}
trade_data = {
exc:{
configs[exc]['quote_tickers'][0]:quoted_trades.get_buffer(),
configs[exc]['market']:market_trades.get_buffer()
}
}
replayer = Replayer(
l2_data = l2_data,
trade_data = trade_data,
gateway= gateway
)
oms = replayer.get_oms()
feed = replayer.get_feed()
play = lambda : replayer.play()
else:
oms = OMS(gateway=gateway)
feed = Feed(gateway=gateway)
play = lambda : asyncio.sleep(100)
That’s all! The orderbook data format and trade data format is as simple as
{exc:{ticker:[{ts,b,a},...]}}
{exc:{ticker:[(ts,price,sz,dir),...]}}
Feeding the tick data to the replayer class, and then using the OMS and Feed from the replayer, we don’t have to make any changes to the market maker code. (by the way, the code is in the quantpylib/scripts/ folder in the repo. Or - follow the tutorial here: https://hangukquant.github.io/scripts/market_making/)
We will add more explanations and details with follow up posts.
At the end of the replayer, when we print this:
pprint(await oms.get_balance(exc=exc))
pprint(oms.orders_peek(exc=exc).as_list())
we get outputs like this:
{'equity_total': 10000.00433675,
'margin_maintenance': None,
'margin_total': None,
'unrealized_pnl': None}
[{'amount': Decimal('-480.0'),
'cloid': '60056970db3db0e57c5cf84a51b1a74f',
'exc': 'bybit',
'filled_sz': Decimal('2.628000000000000039961089996'),
...
'sl': None,
'ticker': 'AERGOUSDT',
'tif': None,
'timestamp': 1727720433556,
'tp': None}]
Now, let us talk about what how the replayer backtest is an improvement over our previous hft test logic.
allows for multiple tickers testing (previously one ticker, one exchange)
allows for cross exchange strategy testing
can define different latencies for different exchanges for different messaging channels (public/private feed)
accounts for a static queue position, improving previous `cross-to-fill`.
backtest and trading logic shares same codebase.
backtest follows contract trading rules of exchange if gateway is provided (price,lot precision etc)
For instance, for point 3 - in the previous backtester, we assumed zero latency. That is, an order submitted was immediately submitted to the matching engine - the local client and exchange server state were one and the same. In the enhancement, this distinction is made. For instance, an order cancel request may be unsuccessful due to request latency and be matched against trade arrival before cancel arrival. Both order submission and order acknowledgements should have delay, such that client/server states are distinct.
We can immediately see this from the example provided here. By playing around, you will notice that if you pass in different latencies from the default args:
you will get different orders filled/cancelled. This new architecture makes testing not only much easier, but also porting over to live trading smooth. Additionally, the agent based design means that we can make improvements to our testing accuracy simply by focusing on the individual mock agents, which is an improvement in the separation of concerns issue posed by our previous tester.
In the coming posts, we will add even more functionality, as well as bring over some of the nice graphics from old backtester class to the Replayer class.
quantpylib out. For annual subscribers, don’t forget to get your access:
or get the repo pass:
https://hangukquant.thinkific.com/courses/quantpylib
Cheerios~