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

BSIP 74 Specification Clarification #273

Closed
wants to merge 2 commits into from

Conversation

jmjatlanta
Copy link
Contributor

Note 1: It is not the intent of this PR to change the mechanics, only to clarify the specifications of BSIP 74. Please review these changes carefully to assure the integrity of the original BSIP, and the accuracy of the specifications.

Note 2: Implementing BSIP74 reduces the "window" of matching limit orders by the MCFR in Case 1. It is assumed the reader understands that, and that issuers will be judicious with their selection of MCFR values. Is it appropriate (or desired) to add this note to this BSIP?

Note 3: These specifications do not dictate what should happen if the collateral is insufficient to pay the margin trading fee. Perhaps (a) the fee takes what it can, or (b) the match fails. If (b), what happens next? Perhaps there is a (c) that I have not thought of.

Copy link
Member

@abitmore abitmore left a comment

Choose a reason for hiding this comment

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

Thanks for bringing this up.


**Case 2:** In the case of the call order being the taker,

`Margin call match price = settlement price/MSSR`.
Copy link
Member

Choose a reason for hiding this comment

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

The match price here should be the limit order's price. The limit order's price (which is buying the collateral asset with debt asset) should not be lower than settlement_price / (MSSR-MCFR), otherwise the match doesn't happen.

Note: the order matching engine requires 1 <= MSSR < MCR and 1 <= MSSR-MCFR < MCR. This ensures that CR of the call order will increase after being matched with a limit order, and the limit order is not buying above feed price when being a taker. If for some reason the parameters became inconsistent and broke the limitations above, cap MCFR at MSSR - 1. The capping applies to case 1 too.

Copy link
Contributor

Choose a reason for hiding this comment

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

Note: the order matching engine requires 1 <= MSSR < MCR and 1 <= MSSR-MCFR < MCR. This ensures that CR of the call order will increase after being matched with a limit order, and the limit order is not buying above feed price when being a taker.

If for some reason the parameters became inconsistent and broke the limitations above, cap MCFR at MSSR - 1. The capping applies to case 1 too.

I'm wondering about how to perform these checks efficiently. If these values should be honored during order matching, does that require "normalizing" all the limit orders during the start of the order matching process? Or once whenever violating limitations are set?

What about, as an alternative, preventing the setting of invalid MSSR and MCFR when they are set in their operation evaluator?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are plenty of numbers floating around here, so please let me make sure I understand what you are saying.

MSSR is defaulted at 1500 (GRAPHENE_DEFAULT_MAX_SHORT_SQUEEZE_RATIO), which I read as 150%. I assume that when you say 1 <= MSSR you mean 1 <= ( ( MSSR-1000) / 1000 ), i.e. the default case is 1 <= 0.5

Also, when you say cap MCFR at MSSR - 1, am I correct in believing (assuming MSSR is GRAPHENE_DEFAULT_MAX_SHORT_SQUEEZE_RATIO) 1499 a.k.a. 149.9%?

Copy link
Contributor Author

@jmjatlanta jmjatlanta May 5, 2020

Choose a reason for hiding this comment

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

What about, as an alternative, preventing the setting of invalid MSSR and MCFR when they are set in their operation evaluator?

See bitshares/bitshares-core#2130 (comment)

In short:

However, mssr is updated by price feed producers and an internal timer, mcfr is updated by asset owner, so likely we can't validate when one of them is updated. So we need to cap the value of mcfr when use it in calculation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member

@abitmore abitmore May 5, 2020

Choose a reason for hiding this comment

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

1 <= MSSR < MCR

Default value of MSSR is 1500 aka 1.5, default value of MCR is 1750 aka 1.75.
1 <= 1.5 < 1.75, it's perfect.

Current data on chain:

  • bitCNY MCR 1600 MSSR 1010, so 1 <= 1.01 < 1.6
  • bitRUBLE MCR 1750 MSSR 1100, so 1 <= 1.1 < 1.75

1 <= MSSR-MCFR < MCR
  • for bitCNY, I'd assume the valid MCFR would be between 0 and 0.01, [0, 0.01]
  • for bitCNY, I'd assume the valid MCFR would be between 0 and 0.1, [0, 0.1]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note: the order matching engine requires 1 <= MSSR < MCR and 1 <= MSSR-MCFR < MCR.

