Merge pull request #57 from bitshares/bsip33
Add BSIP 33: Maker Orders With Better Prices Take Precedence
This commit is contained in:
commit
e12c618a3f
1 changed files with 136 additions and 0 deletions
136
bsip-0033.md
Normal file
136
bsip-0033.md
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
BSIP: 0033
|
||||||
|
Title: Maker Orders With Better Prices Take Precedence
|
||||||
|
Author: Abit More <https://github.com/abitmore>
|
||||||
|
Status: Draft
|
||||||
|
Type: Protocol
|
||||||
|
Created: 2018-02-17
|
||||||
|
Discussion: https://github.com/bitshares/bitshares-core/issues/625,
|
||||||
|
https://github.com/bitshares/bitshares-core/issues/453
|
||||||
|
Replaces: -
|
||||||
|
Worker: To be done
|
||||||
|
|
||||||
|
# Abstract
|
||||||
|
|
||||||
|
Currently, in BitShares, under certian circumstances, a taker order may be
|
||||||
|
matched with a maker order which is not "on the top" of the order book.
|
||||||
|
This behavior is unexpected and irritating for users.
|
||||||
|
|
||||||
|
This BSIP proposes a principle: always match taker orders with maker orders
|
||||||
|
with the best prices (aka on the top of the order book) first.
|
||||||
|
|
||||||
|
# Motivation
|
||||||
|
|
||||||
|
As expected, when matching taker limit orders with maker limit orders, the maker
|
||||||
|
limit orders with better prices will always be matched first.
|
||||||
|
|
||||||
|
For example, if trader A has a limit order selling 100 BTS at
|
||||||
|
0.1 USD per BTS, trader B has a limit order selling 100 BTS at 0.09 USD per BTS,
|
||||||
|
which means B's limit order has a better price for the opposite side to buy.
|
||||||
|
Now if trader C placed an order that buys 10 BTS at 0.105 USD per BTS, B's
|
||||||
|
limit order will take precedence, A's limit order won't be matched.
|
||||||
|
|
||||||
|
However, when there are (maker) margin call orders in the market which have met
|
||||||
|
the requirements that to be matched (able to be margin called), they always
|
||||||
|
take precedence over the (maker) limit orders on the same side, no matter
|
||||||
|
whether the limit orders provided better price.
|
||||||
|
|
||||||
|
For example, if trader A's margin call order is selling 100 BTS at no less than
|
||||||
|
0.1 USD per BTS, trader B has a limit order selling 100 BTS at 0.09 USD per BTS,
|
||||||
|
which means B's limit order has a better price for the opposite side to buy.
|
||||||
|
Now if trader C placed an order that buys 10 BTS at 0.105 USD per BTS, A's
|
||||||
|
margin call order will take precedence, B's limit order won't be matched. That
|
||||||
|
means C is forced to "buy high" when have chance to "buy low", which is
|
||||||
|
unexpected.
|
||||||
|
|
||||||
|
Users have been confused by this behavior, as discussed in [bitshares-core
|
||||||
|
issue #625](https://github.com/bitshares/bitshares-core/issues/625) and other
|
||||||
|
threads.
|
||||||
|
|
||||||
|
Another scenario is described in [Bitshares-core
|
||||||
|
issue #453](https://github.com/bitshares/bitshares-core/issues/453)
|
||||||
|
that sometimes a taker margin call order may be matched with a maker limit order
|
||||||
|
which is not on the top of the order book. This can be seen as a bug.
|
||||||
|
|
||||||
|
# Rationale
|
||||||
|
|
||||||
|
Always matching taker order (e.g. a buy) with a maker order which offered best
|
||||||
|
price (aka lowest ask), is a simpler rule which most users would understand
|
||||||
|
easily.
|
||||||
|
|
||||||
|
There is a parameter in price feed named MSSR, which stands for "maximum short
|
||||||
|
squeeze ratio". Maker price of margin call orders is MSSP, which stands for
|
||||||
|
"maximum short squeeze price", is calculated as `feed_price / MSSR`.
|
||||||
|
Note: `feed_price` here is in terms of debt/collateral, aka "how much debt per
|
||||||
|
collateral".
|
||||||
|
|
||||||
|
That said, the price that margin call orders are offering is MSSP. The prices
|
||||||
|
those limit orders are offering are the limit prices.
|
||||||
|
|
||||||
|
When placing a limit (e.g. buy) order with a price beyond the lowest sell,
|
||||||
|
the order is expected to "walk the book", matching each order on the opposite
|
||||||
|
side in turn, at that order's price, until the new limit order is completely
|
||||||
|
filled, or there is no more sell order matching its price.
|
||||||
|
|
||||||
|
To meet the expectation,
|
||||||
|
* firstly, we need to match the limit buy order with the limit sell orders
|
||||||
|
whose prices are lower than MSSP and prices can match the new order;
|
||||||
|
* then, if the new limit buy order hasn't been completely filled, match it with
|
||||||
|
the margin calls if MSSP can match the new order's price;
|
||||||
|
* then, if the new limit buy order still hasn't been completely filled, match it
|
||||||
|
with the rest sell orders until it's completely filled or no more sell order
|
||||||
|
matching its price
|
||||||
|
|
||||||
|
|
||||||
|
# Specifications
|
||||||
|
|
||||||
|
## Matching a taker limit order
|
||||||
|
|
||||||
|
New limit order is being processed in `apply_order(...)` function of `database`
|
||||||
|
class.
|
||||||
|
|
||||||
|
Currently, in the function, firstly call orders will be checked and matched.
|
||||||
|
After that, limit orders on the opposite side will be checked and matched.
|
||||||
|
|
||||||
|
Need to change the logic to:
|
||||||
|
1. firstly, sort the limit orders on the opposite by `price`, best price first,
|
||||||
|
end at MSSP; check them one by one, calls `match(...)` function until the
|
||||||
|
return value is not `2` which means the new order is completely filled;
|
||||||
|
2. if reach the end (MSSP), which means the new order is still unfilled,
|
||||||
|
call `check_call_orders(..)` function or an equivalent;
|
||||||
|
3. check if `new_order_object` still exist, if yes, redo step one but set the
|
||||||
|
maximum possible price of the market as end price.
|
||||||
|
|
||||||
|
## Matching taker margin call orders
|
||||||
|
|
||||||
|
For [bitshares-core
|
||||||
|
issue #453](https://github.com/bitshares/bitshares-core/issues/453),
|
||||||
|
in `check_call_orders(...)` function of `database` class,
|
||||||
|
iterator `limit_itr` will move forward when variable `filled_limit` is `true`.
|
||||||
|
`filled_limit` will be set to `true` when a limit order get completely filled.
|
||||||
|
However, since `filled_limit` is declared out of the `while` block,
|
||||||
|
it doesn't get reset to `false` after `limit_itr` moved forward. That means
|
||||||
|
after the first limit order get completedly filled, `filled_limit` will always
|
||||||
|
be `true`, so `limit_itr` will always move forward no matter whether *current*
|
||||||
|
limit order got completedly filled, so a taker call order may match
|
||||||
|
with a limit order that is not on the top of the order book.
|
||||||
|
|
||||||
|
To fix this, need to change the code to make sure `limit_itr` always references
|
||||||
|
the limit order on the top of the order book when dereferencing.
|
||||||
|
|
||||||
|
# Discussion
|
||||||
|
|
||||||
|
[to be added if any]
|
||||||
|
|
||||||
|
# Summary for Shareholders
|
||||||
|
|
||||||
|
[to be added if any]
|
||||||
|
|
||||||
|
# Copyright
|
||||||
|
|
||||||
|
This document is placed in the public domain.
|
||||||
|
|
||||||
|
# See Also
|
||||||
|
|
||||||
|
* https://github.com/bitshares/bitshares-core/issues/625
|
||||||
|
* https://github.com/bitshares/bitshares-core/issues/453
|
||||||
|
* https://bitsharestalk.org/index.php?topic=25926.0
|
Loading…
Reference in a new issue