# Position Fees

## Overview

Position fees are periodic charges applied to all open positions on an instrument, proportional to the absolute size of each position. Unlike funding charges, position fees are not a transfer between long and short holders. Instead, the collected fees are deposited into a designated **beneficiary account** (such as the insurance fund).

Position fees may also be configured as **rebates** (a negative fee), in which case the beneficiary account pays out to position holders rather than collecting from them.

The administrator triggers each position fee round via the control gateway API, supplying a rate and reference price for each instrument. The engine then charges (or credits) every open position on those instruments.

## Calculation

The rate and reference price mechanism is identical to funding. The engine accumulates a cumulative total rate from inception to prevent rounding errors from building up over successive rounds.

### Simple Rate

The fee for a position in a given round is:

$$
\text{Fee} = |\text{Position}| \times P_k \times R_k
$$

where $P_k$ is the reference price and $R_k$ is the rate for round $k$.

To prevent rounding errors, the engine tracks the total position fee rate since inception:

$$
F(n) = \sum_{k=1}^n R_k P_k
$$

At round $n+1$, the charge applied to a position $C$ is:

$$
F_T = F(n+1) \times |C| - F(n) \times |C|
$$

#### Example

Two accounts hold positions on a linear BTC future with an inverse step size of 1,000,000 (each contract represents 0.000001 BTC). The administrator applies a position fee with $R = 0.01\%$ and $P = 50{,}000$.

```
Instrument:     Linear BTC future, inverse step size 1,000,000
Long account:   +2,000,000 contracts = 2 BTC notional
Short account:    −800,000 contracts = 0.8 BTC notional

Fee for long account  = (2,000,000 / 1,000,000) × 50,000 × 0.0001 = 2 × 5 = 10.00
Fee for short account =   (800,000 / 1,000,000) × 50,000 × 0.0001 = 0.8 × 5 =  4.00

Total deposited to beneficiary account = 14.00
```

Both positions are charged based on the **absolute** size.

### Cost per Contract

As with funding, an alternative mode allows the administrator to specify a fixed cost per number of contracts rather than a rate applied to a reference price. The engine uses the same cumulative approach to avoid rounding error accumulation.

## Fee Payment

Position fees are collected from the following sources, in order.

### Account Balance

The fee is deducted first from the account's available balance.

### Unrealized PnL

If an account does not have sufficient balance to cover the position fee, but holds unrealized profits on the charged instrument, the engine will draw on those unrealized gains to cover the shortfall. This is achieved by adjusting the position entry price to a slightly less favorable value, reducing the unrealized PnL by the required amount. Two executions of equal and opposite size, marked as PaymentByUnrealizedPnl, record this adjustment.

#### Example

```
Instrument:   Linear BTC future, inverse step size 1,000,000
Position:     Long 2,000,000 contracts (= 2 BTC notional)
Entry price:  49,800
Mark price:   50,000
Balance:       6.00
Fee owed:     10.00

Unrealized PnL = (50,000 − 49,800) × 2 = 400.00
Paid from balance:             6.00
Remaining from unrealized PnL: 4.00

New Unrealized PnL = 400.00 − 4.00 = 396.00
New Entry Price    = 50,000 − (396.00 / 2) = 49,802.00
```

### Unrealized PnL on Other Instruments

Adjusting the entry price of the charged instrument to collect unrealized PnL may not always be possible: the required adjustment could push the entry price above the instrument's maximum price or below its minimum price. In that case, the engine caps the entry price at the relevant bound and, if the account holds positions on other instruments, applies the remaining shortfall using the same PaymentByUnrealizedPnl mechanism on one of those other positions.

### Liquidation

If the position fee exceeds what can be covered by the account's balance and unrealized PnL, the account is liquidated. The insurance fund covers any remaining shortfall via a balance reset, and the normal liquidation workflow follows.

## Rebates

When the fee rate is negative, the beneficiary account pays a rebate to each position holder in proportion to the absolute size of their position.

### Beneficiary Account Margin Check

Before applying a rebate round, the engine performs an **initial margin check** on the beneficiary account. If the beneficiary account does not have sufficient margin to cover all rebates to be paid, the entire position fee round is **rejected**. No rebates are applied to any position.

## Error Cases

| Condition | Outcome |
|---|---|
| An instrument in the request does not exist | The entire position fee round is rejected; no instruments are charged |
| The fee round ID has already been used | The request is rejected as a duplicate |
| A rebate round where the beneficiary account lacks sufficient margin | The entire rebate round is rejected |
| The fee would exceed the maintenance margin floor for the instrument | The charge is rejected (the rate supplied is too large relative to the reference price) |

## State and History

The timestamp of the most recent position fee event is tracked per instrument and is included in the instrument's state-of-the-world output. This allows clients to determine when position fees were last applied for any futures instrument.

Each position fee round also generates a transaction record for every position that was charged, and a response message summarizing the fees collected across all positions.
