> ## Documentation Index
> Fetch the complete documentation index at: https://v3.docs.derive.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Market Maker Protection

> Auto-cancel a maker's quotes and freeze trading when fills breach configurable thresholds within a rolling window.

Market Maker Protection (MMP) is a safety mechanism for makers. It watches the fills a
subaccount takes within a rolling time window and, when cumulative fills breach a
configured threshold, **freezes** that subaccount for a currency: its resting MMP orders
and quotes are cancelled and further trades in that currency are rejected until the freeze
expires or is manually reset.

MMP protects against rapid adverse selection — for example a stale quote getting swept
across many strikes faster than a maker can react.

<Note>
  MMP is configured **per subaccount, per currency** (e.g. `ETH`, `BTC`). Freezes are also scoped to a single currency:
  a freeze on `ETH` does not block trading in `BTC`.
</Note>

## How it works

<Steps>
  <Step title="Opt orders in">
    Only fills from orders and quotes submitted with the [per-order `mmp` flag](/trading/order-types) set to `true` count toward
    MMP limits. Non-MMP orders are ignored by the tracker.
  </Step>

  <Step title="Fills accumulate in a rolling window">
    Each MMP fill is recorded with its absolute traded amount and its signed delta. The engine keeps a sliding window of
    length `mmp_interval` and sums fills inside it.
  </Step>

  <Step title="Breach trips the freeze">
    If cumulative traded amount exceeds `mmp_amount_limit`, **or** the absolute cumulative delta exceeds
    `mmp_delta_limit`, the subaccount is frozen for that currency. Its open MMP orders and quotes are cancelled.
  </Step>

  <Step title="Freeze expires or is reset">
    The freeze lasts `mmp_frozen_time`. When it elapses the subaccount can trade again. A freeze of `0` duration is
    permanent until you call [`private/reset_mmp`](#reset-a-tripped-state).
  </Step>
</Steps>

<Info>
  A limit of `0` disables that check — set only `mmp_amount_limit` or only `mmp_delta_limit` if you want a single
  trigger. An `mmp_interval` of `0` disables MMP entirely for that (subaccount, currency).
</Info>

## Configuration fields

| Field              | Type           | Meaning                                                                                  |
| ------------------ | -------------- | ---------------------------------------------------------------------------------------- |
| `subaccount_id`    | integer        | Subaccount the config applies to.                                                        |
| `currency`         | string         | Settlement currency the config applies to (e.g. `ETH`).                                  |
| `mmp_interval`     | integer (ms)   | Length of the rolling window over which fills are summed.                                |
| `mmp_frozen_time`  | integer (ms)   | How long the freeze lasts once tripped. `0` = frozen until manually reset.               |
| `mmp_amount_limit` | decimal string | Cumulative **absolute traded amount** in the window that trips the freeze. `0` disables. |
| `mmp_delta_limit`  | decimal string | Cumulative **absolute net delta** in the window that trips the freeze. `0` disables.     |

<Note>
  `mmp_interval` and `mmp_frozen_time` are milliseconds. Amount and delta limits are plain decimal strings in the
  instrument's units. Each `set_mmp_config` call is a full upsert: every field is written, and an omitted
  `mmp_amount_limit` / `mmp_delta_limit` defaults to `0`.
</Note>

Setting or resetting MMP requires a session key with the `trade:all`
[scope](/authentication/access-scopes); reading the config requires only an authenticated session.

## Configure MMP — `private/set_mmp_config`

<CodeGroup>
  ```typescript TypeScript (SDK) theme={null}
  import { DeriveClient } from '@derivexyz/derive-ts';

  const client = new DeriveClient({
    network: 'mainnet',
    wallet: process.env.PRIVATE_KEY!,
  });
  await client.connect();
  await client.login();

  const config = await client.orders.setMmpConfig({
    subaccountId: 12345,
    currency: 'ETH',
    mmpInterval: 5000,
    mmpFrozenTime: 60000,
    mmpAmountLimit: '50',
    mmpDeltaLimit: '10',
  });
  ```

  ```python Python (SDK) theme={null}
  # Coming soon.
  ```

  ```rust Rust (SDK) theme={null}
  // Coming soon.
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.derive.xyz/v3/private/set_mmp_config \
    -H "Content-Type: application/json" \
    -H "X-DeriveWallet: $WALLET_ADDRESS" \
    -H "X-DeriveTimestamp: $TS" \
    -H "X-DeriveSignature: $SIG" \
    -d '{
      "subaccount_id": 12345,
      "currency": "ETH",
      "mmp_interval": 5000,
      "mmp_frozen_time": 60000,
      "mmp_amount_limit": "50",
      "mmp_delta_limit": "10"
    }'
  ```

  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "private/set_mmp_config",
    "params": {
      "subaccount_id": 12345,
      "currency": "ETH",
      "mmp_interval": 5000,
      "mmp_frozen_time": 60000,
      "mmp_amount_limit": "50",
      "mmp_delta_limit": "10"
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "subaccount_id": 12345,
      "currency": "ETH",
      "mmp_interval": 5000,
      "mmp_frozen_time": 60000,
      "mmp_amount_limit": "50",
      "mmp_delta_limit": "10"
    }
  }
  ```
</CodeGroup>

The example freezes `ETH` trading for 60 seconds if this subaccount's MMP fills accumulate
more than 50 units of absolute amount, or more than 10 units of net delta, within any
5-second window. The response echoes the stored config back.

## Read MMP config — `private/get_mmp_config`

Returns one row per configured `(subaccount_id, currency)`. Pass `currency` to fetch a
single row, or omit it to return every currency for the subaccount.

<CodeGroup>
  ```typescript TypeScript (SDK) theme={null}
  import { DeriveClient } from '@derivexyz/derive-ts';

  const client = new DeriveClient({
    network: 'mainnet',
    wallet: process.env.PRIVATE_KEY!,
  });
  await client.connect();
  await client.login();

  const configs = await client.send('private/get_mmp_config', {
    subaccount_id: 12345,
    currency: 'ETH',
  });
  ```

  ```python Python (SDK) theme={null}
  # Coming soon.
  ```

  ```rust Rust (SDK) theme={null}
  // Coming soon.
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.derive.xyz/v3/private/get_mmp_config \
    -H "Content-Type: application/json" \
    -H "X-DeriveWallet: $WALLET_ADDRESS" \
    -H "X-DeriveTimestamp: $TS" \
    -H "X-DeriveSignature: $SIG" \
    -d '{
      "subaccount_id": 12345,
      "currency": "ETH"
    }'
  ```

  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 2,
    "method": "private/get_mmp_config",
    "params": {
      "subaccount_id": 12345,
      "currency": "ETH"
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 2,
    "result": [
      {
        "subaccount_id": 12345,
        "currency": "ETH",
        "mmp_interval": 5000,
        "mmp_frozen_time": 60000,
        "mmp_amount_limit": "50",
        "mmp_delta_limit": "10",
        "is_frozen": false,
        "mmp_unfreeze_time": 0
      }
    ]
  }
  ```
