Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BSIP 35: Mitigate Rounding Issue On Order Matching #59

Merged
merged 16 commits into from
Feb 27, 2018
Merged

Conversation

abitmore
Copy link
Member

@abitmore abitmore commented Feb 19, 2018

BSIP for bitshares/bitshares-core#132 and bitshares/bitshares-core#184.

//Update: changed this BSIP to an overall solution for rounding issues, so it will also resolve bitshares/bitshares-core#342. Title changed accordingly.

@abitmore
Copy link
Member Author

I wonder if it's better to separate the solution for force settlement order into a new BSIP, since it's a bit more controversial than others, by putting it to a new BSIP would be easier for us to push other solutions forward.

@xeroc
Copy link
Member

xeroc commented Feb 19, 2018

Very good bsip and easy to follow.
The proposed solution appears efficient and easy to implement.

This:

There is an argument says breaking the min_to_receive limit is a no-go,
because that's why it's called a "limit order".

... I agree with.

Copy link
Member

@xeroc xeroc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solit bsip. Good proposal.
Only missing aspect is the shareholder summary.

@abitmore
Copy link
Member Author

@xeroc If I'm correct share holder summary is not a must. After this draft listed in the main page we can start stake based voting, although if you as an important proxy don't agree it won't pass, in this case can you help revise the solution, or start a discussion somewhere?

@abitmore
Copy link
Member Author

Actually there is a serious issue in this BSIP.

When matching a taker limit order and a margin call order, if debt * MSSP < 1 Satoshi of collateral, if round down in favor of the call order, it means the limit order will get nothing. In the proposed solution, the limit order will be cancelled. This means nobody can ever fill that call order. As a result, the whole market will get stuck unless something helpful occurs.

@abitmore
Copy link
Member Author

I think we need to round up the paying collateral to 1 Satoshi in this case.

@abitmore
Copy link
Member Author

Here came more thoughts about settle orders.

A settle order may suffer something-for-nothing issue when

  • the matching call order is too small, or
  • the settle order itself is too small, or
  • reached max_settlement_volume in current maintenance interval.

We need to react differently for these scenarios. IMHO,

  • if the matching call order is too small, let it pay 1 Satoshi
  • if the settle order itself is too small, cancel it
  • if reached or about to reach max_settlement_volume, stop matching at this block.

## The Chosen Solution

Current code actually implemented (a) in the first place: when matching two
orders, if there is a rounding issue, the order with smaller volume will be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please specify how order volumes are compared to determine which is "smaller".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@abitmore
Copy link
Member Author

abitmore commented Feb 23, 2018

The something-for-nothing issue exists as well when force settling against the global settlement fund (force settling after the asset has been globally settled, e.g. after a black swan event). Code:

      auto settled_amount = op.amount * bitasset.settlement_price;

//Update:
Note: for prediction markets with zero outcome, something-for-nothing should be allowed.

@abitmore
Copy link
Member Author

Something-for-nothing is only a subset of rounding issues, it's the most extreme one. There are other scenarios that one of the matched parties would be paying more than enough, although they're not paying something for nothing overall. There are discussions in bitshares/bitshares-core#342.

I got an idea about how to mitigate the rounding issue, but wonder if it's better to add it to this BSIP (or even replaces this BSIP), or write it as another BSIP.

The principle would be: never pay more than enough when matching orders. Nevertheless, by paying "enough", it's possible that the party still need to pay more than preferred.

Current code writes (comment added by me):

   if( usd_for_sale <= core_for_sale * match_price )
   {
      core_receives = usd_for_sale;
      usd_receives  = usd_for_sale * match_price; // round down, in favor of bigger order
   }
   ...

It can be explained as: when usd_for_sale is of the smaller order, it's assigned to core_receives directly. However, core_receives is usually more than enough when match_price is smaller than 1. To mitigate the rounding issue, my idea is to assign round_up(usd_receives / match_price) back to core_receives, so the code would look like:

   if( usd_for_sale <= core_for_sale * match_price )
   {
      core_receives = usd_for_sale;
      usd_receives  = usd_for_sale * match_price; // round down, in favor of bigger order
      core_receives = ceil( usd_receives / match_price ); // Pseudo code, actually can't use operator/() here but need another function
   }
   ...

Take a scenario similar to the one described in the 4th comment of bitshares/bitshares-core#132 as an example:

  • Alice's order: Sell CORE at $3 / 80 = $0.0375, balance 50 CORE
  • Bob's order: Buy CORE at $19 / 500 = $0.038, balance $100

The original process would be:

  • 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 pay the whole 50 CORE and get round_down(50 CORE * $3 / 80 CORE) = round_down($1.6) = $1, the effective price would be $1 / 50 CORE = $0.02.
  • 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 pay the whole 50 CORE and get round_down(50 CORE * $19 / 500 CORE = round_down($1.9) = $1, the effective price would still be $1 / 50 CORE = $0.02.

Both results are far from Alice's desired price $0.0375.

The revised process would be:

  • 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, then, calculate how much Alice need to pay as round_up($1 * 80 CORE / $3) = round_up(26.67 CORE) = 27 CORE, so the effective price would be $1 / 27 CORE = $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, then, calculate how much Alice need to pay as round_up($1 * 500 CORE / $19) = round_up(26.3 CORE) = 27 CORE, so the effective price would be $1 / 27 CORE = $0.037.

Both results are still below Alice's desired price $0.0375, but they're much closed to $0.0375 in comparison to $0.02.

Above are processes about processing limit orders. After get $1, the remaining amount of Alice's order is too small to get anything, so the order will be cancelled. However, call orders can't be cancelled so need to be processed differently. I'll leave this topic here to be discussed later.

@abitmore abitmore changed the title Add BSIP 35: A Solution To Something-For-Nothing Issue Add BSIP 35: Mitigate Rounding Issue On Order Matching Feb 25, 2018
@abitmore
Copy link
Member Author

Changed this BSIP to an overall solution for rounding issues, so it will also resolve bitshares/bitshares-core#342. Title changed accordingly.

@TheTaconator
Copy link
Contributor

Outstanding description of a complicated issue! The enumeration of the various combinations of order types was very helpful to me.

I like the idea of canceling orders that are predicted to be "too small" to be fulfilled in the future. But how can "too small" be determined? Is the answer, "when any future matching would result in a "something-for-nothing" scenario"?

@TheTaconator
Copy link
Contributor

Example 2 had me wonder about something.

Could there be a way for someone to make a black swan more likely by borrowing such a tiny amount (perhaps with a tiny amount of collateral?) that black swans could more easily be triggered during a market downturn? (Even if my concern is real, perhaps it is not a situation that is introduced by the proposed solution.)

@abitmore
Copy link
Member Author

how can "too small" be determined? Is the answer, "when any future matching would result in a "something-for-nothing" scenario"?

Yes. Only need to check if its price * amount is less than 1 Satoshi.

@abitmore
Copy link
Member Author

The black swan scenario introduced in example 2 is not due to amount too small, but due to collateral ratio too low. Tiny call orders are more likely to be filled when entered margin call territory. By the way, the scenario won't happen after BSIP 32 is implemented.

@xeroc xeroc merged commit 5bf3ddc into master Feb 27, 2018
@abitmore abitmore deleted the bsip35 branch March 5, 2018 23:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Rounding issue when matching orders
4 participants