-
Notifications
You must be signed in to change notification settings - Fork 951
Home
Market making is a trading strategy where the trader simultaneously places both buy and sell orders in an attempt to profit from the bid-ask spread. Market makers stand ready to both buy and sell from other traders, thus providing liquidity to the market.
The strategy is appealing to traders because it doesn't require traders to take a directional view of the market - there's money to be made when the market goes up and when the market goes down. It's also heavily incentivized by exchanges looking for liquidity and volume - many exchange operators will pay you to make markets on their exchanges.
Let's consider a simplified market. Let's say there are three traders: Alice, Bob, and Tim. Alice is looking to sell some of her Bitcoins and Bob is looking to convert some of his USD into Bitcoin. Neither one are savvy about markets or cryptocurrency - they use Bitcoin, but aren't going to lose sleep over trying to get the absolute best prices. Tim is operating Tribeca. Now lets say that the price BTC to USD is $100. Tim could configure Tribeca to send in a buy order for 1 BTC at $95 and a sell order for 1 BTC at $105. Tim would hope that Bob would come along and buy the offered sell order at $105 and Alice would come and sell BTC at $95 - netting Tim $10.
But what if that doesn't happen? What if the price of BTC/USD jumps to $103? Now Tim's buy order seems really uncompetitive at $95 - Alice doesn't want to sell for that little. And Bob could get a pretty good deal by getting the BTC at only two extra dollars. To prevent this scenario, Tim's Tribeca would readjust the orders by cancelling the $95-$105 orders and placing a new set of orders - also known as making a market - at $98-$108.
Like in any market these days, Bob and Alice probably aren't humans clicking buttons. They certainly aren't humans shouting on a floor in lower Manhattan. More likely, they are also computerized algorithms capable of placing orders in milliseconds. To survive as a market maker, you need to be faster than those algorithms to make a profit.
As previously mentioned, market making is really the art of figuring out the price of something, then making a market around that price. So how do we know what is the real price of Bitcoin? Well... we don't. And of course the price of Bitcoin now might be radically different than the price in a day, in an hour, or even in a second from now. The best we can do is to build an estimate, or fair value, of the price of Bitcoin. In Tribeca, we consume the market data from the exchange we are sending orders into as a starting point. That includes the best bids and offers and most recent trades (aka market trades) by other participants in the market.
From our fair value, we then need to make a market around that price. Back to our hypothetical example with Bob and Alice: we could make our market as $95-$105, we could have also made it $99.99-$101.01, or we could have also done $47-$332.21. So how do we decide? That's where the quoting parameters come into play. Those parameters dictate how wide of a market to make (wide=askPrice-bidPrice) and what size we want our quotes in the market to be. The procedure for coming up with profitable parameters is both an art and a science - there is no one size fits all formula.
When Tribeca figures out a suitable market, Tribeca will then send in the buy and sell orders. Hopefully it's able to buy for less then sell for more, and repeat many times per day. Sometimes that's not always the case - sometimes there are genuinely more buyers than sellers for the prices you are setting. Often this comes when the market is moving very fast in one direction. Luckily, Tribeca will prevent you from selling too fast without finding corresponding buyers and will stop sending orders in the imbalanced side.
The code is organized into 3 layers.
-
Engine layer - The brains of the application. Portion of the code responsible for synthesizing market data, open order status, position, fees, trades, safety information and converting that into a quote to send to the exchange. This is the portion of the code which calculates a fair value (
FairValueEngine
) and generates quotes (QuotingEngine
) -
Adapter layer - The engine layer should have no idea about the individual quirks of the exchanges. The engine layer uses the adapter layer to carry out its bidding. The adapter layer also has no idea that it is being used in a manner to make markets. In theory, the adapter layer code and the gateway layer code could be divorced from the Engine layer and we could build a technical analysis or latency arbitrage bot, instead. The adapter layer also contains all the state reported by the gateways.
-
Gateway layer - Each exchange has their own API for interacting with the exchange. All of that business is hidden behind 4 different interfaces:
-
IMarketDataGateway
: Handles order book updates and market trade updates. -
IOrderEntryGateway
: Send and cancel orders and handle updates to the orders. -
IPositionGateway
: Pulls in the latest position (how much BTC and USD do I have?) information -
IExchangeDetailsGateway
: Read-only information describing naming and exchange fee structure.
Gateways are ideally stateless (some state may be needed in order to perform exchange-specific functionality) and are mostly translation layers between exchange APIs and the Tribeca API.
Navigate to the Web UI as described in the install process. You should see a screen like:
-
Market Data and Quotes - this is perhaps the most important screen in the app.
-
The top row in blue with "q" is the quote that you generate via the Quoting Parameters supplied. If the text is grey, the generated quotes are not in the market, and green when they are.
-
"FV" is the fair value price calculated by Tribeca as the starting point for the generated quote.
-
The "mkt" rows are the best bids and offers on the exchange you are connected to.
-
-
Trades - Trades done by your exchange account. "side" is the side which your order was sent as. "val" is the total value of the trade, which is price * size +/- total exchange fee
-
Market Trades - Trades done by all participants in the market. "ms" is the side that was the make side (provided liquidity). The columns starting with "q" are your quotes at the time of the trade, the columns starting with "m" are the best bid and offer information at the time of the trade.
-
Quoting Parameters - All of the parameters needed to generate a quote. See the section "How do I control Tribeca's quotes?" for each field's description.
-
Positions - Shows holdings of each currency pair you are using.
-
Order List - Shows order statuses of each order sent to the exchange.
- "Cxl" - clicking the red button will attempt to cancel the order.
In the web UI, there are two rows of panels with cryptic looking names and editable textboxes. Those are the quoting parameters, the knobs which we can turn to affect how Tribeca will trade.
-
mode
- Sets the quoting mode-
Join
- Sets our quote to be at the best bid and the best offered price, If the BBO is narrower thanwidth
, set our bid quote atFV - width / 2
and ask quote atFV + width / 2
. -
Top
- Same asJoin
, but if the code can better the best bid or offer by a penny while respecting thewidth
, set that as the quote so we will then be at the top of the market. -
Mid
- Set our bid quote atFV - width / 2
and ask quote atFV + width / 2
-
Inverse Join
- Set the quote at the BBO if the BBO is narrower thanwidth
, otherwise make the quote so wide that no one will trade with it. -
Inverse Top
- Same asInverse Join
but make our orders jump to the very top of the order book. -
PingPong
- Same asTop
but always respect the calculatedwidth
from the last sold or boughtsize
.
-
-
fv
- Sets the fair value calculation mode-
BBO
-FV = ([best bid price] + [best ask price])/2.0
-
wBBO
-FV = ([best bid price]*[best ask size] + [best ask price]*[best bid size])/([best ask size] + [best bid size])
-
-
apMode
-
Off
- Tribeca will not try to automatically manage positions. -
EwmaBasic
- Tribeca will use a 200 minute and 100 minute exponential weighted moving average calculation to buy up BTC when the 100 minute line crosses over the 200 minute line, and sell BTC when the reverse happens. The values of 100mins and 200mins are currently not exposed in the UI, but are represented in the code asshortEwma
andlongEwma
.
-
-
width
- Minimum width of our quote in USD (ex. a value of .3 is 30 cents). With the exception for whenapr
is checked and the system is aggressively rebalancing positions after they get out of whack,width
shall never be violated. -
size
- Maximum size of our quote in BTC (ex. a value of 1.5 is 1.5 bitcoins). With the exception for whenapr
is checked and the system is aggressively rebalancing positions after they get out of whack,size
shall never be violated. -
tbp
- Only used whenapMode
isOff
. Sets a static "Target Base Position" for Tribeca to stay near. In off auto-position mode, Tribeca will still try to respectpDiv
and not make your position fluctuate by more than that value. So if you have 10 BTC to trade, settbp = 3
, setapMode = Off
, andpDiv = 1
, your holding of BTC will never be less than 2 or greater than 4. -
pDiv
- If your "Target Base Position" diverges more from this value, Tribeca will stop sending orders to stop too much directional trading. So if you have 10 BTC to trade, "Target Base Position" is reporting 5, andpDiv
is set to 3, your holding of BTC will never be less than 2 or greater than 8. -
ewma?
- Use a 100 minute EWMA smoothed line of the price to not send -
apr?
- If you're in a state where Tribeca has stopped sending orders because your position has diverged too far from Target Base Position, this setting will much more aggressively try to fix that discrepancy by placing orders much larger thansize
and at prices much more aggressive thanwidth
normally allows. It's a bit risky to use this setting. -
trds
- Often, only buying or selling many times in a short timeframe indicates that there is going to be a price swing.trds
and/sec
are highly related: If you do more thantrds
buy trades in/sec
seconds, Tribeca will stop sending more buy orders until either/sec
seconds has passed, or you have sold enough at a higher cost to make all those buy orders profitable. The number of trades is reported by side in the UI; "BuyTS", "SellTS", and "TotTS". If "BuyTS" goes abovetrds
, Tribeca will stop sending buy orders, and the same for sells. For example, iftrds
is 2 and/sec
is 1800 (half an hour):
Time | Side | Price | Size | BuyTS | SellTS | Notes |
---|---|---|---|---|---|---|
12:00:01 | Buy | 10 | 1 | 1 | 0 | |
12:00:02 | Buy | 10 | 0.5 | 1.5 | 0 | Partial fills of size get counted fractionally |
12:00:03 | Sell | 11 | 0.75 | 0.75 | 0 | Sell for more decrements the imbalance |
12:00:05 | Sell | 5 | 0.75 | 0.75 | 0 | Sell for less than the other buys doesn't help |
12:00:06 | Buy | 10 | 0.5 | 1.75 | 0 | |
12:00:07 | Buy | 10 | 0.5 | 2.75 | 0 | Stop sending buy orders until 12:30:07! |
-
/sec
- seetrds
Lets say that you have a great idea about how to profitably make markets and are comfortable getting your hands dirty in some TypeScript. The steps are quite easy
- Create a class implementing
QuoteStyle
found insrc/service/quoting-styles/helpers.ts
. As part of implementing the interface, you'll need to create a new enum member forQuotingMode
in models.ts. Inside that class you can create any sort of logic to create a two-sided market, or return null to signify that there should be no quote in the market. The interface gives you:
a. The latest order book depth of the market. On most exchanges, this is the best 3 price levels. Individual orders are not supported since not all exchanges support that functionality. Last trades in the market are also not yet provided (though reasonably should in the future).
b. The calculated fair value.
c. The current quoting parameters, viewable in the web UI.
-
Install the new class alongside the provided list of modes in the
QuotingStyleRegistry
inmain.js
. -
Rebuild and restart tribeca.
Tribeca is packaged with a backtesting mode.
I am an Ekonobi Developer.