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 model-free alternatives for: risk factors, liquidity scoring and price monitoring triggers #2267

Merged
merged 5 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions protocol/0016-PFUT-product_builtin_future.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,6 @@ Optional parameters:
1. When `max_price` is specified and the market is ran in a [fully-collateralised mode](./0019-MCAL-margin_calculator.md#fully-collateralised) and a party opens a long position at a `max_price`, no closeout happens when mark to market settlement is carried out at a price of `0`. (<a name="0016-PFUT-023" href="#0016-PFUT-023">0016-PFUT-023</a>)
1. When `max_price` is specified and the market is ran in a [fully-collateralised mode](./0019-MCAL-margin_calculator.md#fully-collateralised) and a party opens a short position at a price of `0`, no closeout happens when mark to market settlement is carried out at a `max_price`. (<a name="0016-PFUT-024" href="#0016-PFUT-024">0016-PFUT-024</a>)
1. Futures market can be created without specifying any of the [optional paramters](#1-product-parameters). (<a name="0016-PFUT-025" href="#0016-PFUT-025">0016-PFUT-025</a>)
1. Futures market can be created with a wrapped risk model with [hardcoded risk factors](./0018-RSKM-quant_risk_models.ipynb). (<a name="0016-PFUT-026" href="#0016-PFUT-026">0016-PFUT-026</a>)
1. Updating a risk model on a futures market with regular risk model to a wrapped risk model with [hardcoded risk factors](./0018-RSKM-quant_risk_models.ipynb) results in recalculation of all margin levels in line with hardcoded values and collateral search/release where appropriate. (<a name="0016-PFUT-027" href="#0016-PFUT-027">0016-PFUT-027</a>)
1. Updating a risk model on a futures market with a wrapped risk model with [hardcoded risk factors](./0018-RSKM-quant_risk_models.ipynb) to a regular risk model results in recalculation of all margin levels in line with the specified risk model (hardcoded value are no longer used) and collateral search/release where appropriate. (<a name="0016-PFUT-028" href="#0016-PFUT-028">0016-PFUT-028</a>)
334 changes: 169 additions & 165 deletions protocol/0018-RSKM-quant_risk_models.ipynb

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions protocol/0019-MCAL-margin_calculator.md
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,10 @@ Assume a [capped future](./0093-CFUT-product_builtin_capped_future.md) market wi
- Party B posts an order to buy `30` contracts at a price of `16`, the orders get placed on the book, the maintenance and initial margin levels for party B grow to `1180`, and the margin account balance remains unchanged at `700` and the order margin account balance grows to `480 = max (5 * (100 - 20), 30 * 16)`. The position remains unchanged at `-10`. (<a name="0019-MCAL-157" href="#0019-MCAL-157">0019-MCAL-157</a>)
- Party A posts an order to sell `20` contracts at a price of `17`. A trade is generated for `10` contracts at a price of `18` with party B. A sell order for `10` contracts at a price of `17` from party A gets added to the book. The maintenance and initial margin levels for party A is now `10 * (100 - 17) = 830`, the position is `0` and the remaining volume on the book from this party is `10` at a price of `18`. Party A lost `120` on its position, hence `830 - (300 - 120) = 410` additional funds get moved from the general account as part of the transaction which submitted the order to sell `20` at `17`. Party B now has a position of `0` and following orders open on the book: sell `5` at `20` and buy `30` at `16`. The maintenance and initial margin levels are `max(5 * (100 - 20), 30 * 16) = 480`. The margin account momentarily becomes `820` (`700` + `120` of gains from the now closed position of `-10`), order margin account balance is `480`, hence `820` gets released back into the general account and margin account becomes `0`. (<a name="0019-MCAL-158" href="#0019-MCAL-158">0019-MCAL-158</a>)

## Acceptance Criteria (Hardcoded risk factors)

- When a wrapped model with hardcoded risk factors is used then margin calculations depend entire on the hardcoded values and updating the nested risk model has no effect on margins (<a name="0019-MCAL-159" href="#0019-MCAL-159">0019-MCAL-159</a>)

## Summary

The *margin calculator* returns the set of margin levels for a given *actual position*, along with the amount of additional margin (if any) required to support the party's *potential position* (i.e. active orders including any that are parked/untriggered/undeployed).
Expand Down
17 changes: 16 additions & 1 deletion protocol/0032-PRIM-price_monitoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

The dynamics of market price movements are such that prices don't always represent the participants' true average view of the price, but are instead artefacts of the market microstructure: sometimes low liquidity and/or a large quantity of order volume can cause the price to diverge from the true market price. It is impossible to tell at any point in time if this has happened or not.

As a result, we assume that relatively small moves are "real" and that larger moves might not be. Price monitoring exists to determine the real price in the latter case. Distinguishing between small and large moves can be highly subjective and market-dependent. We are going to rely on the risk model to formalise this process. Risk model can be used to obtain the probability distribution of prices at a future point in time given the current price. A price monitoring trigger can be constructed using a fixed horizon and probability level.
As a result, we assume that relatively small moves are "real" and that larger moves might not be. Price monitoring exists to determine the real price in the latter case. Distinguishing between small and large moves can be highly subjective and market-dependent.
We are going to rely on the risk model to formalise this process. Risk model can be used to obtain the probability distribution of prices at a future point in time given the current price. A price monitoring trigger can be constructed using a fixed horizon and probability level.
To give an example: get the price distribution in an hour as implied by the risk model given the current mid price, if after the hour has passed and the actual mid price is beyond what the model implied (either too low or too high) with some chosen probability level (say 99%), then we'd characterise such market move as large. In general we may want to use a few such triggers per market (i.e. different horizon and probability level pairs). The framework should be able to trigger a price protection auction period with any valid trading mode.
We're also going to allow specifying triggers directly as the maximum valid moves with respect to the reference price. In that case the `maxUpMoveFactor`, `maxDownMoveFactor` can be specified for a given horizon, such that a price is considered valid as long as it's in the range `[reference_price(horizon) * maxDownMoveFactor, [reference)price(horizon) * maxUpMoveFactor]`, where `[reference_price(horizon)` is the reference price corresponding to the specified horizon - obtained in exactly the same way as in the case of a model-based trigger.

As mentioned above, price monitoring is meant to stop large market movements that are not "real" from occurring, rather than just detect them after the fact. To that end, it is necessary to pre-process every transaction and check if it triggers the price monitoring action. If pre-processing the transaction doesn't result in the trigger being activated then it should be "committed" by generating the associated events and modifying the order book accordingly (e.g. generate a trade and take the orders that matched off the book). On the other hand if the trigger is activated and the submitted transaction is valid for auction mode, the entire order book **along with that transaction** needs to be processed via price protection auction. If the transaction which activate the trigger is not valid for auction, then it should get rejected and market should continue in the current trading mode. Auction period associated with a given distribution projection horizon and probability level will be specified as part of market setup. Once the auction period finishes the trading should resume in regular fashion (unless other triggers are active, more on that in [reference-level explanation](#reference-level-explanation)).

Expand Down Expand Up @@ -44,6 +46,8 @@ Likewise, pre-processing transactions will be needed as part of the [fees spec](

#### Market

##### Model-based triggers

- `priceMonitoringParameters` - an array of more price monitoring parameters with the following fields:
- `horizon` - price projection horizon expressed as a year fraction over which price is to be projected by the risk model and compared to the actual market moves during that period. Must be positive.
- `probability` - probability level used in price monitoring. Must be in the [0.9,1) range.
Expand All @@ -55,6 +59,13 @@ If any of the above parameters or the risk model gets modified in any way, the p
- the auction end time implied by the currently running auction/extension should remain unchanged,
- when auction uncrosses price monitoring should get reset using the updated parameters.

##### Model-free triggers

- `modelFreePriceMonitoringParameters` - an array of more price monitoring parameters with the following fields:
- `horizon` - price projection horizon expressed as a year fraction over which price is to be projected by the risk model and compared to the actual market moves during that period. Must be positive.
- `maxUpMoveFactor` - a factor to be applied to the reference price (for the specified horizon) so that the maximum valid price is `reference_price(horizon) * maxUpMoveFactor`. Must be greater than `1`.
- `maxDownMoveFactor` - a factor to be applied to the reference price (for the specified horizon) so that the minimum valid price is `reference_price(horizon) * maxDownMoveFactor`. Must be less than `1`.

#### Network

- `market.monitor.price.defaultParameters`: Specifies default market parameters outlined in the previous paragraph. These will be used if market parameters don't get explicitly specified.
Expand Down Expand Up @@ -141,3 +152,7 @@ to the risk model and obtains the range of valid up/down price moves per each of
- Same as above, but more matching orders get placed during the auction extension. The volume of the trades generated by the later orders is larger than that of the original pair which triggered the auction. Hence the auction concludes generating the trades from the later orders. The overall auction duration is equal to the sum of the extension periods of the two triggers. (<a name="0032-PRIM-021" href="#0032-PRIM-021">0032-PRIM-021</a>). For product spot: (<a name="0032-PRIM-038" href="#0032-PRIM-038">0032-PRIM-038</a>)
- For all available mark price calculation methodologies: the price history used by the price monitoring engine is in line with market's mark price history. (<a name="0032-PRIM-039" href="#0032-PRIM-039">0032-PRIM-039</a>)
- For all available mark-price calculation methodologies: the mark price update candidate gets rejected if it violates the price monitoring engine bounds. (<a name="0032-PRIM-040" href="#0032-PRIM-040">0032-PRIM-040</a>)
- Model-free triggers can be added to the market at creation time along with regular triggers. (<a name="0032-PRIM-041" href="#0032-PRIM-041">0032-PRIM-041</a>)
- Model-free triggers can be added to the market during market update along with regular triggers. (<a name="0032-PRIM-042" href="#0032-PRIM-042">0032-PRIM-042</a>)
- Adding a model-free trigger with `maxUpMoveFactor = 1.1` and `maxDownMoveFactor = 0.95` results in bonds with max valid price of `110` and min valid price of `95` when a reference price is `100`. When time passes so that the reference price becomes `90` then the resulting max valid price is `99` and min valid price is `85.5`. Violating any of these bounds results in an auction. (<a name="0032-PRIM-043" href="#0032-PRIM-043">0032-PRIM-043</a>
)
37 changes: 35 additions & 2 deletions protocol/0042-LIQF-setting_fees_and_rewarding_lps.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,13 @@ An existing LP has `average entry valuation 1090.9` and `S=110`. Currently the s
```


### Calculating the instantaneous liquidity score
### Calculating the liquidity score

At every vega time change calculate the liquidity score for each committed LP.
This is done by taking into account all orders they have deployed within the `[min_lp_price,max_lp_price]` [range](./0044-LIME-lp_mechanics.md) and then calculating the volume-weighted [probability of trading](./0034-PROB-prob_weighted_liquidity_measure.ipynb) at each price level - call it instantaneous liquidity score.
This is done by taking into account all orders they have deployed within the `[min_lp_price,max_lp_price]` [range](./0044-LIME-lp_mechanics.md) and then calculating the volume-weighted instantaneous liquidity score.

It can be based either on [probability of trading](./0034-PROB-prob_weighted_liquidity_measure.ipynb) at each price level or an [explicit scoring function](./0091-ILSF-instantaneous_liquidity_scoring_funcion.md). The purpose of it is to decide on the relative value of volume placed close to the mid price versus that further away from it.

For orders outside the tightest price monitoring bounds set probability of trading to 0. For orders which have less than 10% [probability of trading], we set the probability to 0 when calculating liquidity score.
Note that parked [pegged orders](./0037-OPEG-pegged_orders.md) and not-yet-triggered [stop orders](./0014-ORDT-order_types.md) are not included.

Expand Down Expand Up @@ -465,3 +468,33 @@ Example 1, generated with [supplementary worksheet](https://docs.google.com/spre
- All vAMMs active on a market at the end of an epoch receive SLA bonus rebalancing payments with `0` penalty fraction. (<a name="0042-LIQF-092" href="#0042-LIQF-092">0042-LIQF-092</a>)
- A vAMM active on a market during an epoch, which was cancelled prior to the end of an epoch, receives SLA bonus rebalancing payments with `0` penalty fraction. (<a name="0042-LIQF-093" href="#0042-LIQF-093">0042-LIQF-093</a>)
- A vAMMs cancelled in a previous epoch does not receive anything and is not considered during SLA rebalancing at the end of an epoch(<a name="0042-LIQF-094" href="#0042-LIQF-094">0042-LIQF-094</a>)

### Explicit instantaneous liquidity scoring function

When market is setup with [explicit instantaneous liquidity scoring function](./0091-ILSF-instantaneous_liquidity_scoring_funcion.md) as follows:

- buy-side:
- reference: BEST_BID
- points: [(0,0.25),(1,0)]
- interpolation strategy: FLAT

- sell-side:
- reference: BEST_ASK
- points: [(0,0.35),(1,0)]
- interpolation strategy: FLAT

then all the buy orders deployed at `BEST_BID` get an instantaneous liquidity score of `0.25`, all sell orders deployed at `BEST_ASK` get a score of `0.35` and all other orders get a score of `0`. Updating the risk model has no effect on those scores. (<a name="0042-LIQF-095" href="#0042-LIQF-095">0042-LIQF-095</a>)

When market is setup with [explicit instantaneous liquidity scoring function](./0091-ILSF-instantaneous_liquidity_scoring_funcion.md) as follows:

- buy-side:
- reference: MID
- points: [(0,0.4),(200,0.2)]
- interpolation strategy: FLAT

- sell-side:
- reference: MID
- points: [(0,0.5),(300,0.3)]
- interpolation strategy: FLAT

the decimal places for the asset are, the decimal places for the market are and tick size is. Then buy orders pegged to MID with an offset of `100` get a score of `0.3`, orders with offset of `200` get a score of `0.2` and orders with and offset of `300` also get a score of `0.2`. Sell orders pegged to MID with an offset of `150` get a score of `0.4`, orders with an offset of `300` get a score of `0.3` and orders with an offset of `400` also get a score of `0.3`. Updating the risk model has no effect on those scores. (<a name="0042-LIQF-096" href="#0042-LIQF-096">0042-LIQF-096</a>)
6 changes: 6 additions & 0 deletions protocol/0053-PERP-product_builtin_perpetual_future.md
Original file line number Diff line number Diff line change
Expand Up @@ -369,3 +369,9 @@ Launch a perpetual futures market which sets `internalCompositePrice` to `Nil` (
Launch a perpetual futures market which sets `internalCompositePrice` to a configuration which uses the impact notional price from the order book. for the "vega side price" for funding calculation. Submit a market update proposal to change this `Nil` (so that mark price gets used for the vega side price). Observe that the new methodology for funding calculations is applied correctly from enactment onwards. (<a name="0053-PERP-045" href="#0053-PERP-045">0053-PERP-045</a>).

Launch a perpetual futures market which uses the "Last Traded Price" for the "vega side price" for funding calculation. Submit a market update proposal to change this to a composite price with a configuration which uses the impact notional price from the order book. Observe that the new methodology for funding calculations is applied correctly from enactment onwards. (<a name="0053-PERP-046" href="#0053-PERP-046">0053-PERP-046</a>).

Perps market can be created with a wrapped risk model with [hardcoded risk factors](./0018-RSKM-quant_risk_models.ipynb). (<a name="0053-PERP-047" href="#0053-PERP-047">0053-PERP-047</a>)

Updating a risk model on a perps market with regular risk model to a wrapped risk model with [hardcoded risk factors](./0018-RSKM-quant_risk_models.ipynb) results in recalculation of all margin levels in line with hardcoded values and collateral search/release where appropriate. (<a name="0053-PERP-048" href="#0053-PERP-048">0053-PERP-048</a>)

Updating a risk model on a perps market with a wrapped risk model with [hardcoded risk factors](./0018-RSKM-quant_risk_models.ipynb) to a regular risk model results in recalculation of all margin levels in line with the specified risk model (hardcoded value are no longer used) and collateral search/release where appropriate. (<a name="0053-PERP-049" href="#0053-PERP-049">0053-PERP-049</a>)
22 changes: 22 additions & 0 deletions protocol/0091-ILSF-instantaneous_liquidity_scoring_funcion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Instantaneous liquidity scoring function

## Summary

While by default the market uses probability of trading to calculate the [liquidity score](./0042-LIQF-setting_fees_and_rewarding_lps.md#calculating-the-instantaneous-liquidity-score) it should also be possible to explicitly prescribe the instantaneous liquidity scoring function. When such function is specified then it gets used for liquidity score calculation and probability of trading is ignored.

## Specifying the function

The function gets specified separately for each side of the book as:

* `reference`: reference point to which offset from each `point` is to be applied. It can be `MID` or `BEST BID` / `BEST ASK` depending on the side of the book for which the function is specified.
* `points`: collection of `(offset, value)` tuples providing a discrete representation of the function. Tuple `(10,0.4)` means that the value of the instantaneous liquidity function for a price level of reference point with an offset of `10` is `0.4` (specified in the same way as for [pegged orders](./0037-OPEG-pegged_orders.md)).
* `interpolation strategy`: prescribes a way in which price levels not covered by `points` should be calculated. Should be either `FLAT` resulting in a piecewise-constant function (starting from a lowest offset the value specified for it is assumed to prevail until the next offset is reached) or `LINEAR` resulting in a linear interpolation between points.

Flat extrapolation is always carried out, that is when price level greater than point with a highest offset or smaller than that with a lowest offset needs to be scored we use the nearest values that's been specified.

Validation:

* same as pegged orders for `reference` and `offset`,
* at least two `points` must be specified.

When liquidity scoring function is not specified [probability of trading](./0034-PROB-prob_weighted_liquidity_measure.ipynb) should be used for [liquidity score](./0042-LIQF-setting_fees_and_rewarding_lps.md#calculating-the-instantaneous-liquidity-score) calculation by default. It should also be possible to change it back to a `nil` value later on in market's life to stop using the function prescribed before and return to the default behaviour.
16 changes: 16 additions & 0 deletions protocol/features.json
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,22 @@
"0019-MCAL-158"
]
},
"Model-free alternatives": {
"milestone": "colosseo_II",
"acs": [
"0016-PFUT-026",
"0016-PFUT-027",
"0016-PFUT-028",
"0053-PERP-047",
"0053-PERP-048",
"0053-PERP-049",
"0032-PRIM-041",
"0032-PRIM-042",
"0032-PRIM-043",
"0042-LIQF-095",
"0042-LIQF-096"
]
},
"Unknown": {
"milestone": "unknown",
"acs": []
Expand Down
1 change: 1 addition & 0 deletions wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ permissioned
permissionless
PERP
perps
piecewise
PME
PnL
PoS
Expand Down
Loading