Skip to main content

Market Maker Protection (MMP)

Fill-window limits and auto-cancel behavior for market makers.

Every wallet-scoped MMP endpoint requires EIP-712 authentication. Configuration writes accept the wallet owner or an authorized agent for that wallet. Reads are owner-only and reject authorized-agent signatures.

For read-after-write consistency, send X-Hypercall-Fence-Wait: 1 on any MMP mutation. A successful response then includes X-Hypercall-Fence; echo that value as X-Hypercall-Fence on the authenticated GET. Mutations without the opt-in wait header intentionally do not return a fence.

Overview

MMP protects market makers from rapid adverse fills by:

  1. Tracking cumulative fill metrics within a rolling time window
  2. Canceling orders when limits are breached
  3. Auto-canceling all other MMP-enabled orders for the same wallet+underlying

Configuration

Set MMP Config

Endpoint: POST /mmp-config

Request: SetMmpConfigRequest

{
"wallet": "0x...",
"currency": "BTC",
"interval_ms": 60000,
"frozen_time_ms": 300000,
"qty_limit": "1000000",
"delta_limit": "10.0",
"vega_limit": "5.0",
"nonce": 1,
"signature": "0x..."
}

Fields:

  • wallet: Wallet address
  • currency: Underlying currency (e.g., "BTC", "ETH")
  • interval_ms: Rolling window length in milliseconds
  • frozen_time_ms: Freeze duration after trigger (milliseconds)
  • qty_limit: Optional quantity limit (contract units), serialized as a decimal string
  • delta_limit: Optional delta limit, serialized as a decimal string
  • vega_limit: Optional vega limit, serialized as a decimal string
  • nonce: Replay-protection nonce, exactly one greater than the latest committed nonce returned by the authenticated read
  • signature: EIP-712 SetMmpConfig signature over every request field

Response: ApiResponse<MmpConfigData>

Get MMP Config

Endpoint: GET /mmp-config?wallet=...&currency=...

Query parameters:

  • wallet (required)
  • currency (optional filter)

Required headers:

  • X-Hypercall-Expires-At-Ms: Unix expiry in milliseconds, no more than 60 seconds in the future
  • X-Hypercall-Signature: GetMmpConfig signature over wallet, currency (empty string when omitted), and the header expiry

The recovered signer must be the wallet owner. Authorized-agent signatures are not accepted for this read.

Response: MmpConfigResponse

{
"success": true,
"data": [
{
"wallet_address": "0x...",
"currency": "BTC",
"interval_ms": 60000,
"frozen_time_ms": 300000,
"qty_limit": "1000000",
"delta_limit": "10.0",
"vega_limit": "5.0",
"enabled": true,
"nonce": 1
}
]
}

Delete MMP Config

Endpoint: DELETE /mmp-config

Request: DeleteMmpConfigRequest

{
"wallet": "0x...",
"currency": "BTC",
"nonce": 1,
"signature": "0x..."
}

Response: ApiResponse<String>. A successful command disables the numeric wallet/underlying authority state. With request header X-Hypercall-Fence-Wait: 1, the response includes X-Hypercall-Fence for the projection-backed read.

Reset MMP State

Endpoint: POST /mmp-config/reset

Request: ResetMmpRequest

{
"wallet": "0x...",
"currency": "BTC",
"nonce": 1,
"signature": "0x..."
}

Response: ApiResponse<String>. A successful command clears the MMP fill window and freeze state in replayable authority. With request header X-Hypercall-Fence-Wait: 1, the response includes X-Hypercall-Fence for the projection-backed read.

MMP Behavior (Critical to Understand)

Fill Processing Order

MMP evaluation is POST-FILL:

  1. Engine matches and accepts the fill first
  2. Then MMP checks cumulative metrics
  3. If limits are breached:
    • MMP triggers
    • Remaining quantity on active order stops processing
    • Order becomes CANCELED with reason: "MMP triggered during fill processing"
    • Engine emits MmpTriggered event
    • Engine auto-cancels all other MMP-enabled open orders for the same wallet+underlying