</CodeGroup>

<ResponseField name="is_frozen" type="boolean">
  `true` while the subaccount is currently frozen for this currency.
</ResponseField>

<ResponseField name="mmp_unfreeze_time" type="integer">
  Unix epoch milliseconds at which the freeze lifts. `0` when not frozen; a very large value indicates a freeze that
  lasts until a manual reset.
</ResponseField>

## Reset a tripped state — `private/reset_mmp`

Clears the freeze and the rolling window so the subaccount can trade again immediately.
Pass `currency` to reset one currency, or omit it to reset every currency for the
subaccount.

<CodeGroup>
  ```typescript TypeScript (SDK) theme={null}
  import { DeriveClient } from '@derivexyz/derive-ts';

  const client = new DeriveClient({
    network: 'mainnet',
    wallet: process.env.PRIVATE_KEY!,
  });
  await client.connect();
  await client.login();

  await client.orders.resetMmp({ subaccountId: 12345, currency: 'ETH' });
  ```

  ```python Python (SDK) theme={null}
  # Coming soon.
  ```

  ```rust Rust (SDK) theme={null}
  // Coming soon.
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.derive.xyz/v3/private/reset_mmp \
    -H "Content-Type: application/json" \
    -H "X-DeriveWallet: $WALLET_ADDRESS" \
    -H "X-DeriveTimestamp: $TS" \
    -H "X-DeriveSignature: $SIG" \
    -d '{
      "subaccount_id": 12345,
      "currency": "ETH"
    }'
  ```

  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 3,
    "method": "private/reset_mmp",
    "params": {
      "subaccount_id": 12345,
      "currency": "ETH"
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 3,
    "result": "ok"
  }
  ```
</CodeGroup>

<Tip>
  While frozen, any new trade in the frozen currency is rejected before settlement. Watch your subaccount order stream
  for cancellations tagged with an MMP trigger, then call `private/reset_mmp` once you have re-priced.
</Tip>

## Cancel on disconnect

MMP guards against adverse fills; **cancel-on-disconnect (COD)** guards against a
dropped connection. When a COD-enabled connection drops, the exchange
automatically cancels that wallet's resting orders, quotes, and trigger orders —
so a network failure never leaves stale quotes on the book. Graceful server
shutdowns cancel COD-enabled connections too.

For a market maker the two are complementary: MMP reacts to fills breaching your
thresholds; COD reacts to losing the session entirely.

COD is a **persisted account setting** (not a per-message flag), toggled with
`private/set_cancel_on_disconnect` and gated by the `Trade(All)` scope — once
enabled it applies to every new connection until you disable it.

<Card title="Cancel on disconnect" href="/trading/cancel-on-disconnect">
  Full behaviour, the `private/set_cancel_on_disconnect` request, and scope requirements.
</Card>

## Related

<CardGroup cols={2}>
  <Card title="Order types" href="/trading/order-types">
    Set the per-order `mmp` flag to include an order in MMP tracking.
  </Card>

  <Card title="Access scopes" href="/authentication/access-scopes">
    The `trade:all` scope required to set and reset MMP.
  </Card>
</CardGroup>


## Related topics

- [Reset market maker protection freeze](/api-reference/market-maker-protection/reset-market-maker-protection-freeze.md)
- [Get market maker protection config](/api-reference/market-maker-protection/get-market-maker-protection-config.md)
- [Set market maker protection config](/api-reference/market-maker-protection/set-market-maker-protection-config.md)