Is it safe to only consider the second part? Or do we allow a negative MCFR?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think we allow a negative MCFR.

bsip-0074.md Show resolved Hide resolved

Note that MCFR does not come into play for order matching in this case, but it is involved in the calculation of collateral that is returned to the call order owner.

When margin call trading happens with the call order as the taker, the buyer sells smartcoin with quantity X and receives collateral in quantity `X/limit order price`, the margin call order owner sells collateral in quantity `X/limit order price*(1+MCFR)` and gets smartcoin in quantity X, the delta in paid and received collaterals (quantity `X*MCFR/limit order price`) will be paid to the owner of the smartcoin as the margin call fee.
Copy link
Member

Choose a reason for hiding this comment

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

This is a fair approach, although perhaps not the best.

Also please be aware that X is affected by the TCR parameter as well as the filling price (but not only the matching price), when the filling price got shifted due to MCFR, X could be different. This applies to case 1 too.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a fair approach, although perhaps not the best.

Would this be better by not reducing the CR of a margin call order that is partially filled?

"When margin call trading happens with the call order as the taker, the buyer sells smartcoin with quantity X and receives collateral in quantity X*(1-MCFR)/limit order price, the margin call order owner sells collateral in quantity X/limit order price and gets smartcoin in quantity X, the delta in paid and received collaterals (quantity X*MCFR/limit order price) will be paid to the owner of the smartcoin as the margin call fee."

Is there something else that would be better?

Copy link
Member

Choose a reason for hiding this comment

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

When there is a limit order bidding high, and a call order takes it, it's perhaps "better" (or not) that the call order pays more fees than X*MCFR/limit_order_price, e.g. pays X*MCFR/feed_price.

@winston-1984
Copy link

winston-1984 commented May 6, 2020

The status is you do not have enough collateral so you are margin called. Your debt is placed up for sale so your collateral can be extracted to pay your due. The amount of collateral you get back (per unit of debt) is less than feed price because you're being squeezed. You're liquidated at up to the margin call limit price; the realized call price.

Now the system will tax you and pay the issuer as an added penalty/indignity of being margin called. It would seem a legitimate tax is on the collateral ACTUALLY recovered; as opposed to collateral that "could have been" recovered.

As a metaphor, in real life, we're often faced with theoretical prices and executed market prices when we shop. The "list price" of some item for sale at the store might be $200; but the actual price you pay after a 50% discount is $100. In such circumstance, the State charges tax on the discounted rate of execution; not the theoretical list price. This is the case regardless of whether its an advertised discount, haggled discount, or any other reduction of execution price. Likewise; feed price is theoretical. Whereas, realized call price is the price of execution. It seems in keeping with norms of society to charge taxation on the executed market prices. If the State tax rate is 10%, your liability on $100 executed sale (realized call) is $10; not $20 on the listed (feed) price.

@MichelSantos
Copy link
Contributor

@abitmore This is a follow-up to a related discussion

There are three ideas that I am having difficulty with reconciling.

Idea 1: The original BSIP74 specifications as being approximately true

Idea 2: Our discussion where we confirmed that "the buyer's/limit order owner's expectation of the "real price" is settlement_price/(MSSR-MCFR)." and that the this "real price" is the match price.

Idea 3: The statement "IMO, when MCFR is zero, all existing test cases should pass." which includes two BSIP77 tests (1 and 2) which, under the current values of the hardfork activation times, operate under BSIP74 rules.

My current reconciliation is to conclude that BSIP74 does not apply when the call order is taker but does apply when the call order is maker. I conclude this based on the test line 1 which is operating under BSIP74 rules because (a) it is invoked from this BSIP77 test, and (b) the currently defined activation times. [1] specifically states that Bob, the margin call owner, paid 105 CORE in collateral which (c) is the amount asked for by the limit order, and (d) does not equal 110 CORE which is what should be paid by the call order according to BSIP74 when there is a 10% MSSR.

Is there some other way to interpret or reconcile these three ideas?

Alternatively, if these three ideas are compatible with each other, and if this BSIP77 test is an example of how BSIP74 should operate under BSIP74 rules when the call order is a taker, it would help greatly and save time to have the following additional numerical examples

