Merge pull request #74 from bitshares/bsip38-patch2
Add rounding rule for bsip 38
This commit is contained in:
commit
28eb764536
2 changed files with 201 additions and 12 deletions
|
@ -7,7 +7,7 @@
|
|||
Discussion: https://github.com/bitshares/bitshares-core/issues/132,
|
||||
https://github.com/bitshares/bitshares-core/issues/184,
|
||||
https://github.com/bitshares/bitshares-core/issues/342
|
||||
Replaces: -
|
||||
Superseded-By: 0038 (partly)
|
||||
Worker: 1.14.96
|
||||
|
||||
# Abstract
|
||||
|
@ -261,7 +261,8 @@ The detailed rules proposed by this BSIP with new rules highlighted:
|
|||
amount remaining), check the remaining amount, if the amount is too small
|
||||
so the order would receive nothing on next match, cancel the order.**
|
||||
|
||||
* When matching a limit order with a call order,
|
||||
* When matching a limit order with a call order (**note: this rule has changed
|
||||
in [BSIP 38](bsip-0038.md)**),
|
||||
* **if the call order is receiving the whole debt amount, which means it's
|
||||
smaller and the short position will be closed after the match, round up its
|
||||
paying amount; otherwise,** round down its paying amount.
|
||||
|
@ -371,12 +372,12 @@ Assuming both orders are limit orders, they'll be processed as follows:
|
|||
* If Alice's order is maker, use `$3 / 80` as match price; since Alice's order
|
||||
is smaller, round in favor of Bob's order, so Alice will get
|
||||
`round_down(50 CORE * $3 / 80 CORE) = round_down($1.6) = $1`,
|
||||
and Bob will get `round_up($1 * 80 CORE / $3) = round_up($26.67) = $27`,
|
||||
and Bob will get `round_up($1 * 80 CORE / $3) = round_up(26.67 CORE) = 27 CORE`,
|
||||
the effective price would be `$1 / 27 = $0.037`;
|
||||
* If Bob's order is maker, use `$19 / 500` as match price; since Alice's order
|
||||
is smaller, round in favor of Bob's order, so Alice will get
|
||||
`round_down(50 CORE * $19 / 500 CORE = round_down($1.9) = $1`,
|
||||
and Bob will get `round_up($1 * 500 CORE / $19) = round_up($26.3) = $27`,
|
||||
and Bob will get `round_up($1 * 500 CORE / $19) = round_up(26.3 CORE) = 27 CORE`,
|
||||
the effective price would also be `$1 / 27 = $0.037`.
|
||||
|
||||
# Specifications
|
||||
|
|
204
bsip-0038.md
204
bsip-0038.md
|
@ -6,7 +6,7 @@
|
|||
Created: 2018-03-05
|
||||
Discussion: https://bitsharestalk.org/index.php?topic=25924.0,
|
||||
https://github.com/bitshares/bsips/issues/51
|
||||
Replaces: -
|
||||
Replaces: 0035 (partly)
|
||||
Worker: To be done
|
||||
|
||||
# Abstract
|
||||
|
@ -21,6 +21,8 @@ requirement.
|
|||
This BSIP proposes a protocol change to let shortes (borrowers) have control
|
||||
over selling how much collateral when being margin called.
|
||||
|
||||
This BSIP depends on [BSIP 31](bsip-0031.md).
|
||||
|
||||
# Motivation
|
||||
|
||||
As discussed in [this forum
|
||||
|
@ -30,7 +32,7 @@ black swan, thus hurts the BTS ecosystem. Many participants in the discussion
|
|||
agree that usually it's not really required to cover all debt (thus selling more
|
||||
collateral) when being margin called.
|
||||
|
||||
After [BSIP 31](https://github.com/bitshares/bsips/blob/master/bsip-0031.md) is
|
||||
After [BSIP 31](bsip-0031.md) is
|
||||
in place, shorters will have more chance to not cover all debt on margin call,
|
||||
but it's not 100% guaranteed, and they can only accept the result passively.
|
||||
|
||||
|
@ -46,17 +48,32 @@ Different shorters have different expectations when being margin called:
|
|||
|
||||
With a new "target collateral ratio" option, all these expectations can be met.
|
||||
|
||||
In sections below, both a "margin call order" and a "call order" mean a short
|
||||
position in margin call territory.
|
||||
|
||||
## The Definition of Target Collateral Ratio
|
||||
|
||||
For reference purpose, the collateral ratio of any given debt/short position
|
||||
describes the ratio between the available collateral (e.g. core toke BTS) to
|
||||
the debt that is owed (e.g. CNY, etc.) by the original borrower to the
|
||||
blockchain. It is defined to be a dimensionless value as
|
||||
`CR = collateral / (debt / feed_price)` where the price is measured in units of
|
||||
the debt asset / units of the collateral asset (e.g. `CNY / BTS`).
|
||||
|
||||
"Target collateral ratio" is an optional value which can be set onto a short
|
||||
position, when the position being automatically liquidized (margin called),
|
||||
sell no more than required collateral until collateral ratio of the position
|
||||
reaches this value.
|
||||
is **higher than** this value.
|
||||
* Default value: not set, which means to sell as much collateral as possible,
|
||||
which is same to current behavior.
|
||||
* When the value is set but below MCR, use MCR.
|
||||
* When matching a margin call order with a force settle order, ignore this
|
||||
option.
|
||||
* When checking for black swan or globally settling, ignore this option.
|
||||
|
||||
Why to use "higher than" but not "equal to", is due to an existing rule:
|
||||
if a short position's collateral ratio is equal to MCR, it will still be
|
||||
margin called.
|
||||
|
||||
## The Math
|
||||
|
||||
|
@ -78,7 +95,175 @@ max_amount_to_sell = (debt * target_CR - collateral * feed_price)
|
|||
/ (target_CR * match_price - feed_price)
|
||||
```
|
||||
|
||||
The result is a rational number, need to be rounded up to an integer.
|
||||
The result is a rational number.
|
||||
|
||||
Then, the maximum debt it wants to cover can be calculated as:
|
||||
|
||||
```
|
||||
max_debt_to_cover = max_amount_to_sell * match_price
|
||||
```
|
||||
|
||||
The result is a rational number as well.
|
||||
|
||||
## Rounding on Maximums Calculation
|
||||
|
||||
As described in [BSIP 35](bsip-0035.md), at last we need to convert the
|
||||
rational numbers to integers, so rounding is involved.
|
||||
|
||||
### The first round
|
||||
|
||||
When calculating maximum debt to cover, the goal is to go over the specified
|
||||
target but not go too far beyond.
|
||||
That said, if a short position got matched with a big limit order, after
|
||||
partially filled, its collateral ratio should be **just** higher than specified
|
||||
target collateral ratio.
|
||||
|
||||
We may calculate like this: if `max_debt_to_cover` has no fractional component
|
||||
(e.g. 5.00 as opposed to 5.23), plus it by one Satoshi; otherwise, round it up.
|
||||
An effectively same approach is to round down then add one Satoshi onto the
|
||||
result:
|
||||
|
||||
```
|
||||
max_debt_to_cover_int = round_down(max_debt_to_cover) + 1
|
||||
```
|
||||
|
||||
With `max_debt_to_cover_int` in integer, `max_amount_to_sell_int` in integer
|
||||
can be calculated as:
|
||||
|
||||
```
|
||||
max_amount_to_sell_int = round_up(max_debt_to_cover_int / match_price)
|
||||
```
|
||||
|
||||
It's worth noting that we need to make sure the 2 integers always pair
|
||||
perfectly, they're either the full collateral amount and full debt
|
||||
amount, or have:
|
||||
|
||||
```
|
||||
max_amount_to_sell_int == round_up(max_debt_to_cover_int / match_price)
|
||||
max_debt_to_cover_int == round_down(max_amount_to_sell_int * match_price)
|
||||
```
|
||||
|
||||
For `max_amount_to_sell_int` above, we can adjust `max_debt_to_cover_int` with:
|
||||
|
||||
```
|
||||
max_debt_to_cover_int = round_down(max_amount_to_sell_int * match_price)
|
||||
```
|
||||
|
||||
### Review the result
|
||||
|
||||
Due to rounding, it's not guaranteed that selling more collateral will
|
||||
always result in higher collateral ratio on remaining call order.
|
||||
|
||||
On one hand, it's not guaranteed that the pair of integers above will
|
||||
meet the requirements: after covered `max_debt_to_cover_int`, it's possible
|
||||
that collateral ratio of remaining order is still not higher than `MCR` or
|
||||
`target_CR`. In this case, the result is not acceptable. Generally, if we search
|
||||
upwards, we can find a new pair that meets the requirements, or hit the order's
|
||||
collateral or debt amount.
|
||||
|
||||
On the other hand, no matter if the pair above meets the collateral ratio
|
||||
requirement, it's possible that there exists a smaller pair which meets the
|
||||
requirement. However, it's not easy to find a perfect pair. If we search
|
||||
downwards, it's not easy to decide when to stop; if we start from a smaller
|
||||
pair then search upwards, it's not easy to decide where to start.
|
||||
|
||||
### Favor performance over accuracy
|
||||
|
||||
Due to the difficulty mentioned above, in this BSIP we allow imperfect results,
|
||||
and don't describe or enforce how exactly to find better results.
|
||||
|
||||
The first implementation should be made with efforts. It will become consensus
|
||||
after approved by stake holders via voting. It will then be in effect until
|
||||
changed or replaced with a new BSIP.
|
||||
|
||||
Here are some guidelines about implementation.
|
||||
|
||||
When searching upwards, usually the real working pair is not far away, but it's
|
||||
not guaranteed due to rounding. For better performance, it's not good to search
|
||||
by adding one Satoshi every time. Can use a divergence sequence or other
|
||||
sublinear-time algorithm, that means it's possible that some good data will be
|
||||
skipped which may result in impefect result.
|
||||
|
||||
|
||||
## Rounding on Order Matching, and Edge Cases
|
||||
|
||||
Rounding rules about order matching are defined in [BSIP 35](bsip-0035.md).
|
||||
|
||||
Generally, when two orders got matched, the order matching engine will favor
|
||||
the larger order while rounding.
|
||||
|
||||
When a call order got matched with a limit order, if the call order has no
|
||||
`target_CR` option set but its debt is more than the limit order offered,
|
||||
or the call order has `target_CR` option set but `max_debt_to_cover_int`
|
||||
is more than the limit order offered, both means the call order is larger,
|
||||
according to the rounding rule, the call order's paid collateral will be
|
||||
rounded down, so its collateral ratio will increase after partially filled.
|
||||
|
||||
If the call order has `target_CR` option set and is covering the whole "maximum
|
||||
debt to cover", to be fair, we should consider that part of call order to be
|
||||
smaller and favor the limit order while rounding, otherwise the limit order may
|
||||
suffer an overall loss.
|
||||
That means the call order will be partially filled and its paid
|
||||
collateral will be rounded up, in this case, if the call order's collateral
|
||||
ratio was not too low, usually, partially filling will still lead to an
|
||||
increase in collateral ratio.
|
||||
|
||||
However, there are edge cases: if the call order's collateral ratio is already
|
||||
low, or its debt or collateral amount is tiny, rounding up paid collateral on
|
||||
partially filling will probably lead to a decrease in collateral ratio,
|
||||
in an extreme case it may even lead to a black swan event. This is against the
|
||||
intention of this BSIP. To solve this issue, if detected a decrease in
|
||||
collateral ratio when matching, we propose to ignore the `target_CR` option of
|
||||
corresponding call order, and re-evaluate the match.
|
||||
|
||||
## The Revised Rounding Rules on Order Matching
|
||||
|
||||
So the rule for matching a limit order with a call order will be revised as
|
||||
follows with new rules **in bold**:
|
||||
* if the call order is receiving the whole debt amount, which means it's
|
||||
smaller and the short position will be closed after the match, round up its
|
||||
paying amount;
|
||||
* **otherwise,**
|
||||
* **if the call order has `target_collateral_ratio` set and is receiving the
|
||||
maximum debt amount calculated with `target_collateral_ratio`, see the call
|
||||
order as smaller, try to round up its paying amount;**
|
||||
* **for edge cases, if the call order's collateral ratio would not increase
|
||||
after being partially filled due to the round-up (which may even cause a
|
||||
black swan event in an extreme scenario), see its `target_collateral_ratio`
|
||||
as "not set" for this time, re-apply the filling rules for this match.**
|
||||
* otherwise, the call order is larger, round down its paying amount.
|
||||
* if the limit order would receive nothing, cancel it (it's smaller,
|
||||
so safe to cancel);
|
||||
* otherwise, calculate the amount that the limit order would pay as
|
||||
`round_up(receiving_amount * match_price)`. After filled both orders,
|
||||
if the limit order still exists, the remaining amount might be too small,
|
||||
so cancel it.
|
||||
|
||||
## When and How To Use the Option
|
||||
|
||||
The `target_collateral_ratio` option can to be set, updated or cleared when
|
||||
creating or updating a short position. When doing so, other rules still apply,
|
||||
E.G. can't update a short position to have too small collateral ratio.
|
||||
|
||||
For one account, different short positions (for different assets) can be set
|
||||
with different `target_collateral_ratio`.
|
||||
|
||||
For one short position,
|
||||
|
||||
* if want to close it completely to cut losses when being margin called,
|
||||
* don't set or clear `target_collateral_ratio` option, because the option is
|
||||
**optional** so can be unset or cleared;
|
||||
|
||||
* if want to sell as little collateral as possible when being margin called,
|
||||
to keep the remaining short position as large as possible,
|
||||
* set `target_collateral_ratio` to `MCR` or less;
|
||||
|
||||
* if want to sell more than minimum required collateral when being margin
|
||||
called, to reduce the possibility of being margin called again in the near
|
||||
future, but don't want to completely close the short position,
|
||||
* set `target_collateral_ratio` to a value higher than `MCR`, E.G. `300%`.
|
||||
The higher the value is, the more collateral will be listed for sale when
|
||||
it's margin called.
|
||||
|
||||
|
||||
# Specifications
|
||||
|
@ -128,16 +313,19 @@ The `proposal_create_evaluator` is used to evaluate and apply the
|
|||
|
||||
After a call order get matched with a limit order and about to fill,
|
||||
* if `target_collateral_ratio` is not set, process as before;
|
||||
* if `target_collateral_ratio` is set, calculate maximum amount of collateral
|
||||
for sale according to the equation described above, then process as before.
|
||||
* if `target_collateral_ratio` is set, compare it to `MCR`, use the bigger
|
||||
one (aka `max(target_collateral_ratio,MCR)`) to calculate maximum amount of
|
||||
debt to cover according to the equation described above, and apply the
|
||||
revised rounding rules, then process other logic as before.
|
||||
|
||||
## UI/UX
|
||||
|
||||
The new option need to be presented and can be used in UI after the hard fork.
|
||||
|
||||
When there are call orders to be filled, if `target_collateral_ratio` option
|
||||
is set, UI need to show exact amounts of collateral that another trader is able
|
||||
to buy according to the equation described above.
|
||||
is set, UI need to show exact amount of collateral that another trader is able
|
||||
to buy and exact amount of debt that need to pay according to the equation
|
||||
described above. Note that this calculation will need to use the current `feed_price`.
|
||||
|
||||
# Discussion
|
||||
|
||||
|
|
Loading…
Reference in a new issue