This is a follow-up to our API guide. Note that this is for educational purposes only. Please don’t take any of this as financial advice.
If you’ve read our market making article, you may be excited to take the next step in understanding the strategy. But what better way to learn than by doing? In that spirit, we’ve open-sourced an example market maker (“EMM”) bot to teach you in practice.
In this tutorial, we assume that you are already familiar with using git and terminals. If this is not you, but you still want to try Kollider out, let us know! We’ll help you get started regardless. By the way, we’ve talked about how trading manually is still a viable way to trade, so you don’t need a bot to get started.
Getting the Code
To get started, you need to clone the example_market_maker code. You’ll need python and pip (version >= 3.56) to run the script. Once you’ve cloned it, go to the maker’s directory and run pip install:cd example_market_maker
pip install -r requirements.txt
This will add requirements including Kollider’s websocket client.
Anatomy of the Example Market Maker
If you haven’t yet, quickly glance through the simplified concept behind market making, as that’ll help you pick up the rest of this tutorial more quickly.
The EMM is primarily composed of four moving parts:
- Connecting to Kollider’s websocket to get product and market data
- Calculating a reference price from that data
- Calculating our order prices
- Placing our orders (note: for safety reasons, we set the default to just “dry run” and show you the order quantity, prices, and side that it would have placed)
Let’s dig deeper.
Connecting and Getting Data
Before getting started, you need to enter your API credentials at the top of
If you don’t have an API key or secret yet, please follow the instructions on this page.
If you run the default settings of EMM (after API credentials, of course!), you should already get some data through the websocket. So, let’s explore some of the code that makes that happen.
Once you run
pip install -r requirements.txt, pip will download Kollider’s websocket client, which
MarketMaker subclasses.from kollider_api_client.ws import *
The current version of EMM will subscribe to orderbook data, the index price, and the state of your existing positions (none initially for your account). To see this, you can navigate to
main.py and check out the subscribe and fetch lines of code.# Subscribing to index prices.
MarketMaker overrides the method
on_message to handle and parse all of the data coming from the websocket. If you wanted to handle some messages differently, you’d want to follow
parse_msg(..) and alter the code there.def on_message(self, _, msg):
Calculating Reference Price
Following the framework given in Demystifying Market Making, the market maker centres around a
reference_price. In EMM, we are calculating this in the
update_start_price() methoddef update_start_prices(self):
# You could change this to your own reference price.
The reference prices are created by calculator classes. Currently, there are two calculations available: (1) one that uses the index price; and (2) another that uses the mid-price of the orderbook.
You can find them in the
src/calculatorsdirectory. You can add your own there. They will generally follow this interface, but they don’t need to strictly adhere to that.class PriceCalc(object): # Calculates a reference price.
self.is_done = False
self.price = None def is_ready(self):
return self.is_done def get_price(self):
def update_price(self, exchange_state: ExchangeState):
Orders are created in two main steps. The first is to calculate the “start prices”, meaning the best bid and ask prices that are going to be closest to the centre of the market. That largely happens in
update_start_prices(..) where we calculate the
reference price and finally the start prices by adding an offset to that. According to the market maker article we are following, we would add a lean. This would happen in this same method, but we leave that exercise to you. It is optional and is not currently in the EMM.
Lastly, we determine our actual order prices and quantities within the
create_orders method. This is controlled by the
max_short_pos_btc settings in
config.yaml and is used in the following code in
create_orders:long_btc_remaining = self.long_btc_remaining()
short_btc_remaining = self.short_btc_remaining()
And then “builds the order” inside the
get_order_price methods by applying the
stack_pct as a multiple of the index from each side’s start prices.
Note that you’ll see rounding like this on order prices because, like most exchanges, it is critical for the exchange to receive prices that actually match the prices separated by tick size of that product:order_price = toNearest(start_price + index * start_price * conf[“trading_params”][“stack_pct”], tick_size)
Dry Run and Other Settings
As we have mentioned, this project is meant for educational purposes. With that, we have added a dry run flag in
config.yamlenable_dry_run: true # dry run will not send order and only print them to screen
Setting that flag to
true prevents the EMM from sending out orders, and instead it will print the orders it would have sent. For example:
Dry run. Would place the following orders:Ask 70 @ price 59100.5
Ask 60 @ price 59041.5
Ask 50 @ price 58982.5
Bid 50 @ price 58279.0
Bid 60 @ price 58220.5
Bid 70 @ price 58162.0
Set It and Turn It On
Now that you have added your API credentials and set the dry run to true in
config.yaml, you are ready to run the EMM. You can do so from the project’s root folder by runningpython src/main.py
If the dry run is set to false, the EMM will attempt to place orders. This part largely happens in the
converge_orders method. This takes the order list created in the
create_orders method and determines whether to send new or amend previously existing orders if there has been more than a
config.yaml) change in prices.abs((desired_order.price / order.price) — 1) > trading_params[“relist_tolerance”]
Trading Live and Moving Forward
(NOTE: the settings shown below are not meant to be a recommendation for the reader, but just to show which parameters we are talking about.)
We’ve set it to not trade by default (i.e., dry run is enabled) and let you see what orders the bot would place first. If you do set dry run to false, it would probably make sense to keep the spreads wide by increasing these settings:min_spread: 0.02
Furthermore, it would make sense to lower the capital and position risk settings to minimize any potential losses as you continue to learn:start_order_size: 10
If you’re looking for ideas on how to continue expanding the EMM for your own purposes, one potential idea is to look at how others think of market making. Our EMM follows our market making article, and you can start with that by adding a lean parameter and algorithm, but there could be a multitude of ways you can vary up your MM education. You can also check out the other articles in our blog to start getting ideas of how to maybe backtest your EMM and/or adapt it to be a spread trade.
Know anyone else interested in learning about bitcoin, Lightning, and trading? Follow us on Twitter and help us share the word.