(a) more_call_order_update_test_after_hardfork_bsip77_when_icr_not_set when MCFR is 5%
(b) a similar example as more_call_order_update_test_after_hardfork_bsip77_when_icr_not_set when Bob is a maker with MCFR at 5%

which describe

  • what does the call order pay?
  • what does the call order receive?
  • what does the limit order pay?
  • what does the limit order receive?
  • what is recorded as the match price?

With these numerical examples, we can finally resolve the specifications.

@christophersanborn
Copy link
Member

christophersanborn commented May 19, 2020

Offering some of my own thoughts here. No guarantee they're fully baked.

It seems to me the maker/taker issue boils down to the fact that one party to the trade (the taker) has the potential to get a "better deal" than they are asking for, by virtue of being able to pick an existing order off the book.

If the taker is the limit order, the logic in BSIP74 as written is reasonably clear. The trade price will be X*(MSSR-MCFR)/SP collateral for X smart coin. This might well be a better price than the limit order asked for, but there is no ambiguity as to what the price is. Furthermore, the call order will have relinquished X*MSSR/SP collateral, which is a greater amount of collateral than was paid to the limit order (if MCFR > 0), and so there exists a "delta" which is equivalent to (notwithstanding rounding errors) Δ = X*MCFR/SP, which can be paid to the asset issuer as a fee.

The other scenario:

If the taker is the call order, then the trade price will be collateral amount C_trade <= X*(MSSR-MCFR)/SP exchanged for X smart coin. The inequality exists because the call order might find an order on the books that offers X smart coin for less C than the call order is offering.

In this case, it's a little unclear what amount of collateral the call order should relinquish. On the one hand, it could relinquish the very same C_pays = X*MSSR/SP, in which case the "delta" is a larger amount than before, i.e., Δ >= X*MCFR/SP. Should the entirety of the delta be paid to the issuer as a fee? If so, the issuer is getting a greater percentage than they have nominally charged, and the call order is denied the windfall of getting to be a taker rather than a maker.

On the other hand, when the call order is taker, we could "fix" the delta at Δ = X*MCFR/SP, and define the relinquished collateral as C_pays = C_trade + Δ. In this case, the margin call fee is fixed at its nominal percentage, (issuer does not "steal" the callee's windfall), and the call order gets to derive the benefit of being a taker.

I favor the latter option, as it seems more fair to me.

Further commentary:

  • I'm taking as an assumption that, prior to BSIP74, that a margin call order that is fortunate enough to be a taker does derive the benefit thereof — i.e. it gets to match at a more advantageous price than the MCOP (margin call order price), if an order is on the books at such an advantageous price. (If this is NOT true, then it means there are cases when a maker order gets a better price than asked, which would seem to contradict @abitmore's statement: "According to BSIP32, in any case, the matching/filling price is the maker price ... BSIP74 doesn't change it." (from here.))

  • If that assumption is correct, then @MichelSantos's statement:

Idea 2: Our discussion where we confirmed that "the buyer's/limit order owner's expectation of the "real price" is settlement_price/(MSSR-MCFR)." and that the this "real price" is the match price.

can't be correct (or I'm not understanding it) — as there ARE cases where the match price is DIFFERENT from settlement_price/(MSSR-MCFR) — specifically the case where the call order is taker. The difference is in favor of the call order (allows it to retain a bit more collateral). A possible reconciliation of this is that "real price" is not supposed to refer to the "match price" but only to the price at which the call order is offered. The match price may differ in the case where the call takes an existing advantageous offer.

@abitmore
Copy link
Member

@MichelSantos wrote:

Idea 2: Our discussion where we confirmed that "the buyer's/limit order owner's expectation of the "real price" is settlement_price/(MSSR-MCFR)." and that the this "real price" is the match price.

There was a misunderstanding or miscommunication. I replied "yes" there because I thought your question implied the limit order was the taker, in this case, the (maker) price the call order offers is settlement_price/(MSSR-MCFR) but not settlement_price/MSSR. Due to the "filling orders at maker price" principle, if a limit order was placed as a maker, the owner (of the limit order) should not expect the limit order to be filled at a better price (except rounding).

As @christophersanborn pointed out, the logic is clear when the limit order is the taker.

When the limit order is the maker, I've commented earlier (#273 (comment)):