Implication: You can receive fills that push you beyond your configured thresholds before MMP triggers.

Trigger Conditions

MMP triggers if any configured limit is breached:

  • Quantity limit: cumulative_qty > qty_limit
  • Delta limit: |cumulative_delta| > delta_limit
  • Vega limit: |cumulative_vega| > vega_limit

Cumulative metrics are computed over the rolling window (interval_ms).

Cancel Behavior

When MMP triggers:

  1. Active order: Remaining quantity stops, order becomes CANCELED with reason "MMP triggered during fill processing"
  2. Other orders: All other MMP-enabled open orders for the same wallet+underlying are auto-canceled with reason "Order canceled by MMP trigger"

Note: Only MMP-enabled orders are canceled. Orders with mmp_enabled=false are not affected.

Freeze Behavior

After MMP triggers:

  • Currency is frozen for frozen_time_ms milliseconds
  • While frozen, new fills may be rejected (implementation-dependent)

Fill Metrics Calculation

Quantity

  • Source: Fill size (contract units)
  • Cumulative: Sum of all fills in the rolling window

Delta

  • Source: Calculated from fill symbol and GreeksCache
  • Cumulative: Sum of all fill deltas in the rolling window

Vega

  • Source: Calculated from fill symbol and GreeksCache
  • Cumulative: Sum of all fill vegas in the rolling window

Rolling Window

Window Eviction

Fills older than interval_ms are automatically evicted from the window:

  • Eviction runs periodically (background task)
  • Cumulative metrics are decremented as old fills are removed

Window Reset

Reset MMP state via POST /mmp-config/reset:

  • Clears all fills in the window
  • Resets cumulative metrics to zero
  • Unfreezes currency

MMP Events

MmpTriggered Event

Internal event (not currently forwarded to WS clients):

MmpTriggeredMessage {
wallet: WalletAddress,
currency: String,
reason: String, // "qty_limit" | "delta_limit" | "vega_limit"
}

Best Practices

Configuration

  1. Set appropriate limits: Based on your risk tolerance and typical fill sizes
  2. Use currency-specific configs: Configure per underlying (BTC, ETH, etc.)
  3. Monitor MMP triggers: High trigger rate may indicate misconfigured limits or adverse market conditions

Order Management

  1. Enable MMP selectively: Set mmp_enabled=true only for orders you want protected
  2. Use consistent currency: Ensure all orders for the same underlying use the same currency in MMP config
  3. Handle MMP cancels: Implement logic to detect MMP-triggered cancels and adjust quoting

Monitoring

  1. Track MMP triggers: Monitor for "MMP triggered during fill processing" and "Order canceled by MMP trigger" reasons
  2. Review fill windows: Check cumulative metrics via MMP config (not exposed via API currently)
  3. Adjust limits: If MMP triggers too frequently, increase limits; if too infrequently, decrease limits

Common Issues

MMP Triggers Too Frequently

Causes:

  • Limits too low for typical fill sizes
  • Adverse market conditions
  • Rapid quoting causing many fills

Solutions:

  • Increase qty_limit, delta_limit, or vega_limit
  • Increase interval_ms to allow more fills in window
  • Reduce quoting frequency

MMP Doesn't Trigger

Causes:

  • Limits too high
  • MMP not enabled on orders (mmp_enabled=false)
  • Currency mismatch (MMP config currency != order underlying)

Solutions:

  • Decrease limits
  • Verify mmp_enabled=true on orders
  • Verify MMP config currency matches order underlying

Unexpected Cancels

Symptom: Orders canceled with reason "Order canceled by MMP trigger" but you didn't expect it.

Cause: Another order for the same wallet+underlying triggered MMP.

Solution: Review all MMP-enabled orders for the same underlying when one triggers.