Merge pull request #74 from bitshares/bsip38-patch2

Add rounding rule for bsip 38
This commit is contained in:
Abit 2018-04-17 22:46:53 +02:00 committed by GitHub
commit 28eb764536
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 201 additions and 12 deletions

View file

@ -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

View file

@ -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