This (note: the specs written in this pull request) is a fair approach ...

Actually it is the same idea as @christophersanborn's : "fix" the delta at a price.

@christophersanborn wrote:

I'm taking as an assumption that, prior to BSIP74, that a margin call order that is fortunate enough to be a taker does derive the benefit thereof — i.e. it gets to match at a more advantageous price than the MCOP (margin call order price), if an order is on the books at such an advantageous price.

This assumption is correct.

@MichelSantos
Copy link
Contributor

@christophersanborn @abitmore Do we have agreement of the following for Case 2/call order is taker/limit order is maker?

Case 2: In the case of the call order being the taker,

When margin call trading happens with the call order as the taker:

The match price is X/limit_order_price

During filling

  • the limit order pays smartcoin with quantity X
  • the call order receives smartcoin with quantity X
  • the limit order receives collateral with quantity X/limit_order_price
  • the call order pays collateral with quantity X/limit_order_price
  • the call order also pays the margin call fee in collateral with quantity X*MCFR/settlement_price

Therefore the call order pays a total collateral with quantity X/limit_order_price + X*MCFR/settlement_price

@abitmore
Copy link
Member

When the call order is the taker, it pays the fee in collateral asset with quantity X*MCFR/settlement_price or X*MCFR/limit_order_price? Which one is better?

@MichelSantos
Copy link
Contributor

MichelSantos commented May 19, 2020

When the call order is the taker, it pays the fee in collateral asset with quantity X*MCFR/settlement_price or X*MCFR/limit_order_price? Which one is better?

Which is better depends on the objective. The objective described in the Motivation is "add to the system's income". Both X*MCFR/settlement_price and X*MCFR/limit_order_price do that. However, X*MCFR/settlement_price has the following advantages:

  • it is the same as the fee from the maker side. This rule makes the BSIP easy to describe: the margin call fee equal X*MCFR/settlement_price +/- rounding errors and constraints such that the margin call order never pays more than X*MSSR/settlement_price in collateral.

  • the same fee formula is simpler to understand by call order owners after they have been margin called and inspect their account history

One might argue that another advantage is that it is a larger fee which is in closer agreement to the motivation of adding to the system's income. However this ignores that the owners of call orders might adjust their behavior if and when BSIP74 is activated to reduce the frequency or likelihood being margin called. This could be achieved either by reducing the creation of call orders and/or increasing their collateral ratios to reduce margin calls.

(Updated by @abitmore for better format)

@christophersanborn
Copy link
Member

When the call order is the taker, it pays the fee in collateral asset with quantity X*MCFR/settlement_price or X*MCFR/limit_order_price? Which one is better?

This is an interesting question. Here the limit_order_price is better than the margin_call_offer_price, (because call is taker), but not necessarily better than the settlement price. Had the call been maker, fee would be X*MCFR/settlement_price. I think we want to avoid augmenting that fee, which could happen if limit_order_price falls between settlement_price and margin_call_offer_price. On the other hand, if the call order lucks out and gets a great price — a better price than settlement_price, it would then speak to @winston-1984's point above that the fee should be paid on the discounted price that the order actually received, rather than the "full price" which the order didn't have to pay.

I propose we check which fee calculation is better and give the call order the better result. This check is only needed when call is taker. In particular, I propose this matrix:

Call is Maker (Just for review):

In this case we do:

fee = X*MCFR/settlement_price. Note we do NOT use limit_order_price in the denominator. If we did it would make a bigger fee. (And would probably also complicate the determination of which call orders are sufficiently collateralized to be margin called — i.e. the short-squeeze protection.)

Call is Taker:

In this case we do:

