> For the complete documentation index, see [llms.txt](https://docs.dimes.fi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.dimes.fi/for-developers/order-types/partial-close.md).

# Partial Close

Shrink an open leveraged position by selling part of it, without closing the whole thing. The position stays open at a smaller size.

> **Beta feature — enabled per partner.** Until it is enabled for your API key, `GET /positions/{id}/partial-closes` and any `requestPartialClose` call relayed through `POST /relayer-submissions` return 400 `beta_feature_not_enabled`, and `current.min_partial_close_token_units` / `current.max_partial_close_token_units` are `null` on every position. Contact us to have it enabled.

A normal [close](/for-developers/wallet-integration/on-chain-integration.md#closing-a-position) exits the entire position. A **partial close** sells only a slice: the position stays open at a reduced size, with the proportional capital repaid. Use it to take partial profit, trim exposure, or de-risk a position you still want to hold.

The position's `status` stays `open` the whole time — request, execution, and after.

## How it works

One user transaction; the backend does the rest.

```
User action                               Backend (automatic)
───────────                               ───────────────────
Call requestPartialClose(key, units) ───► Detect event
                                          Withdraw the slice off-vault
                                          Sell the slice on the exchange
                                          Repay proportional capital, finalize on-chain
                                          ──► position stays open at reduced size
```

Three outcomes, all handled for you:

* **The slice sells.** Capital is repaid proportionally and the position continues at its new smaller size and lower leverage.
* **The slice partially fills.** The unsold remainder returns to the position; only the sold fraction is booked.
* **Nothing fills.** The request is aborted and the position is restored unchanged.

Once finalized, the position is an ordinary open position again — request another partial close, or a full [close](/for-developers/wallet-integration/on-chain-integration.md#closing-a-position) of what remains.

A note on very small positions: sales are rounded down to the exchange's lot size, so a position reduced many times can be left holding a remainder too small to sell. It stays with the position and redeems when the market resolves.

## Calling the contract

Only the position owner (the wallet that called `createPosition`) can request a partial close. The `positionKey` is the `on_chain_position_key` field from `GET /positions`; `closeTokenUnits` is the number of position tokens to sell, which must be less than the position's current `current.position_token_units` and leave a non-trivial remainder.

{% tabs %}
{% tab title="ethers.js" %}

```javascript
const VAULT_ABI = ["function requestPartialClose(bytes32 positionKey, uint256 closeTokenUnits) external"];
const vault = new ethers.Contract(vaultAddress, VAULT_ABI, signer);

const tx = await vault.requestPartialClose(position.on_chain_position_key, closeTokenUnits);
await tx.wait();
```

{% endtab %}

{% tab title="viem" %}

```typescript
import { buildRequestPartialCloseTx } from "@dimes-dot-fi/sdk/contract";

const tx = buildRequestPartialCloseTx(vaultAddress, position.on_chain_position_key, closeTokenUnits);

await walletClient.writeContract(tx);
```

For a deposit wallet, `buildRequestPartialCloseCalls` returns the batch calls to sign and relay the same way you relay a close — see [Smart Wallet Integration](/for-developers/wallet-integration/smart-wallet-integration.md).
{% endtab %}
{% endtabs %}

For smart-contract wallets, wrap `requestPartialClose` in the wallet's batch the same way you would `requestClose` (see [Smart Wallet Integration](/for-developers/wallet-integration/smart-wallet-integration.md)).

`requestPartialClose` is the only call your integration makes — every other partial-close function on the vault is executed by the backend. The full canonical vault ABI is published in the [UI repo](https://github.com/dimes-fi/dimes-demo-ui/blob/main/src/contract/canonical-leveraged-prediction-vault-v1-abi.json).

## Position fields

After a partial close completes, the `current.*` fields reflect the new, smaller position — fewer `position_token_units`, reduced `notional_*`, lower `book_leverage_bps` / `market_leverage_bps`. The `entry.*` fields never change; they describe the original open.

Positions mid-partial-close are returned by `GET /positions?status=open` and counted under the `active` state group.

Two basis-point fields tell an initial partial fill apart from a partial close:

* `entry.initial_fill_bps` — how much of the requested size was filled **at open**. Frozen at open; it does not move when the position is later partially closed. Use it for an "opened at X% of requested" badge.
* `current.remaining_bps` — how much of the originally opened size is **still held**. This drops after each partial close (e.g. `7000` = 70% left after a 30% close). Surface it as "remaining", not as a fill regression.

## History

Fetch the executed partial-close history for a position — tokens sold, average realized price, proceeds, capital repaid, owner payout, and the size/leverage left afterwards:

```
GET /prediction-markets/positions/{position_id}/partial-closes
```

```typescript
const { data } = await client.getPositionPartialCloses(positionId);
```

Only partial closes that finalized on-chain are returned, in chronological order. See [Position partial closes](/for-developers/api-and-events/api-reference.md#position-partial-closes-sub-resource) for the full field reference.

## WebSocket events

Four events track the slice. Each payload is the full position object in its open shape (`current` / `risk` / `fees` / `timing`), identical to the REST API — see [WebSocket Events](/for-developers/api-and-events/websocket.md).

| Event                              | When                                                                    |
| ---------------------------------- | ----------------------------------------------------------------------- |
| `position.partial_close_requested` | Owner's `requestPartialClose` was indexed; the slice is queued.         |
| `position.partial_close_initiated` | The slice was withdrawn and the sell order is in flight.                |
| `position.partial_closed`          | The partial close finalized; `current.*` now reflect the reduced size.  |
| `position.partial_close_aborted`   | The slice did not fill; the position was restored to its original size. |

All four carry an open position, so a single handler covers them:

```javascript
for (const event of [
  "position.partial_close_requested",
  "position.partial_close_initiated",
  "position.partial_closed",
  "position.partial_close_aborted",
]) {
  socket.on(event, ({ data }) => updateOpenPosition(data));
}
```

`position.partial_closed` fires for every successful finalize — whether the slice fully sold, partially filled, or was deleveraged by a concurrent risk unwind mid-slice. Treat them identically.
