> For the complete documentation index, see [llms.txt](https://docs.callput.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.callput.app/traders/pricing-mechanism.md).

# Pricing mechanism

## Pricing mechanism

Callput uses reference price inputs to derive an indicative mark price. A keeper then calculates a request-specific execution price. Settlement value applies after expiry under protocol rules. A submitted request is not an executed position. It can remain pending or resolve as `Executed` or `Cancelled`.

For the user-facing summary, read [Pricing and execution](/traders/pricing-and-execution.md). This page is the detailed mechanism reference.

### Value definitions

| Value            | Definition                                                   |
| ---------------- | ------------------------------------------------------------ |
| Reference price  | Market-data input used by the pricing process                |
| Mark price       | Indicative option value for market discovery                 |
| Execution price  | Request-specific value resolved by the queued execution flow |
| Settlement value | Protocol-defined value used for an expired position          |

Market closures, holidays, halts, gaps, stale data, oracle or reference-data failures, and liquidity conditions can affect availability and these values.

## Pricing surfaces

Callput pricing spans three surfaces.

| Surface               | Main values                                                              | Role                                    |
| --------------------- | ------------------------------------------------------------------------ | --------------------------------------- |
| Market-data backend   | `markIv`, `markPrice`, `riskPremiumRateForBuy`, `riskPremiumRateForSell` | discovery and quote exploration         |
| Keeper execution path | request-specific `markPrice` and `rpRate`                                | prepares a queued request for execution |
| Onchain contracts     | `markPrice`, `riskPremium`, `executionPrice`                             | resolves the final execution result     |

The important distinction is that the public feed exposes RP as a rate, while onchain execution uses an absolute `riskPremium` amount written for a specific `requestIndex`.

{% stepper %}
{% step %}

### Build the underlying futures reference

Before pricing an option, the backend computes an `underlyingFutures` value:

`underlyingFutures = futuresIndex * (1 + riskFreeRate * yearsToExpiration)`

The risk-free rate is selected from the expiry map for the underlying asset, then clamped to a bounded range before use. This gives the pricing model a term-aware futures reference instead of relying only on spot.
{% endstep %}

{% step %}

### Determine mark IV and mark price

Callput resolves mark IV and mark price in two stages.

#### Direct market path

If the instrument already has direct `markIv` and `markPrice` data, the system uses those values.

#### Fallback estimation path

If direct values are unavailable, the system:

1. filters instruments with the same underlying, expiry, and option side
2. finds the nearest strikes around the target strike
3. chooses an estimated mark IV from those nearby strikes
4. computes mark price from the pricing model

The mark-price formula is the Black-Scholes-style option formula applied to:

* `underlyingFutures`
* strike
* IV
* time to expiry
* call or put direction

#### Spread pricing path

For two-leg spreads:

* spread mark IV is the average of the two leg IVs
* spread mark price is `max(mainLegMarkPrice - pairedLegMarkPrice, 0)`

This is why Callput spread prices are derived from the net structure of the legs, not from a flat packaged spread quote.
{% endstep %}

{% step %}

### Compute the request's trade greeks and moneyness

Risk premium starts from the trade itself.

The backend computes:

* `newTradeGreeks`
* `newTradeMoneyness`

These are derived from the actual option structure being traded:

* underlying
* expiry
* call or put direction
* long or short direction
* size
* main leg
* paired leg if the strategy is a spread
  {% endstep %}

{% step %}

### Compare current OLP state with post-trade OLP state

Callput does not price RP from the trade alone. It prices RP from how that trade changes protocol-side exposure.

The RP path uses:

* current OLP greeks, referred to here as `G0`
* post-trade OLP greeks, referred to here as `G1`
* current utility ratio, `UR0`
* post-trade utility ratio, `UR1`

The direction of the adjustment depends on whether the request is opening or closing:

* for open requests, post-trade OLP greeks move opposite to the new trade greeks
* for close requests, post-trade OLP greeks move in the same direction as the new trade greeks

That distinction is one reason open and close flows do not price identically.
{% endstep %}

{% step %}

### Build the RP rate

The RP rate is not one constant. It is built from multiple layers.

#### Exposure-scaling layer

The backend computes bounded unit percentages from the relationship between `G0` and `G1`, then applies a size-scaling factor derived from OLP deposited USD buckets. This produces normalized unit greeks for delta, vega, and theta.

#### Term-weight layer

Those normalized greeks are weighted by asset-specific term tables. Short-dated and longer-dated options therefore do not receive the same RP treatment.

If the trade reduces exposure in the same sign direction, the greek contribution is discounted. If it increases or flips exposure, the full weight applies.

#### Utility-ratio and moneyness layer

The backend then applies:

* an RP multiplier derived from moneyness and days to expiry
* a utility-ratio multiplier derived from `UR0` and `UR1`

This is the part that makes OLP utilization matter directly for execution pricing.

#### Asset and option-direction layer

The final buy-side RP rate is built from:

`rpRateForBuy = TOTAL_RATIO * baseRp * rpMultiplier * urMultiplier * UNDERLYING_ASSET_RATIO * CALL_PUT_RATIO`

The sell-side RP rate is then capped from the buy-side rate:

`rpRateForSell = min(rpRateForBuy, RP_MAX_RATE_FOR_SHORT_TERM)`

#### Volatility-score layer

If delta moves in the risk-increasing direction, the backend adds a volatility-score adjustment.

The final result is:

* `riskPremiumRateForBuy`
* `riskPremiumRateForSell`

These are the RP-rate values shown in the public market feed.
{% endstep %}

{% step %}

### Recompute RP for the actual queued request

When a queued request is about to execute, the keeper does not blindly reuse the public feed snapshot.

Instead, it recalculates:

* `markPrice`
* actual request size
* request-specific `rpRate`

for the actual request context:

* `optionTokenId`
* `requestIndex`
* current OLP state
* open or close direction

The keeper then converts RP from a rate into an absolute premium amount:

`riskPremium = markPrice * rpRate`

That amount is serialized and written onchain for the specific `optionTokenId` and `requestIndex`.

This is why RP is both:

* a public discovery-rate concept in the market feed
* an onchain request-specific premium amount during execution
  {% endstep %}

{% step %}

### Resolve final execution price onchain

Once `markPrice` and `riskPremium` are available onchain, the contracts resolve execution with a directional sign rule.

| Flow  | Trader direction      | Execution rule            |
| ----- | --------------------- | ------------------------- |
| Open  | buy / long exposure   | `markPrice + riskPremium` |
| Open  | sell / short exposure | `markPrice - riskPremium` |
| Close | close long exposure   | `markPrice - riskPremium` |
| Close | close short exposure  | `markPrice + riskPremium` |

In practical terms:

* open buys and close sells execute above mark
* open sells and close buys execute below mark
  {% endstep %}
  {% endstepper %}

## Invalid-price and guard conditions

Execution is not allowed in every state.

The current pricing path rejects or invalidates flows when:

* open sell would require `markPrice - riskPremium <= 0`
* close buy would require `markPrice - riskPremium <= 0`
* open buy fails the minimum mark-price check enforced by `minMarkPrices`
* the relevant fast price is stale
* request constraints such as `_minSize`, `_minAmountOut`, or `_minOutWhenSwap` cannot be satisfied

The result can be a normal `Cancelled` outcome rather than an unexpected protocol failure.

## What traders and builders should take away

* `markPrice` is not the full execution price
* the public feed exposes RP as a rate, but onchain execution uses an absolute premium amount
* request timing and queue position matter because RP is request-index aware
* OLP inventory and utilization are part of the pricing mechanism
* a displayed market is useful for discovery, but final execution still depends on the current keeper and onchain state