fee = min(X*MCFR/settlement_price, *X*MCFR/limit_order_price. The former will be the minimum when the limit_order_price is between settlement_price and margin_call_offer_price. Note that this preserves agreement with the case where call-is-maker, and ensures we don't complicate short-squeeze protection. The latter will be the min when the call order really lucks out and matches an order with a limit_order_price that is better than the settlement_price.

@abitmore
Copy link
Member

Thank you @christophersanborn for pointing out the error. X*MCFR/limit_order_price doesn't work well since it may make the call order pay even more fees when being the taker than being the maker. To fix it I think we need to use X*MCFR/[limit_order_price*(MSSR-MCFR)]. This fits @winston-1984's point too. @MichelSantos how about this?

@MichelSantos
Copy link
Contributor

Thank you @christophersanborn for pointing out the error. X*MCFR/limit_order_price doesn't work well since it may make the call order pay even more fees when being the taker than being the maker. To fix it I think we need to use X*MCFR/[limit_order_price*(MSSR-MCFR)]. This fits @winston-1984's point too. @MichelSantos how about this?

I'm sorry but I don't understand how X*MCFR/[limit_order_price*(MSSR-MCFR)] is derived nor its full objective.

Your statement seems to be that the fee as taker should not be more than the fee as maker. A min function, as described by Christopher, would address that concern.

@christophersanborn
Copy link
Member

I'm sorry but I don't understand how X*MCFR/[limit_order_price*(MSSR-MCFR)] is derived nor its full objective.

It comes from the fact that the call order offers a price of margin_call_offer_price which is defined as settlement_price/(MSSR-MCFR). When we are maker, this is always the match price. When we are taker, the call order will match limit orders whose limit_order_price is at or above the margin_call_offer_price, or:

limit_order_price >= settlement_price/(MSSR-MCFR)

which, when plugged in to the formula for fee gives: (inequality switches direction because the price is in inverse)

fee <= X*MCFR/[ (settlement_price/(MSSR-MCFR)) * (MSSR-MCFR) ], or,

fee <= X*MCFR/settlement_price.

So we get the result that the fee matches the spec price in the extremum match condition where we take an order at the same price as the offer price, but goes down if we happen to match at a more favorable price.

@abitmore
Copy link
Member

@MichelSantos wrote:

... I don't understand how X*MCFR/[limit_order_price*(MSSR-MCFR)] is derived nor its full objective.

The 2 orders match, which means settlement_price / (MSSR-MCFR) <= limit_order_price,

  • when the call order is the maker, the matching price is P = settlement_price / (MSSR-MCFR), so settlement_price = P * (MSSR-MCFR), we charge the margin call fee based on the match price, to the result F = debt_amount * MCFR / settlement_price = debt_amount * MCFR / [P * (MSSR-MCFR)];
  • when the call order is the taker, the matching price is P' = limit_order_price, to be consistent with above, we charge the margin call fee as F' = debt_amount * MCFR / [P' * (MSSR-MCFR)] = debt_amount * MCFR / [ limit_order_price * (MSSR-MCFR)].
    • It's linear, so IMHO better than min().

@MichelSantos
Copy link
Contributor

The 2 orders match, which means settlement_price / (MSSR-MCFR) <= limit_order_price,
...
It's linear, so IMHO better than min().

Thanks for both of those explanations @christophersanborn @abitmore

I also now understand that because the limit_order_price is constrained between settlement_price / (MSSR-MCFR) <= limit_order_price <= settlement_price by the other logic in check_call_orders, this linear function will behave the same as the minimum function within this constrained domain.

Although I still think that this margin call fee is more complicated to explain than a fee = X * MCFR / settlement_price, I have no objection to it.

@sschiessl-bcp
Copy link
Collaborator

I have not thought through your detailed explanation, it looks fine at glance and does not alter the intent of this bsip.

@jmjatlanta can you resolve all reviews and comment when you see this done?

@abitmore
Copy link
Member

Although I still think that this margin call fee is more complicated to explain

I think it can be explained in a consistent manner as

margin_call_fee = collateral_paid_to_buyer * MCFR / (MSSR-MCFR)

which to be deducted from remainder of collateral in the debt position.

@abitmore
Copy link
Member

@sschiessl-bcp I would expect that @MichelSantos will create a new pull request to resolve the reviews.

@MichelSantos
Copy link
Contributor

I have not thought through your detailed explanation, it looks fine at glance and does not alter the intent of this bsip.

@jmjatlanta can you resolve all reviews and comment when you see this done?

@sschiessl-bcp For whatever it's worth, I agree that the updates do not change the intent, and that it addresses an ambiguity when the margin call order was a taker. The ambiguity is well summarized by @abitmore , after much development and discussions, as what is amount of collateral that is paid to the buyer.

@abitmore
Copy link
Member

Closing in favor of #278.

@abitmore abitmore closed this May 29, 2020
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.

6 participants