Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.parquet.exchange/llms.txt

Use this file to discover all available pages before exploring further.

Partial close lets you reduce an existing Parquet position without exiting it entirely. It is not in the trading UI as of the current frontend — the Close button always closes the full position. The capability lives at the on-chain handler and is plumbed through the SDK, so power users and programmatic traders can call it directly. This page documents the closeSize parameter, its validation rules, fee treatment, and a worked example.

The closeSize parameter

The SDK exposes partial close through the same closePositionIx builder that does full closes:
closePositionIx(accounts, closeSize: BN | null)
The second argument is what determines the behavior:
  • null — full close. The entire position is unwound, collateral is released, and the position account is closed.
  • A BN value — partial close. The number is interpreted as USDC notional in 6-decimal base units. For example, new BN(100_000_000) closes $100 of notional.
On-chain, the handler:
  1. Computes the fraction closeSize / position.size_usdc.
  2. Realizes PnL on that fraction only, settling against the LP pool.
  3. Pro-rates collateral release by the same fraction.
  4. Decrements position.size_usdc by closeSize (the remaining position keeps its entry price unchanged — partial close is not a re-open).
  5. Updates open interest on the market accordingly.
The remaining position behaves identically to one that was opened smaller in the first place: same entry price, smaller size, smaller collateral, same liquidation math.

Validation

The instruction enforces three rules. Violating any of them returns an error before any state change.
RuleConditionError on failure
Size bound0 < closeSize ≤ position.size_usdcInvalidCloseSize
Min collateralRemaining collateral ≥ MIN_COLLATERAL_USDC ($10)BelowMinCollateral (code 2006)
Position healthPosition not already below maintenance marginSame gate as a full close
The min-collateral rule is the one that trips people up: if you have a 50positionwith50 position with 15 of collateral and try to close 40,theremaining40, the remaining 10 position would have only 3ofcollateral,whichisbelowthe3 of collateral, which is below the 10 floor. The instruction will reject the call. Either close less, or close fully.
There is no special path to close a position that is already below MMR. Partial close uses the same health gate as full close — if the position is liquidatable, you cannot exit it via closePosition; the keeper will liquidate it.

Fee treatment

Fees scale with the closed notional, not the full position size. Closing 25% of a 1,000positionpaysfeeson1,000 position pays fees on 250 of notional, not $1,000. The favorable-rate logic still applies, evaluated on the partial-close trade:
  • Base rateBASE_FEE_BPS = 0.1% (10 bps), applied to the closed notional.
  • Favorable rateFEE_BPS_FAVORABLE = 0.05% (5 bps), applied if the partial close reduces OI imbalance for the market. The check is the same as for a full close: if your side is the heavier side of the book, closing reduces imbalance and you pay the favorable rate.
The canonical fee constants live in the monorepo’s docs/reference/published-numbers.md — see the sources trailer at the bottom of this page for the verified values.
If you are unwinding a profitable position on the heavier side of OI and want to capture the favorable rate, partial closes let you do this in tranches — each tranche is evaluated independently against the OI imbalance at the moment it lands.

Example: close 25% of a position

The following snippet closes $100 of a position via direct instruction construction. It assumes you already have a PerpClient and have looked up the relevant PDAs.
import { PerpClient } from "@parquet/sdk"; // build-from-source for now
import { BN, AnchorProvider } from "@coral-xyz/anchor";
import { Transaction } from "@solana/web3.js";

const perp = new PerpClient(program);

// Close $100 of notional. Units are USDC 6-decimal base units,
// so 100 * 1_000_000 = 100_000_000.
const closeSizeUsdc = new BN(100_000_000);

const ix = await perp.closePositionIx(
  {
    owner,
    position: positionPda,
    marketState: marketPda,
    marketOracle: oraclePda,
    priceFeed: priceFeedPda,
    // ... remaining accounts per the IDL (vaults, fee distributor, token program, etc.)
  },
  closeSizeUsdc, // pass null here for a full close
);

const tx = new Transaction().add(ix);
await provider.sendAndConfirm(tx, []);
To close a percentage rather than a fixed dollar amount, compute it from the on-chain position:
const position = await perp.fetchPosition(positionPda);
const quarter = position.sizeUsdc.divn(4); // closeSize = 25% of size

const ix = await perp.closePositionIx(accounts, quarter);
The closePositionIx builder returns a plain TransactionInstruction, so you can add it to a transaction alongside compute-budget instructions, priority fees, or other actions.

Why isn’t this in the UI?

Honest answer: scope. The v1 launch frontend prioritized the open / close / margin-adjust loop with a single Close button, and partial close did not make the cut. The on-chain handler is general — it has always supported partial closes — and the SDK was wired up alongside it. Exposing a “Close 25% / 50% / 75% / 100%” selector or a free-form size input in the trade panel is tracked as a follow-up; in the meantime, power users get full access via the SDK. If you want to reduce risk on a position from the UI today, the supported path is to add margin rather than reduce size — see Margin management for that flow.

See also