How Backtests Settle Perpetual Funding and Apply Margin Models
Summary
This guide explains how a simulated venue handles perpetual funding and account configuration during a backtest. Funding-rate updates supply the latest rate; when a funding boundary is known, the backtest clock creates a settlement at that time. Without an explicit next-funding timestamp, settlement occurs only when an update lands on the configured interval boundary. Updates without a boundary remain available as strategy data but do not trigger payments. Settlements adjust open positions and the corresponding account balance before the portfolio sees the updated state. Positive funding debits longs and credits shorts, affecting realized P&L and cash.
The document also describes the three supported account types—cash, margin, and betting—and shows low- and high-level ways to configure venues and starting balances. Margin accounts default to a leveraged margin model; a standard model reserves the instrument’s fixed initial and maintenance margin percentages without scaling them down by account leverage. The text is a configuration and accounting reference, not a comparison of model performance, and notes that the high-level configuration does not accept custom margin models from class-path strings.
Key ideas
- Funding settlements occur at explicit next-funding timestamps or, absent those, at interval boundaries identified by update timestamps.
- Funding adjustments affect open positions, realized P&L, and the matching account cash balance.
- A positive funding rate charges long positions and credits short positions.
- Backtest venues support cash, margin, and betting account types.
- Margin accounts default to leveraged margin calculations, while the standard model uses fixed instrument margin percentages.
Tags
Full text
# Backtest Accounts and Margin
# Backtest Accounts and Margin
Backtest venues use simulated accounts for balances, margin, and funding settlement. For the full
account model and margin formulas, see [Accounting](../accounting.md).
## Funding
Backtests settle perpetual funding at funding boundaries from `FundingRateUpdate` data. When an
update has `next_funding_ns`, the simulated exchange stores the latest rate, and the backtest clock
emits one `FundingSettlement` at that timestamp. Without `next_funding_ns`, the exchange settles
only when `ts_event` lands on the `interval` boundary. Updates without a boundary remain strategy
data and do not create funding payments.
```mermaid
flowchart LR
A[FundingRateUpdate] --> B[SimulatedExchange stores latest rate]
B --> C[Backtest clock reaches funding boundary]
C --> D[FundingSettlement]
D --> E[Open positions]
E --> F[PositionAdjusted: Funding]
E --> G[AccountState]
F --> H[Portfolio]
G --> H
```
The settlement adjusts the open position and the matching account balance before the portfolio
observes the new state.
`PositionAdjusted` remains the position accounting event. A positive funding rate debits long
positions and credits short positions. The resulting adjustment changes realized PnL, and the
matching account balance update records the cash movement.
## Accounts
Every backtest venue uses one of three `account_type` values: `CASH`, `MARGIN`, or `BETTING`.
The low-level API accepts model types directly:
```python
from decimal import Decimal
from nautilus_trader.backtest import BacktestEngine
from nautilus_trader.config import BacktestEngineConfig
from nautilus_trader.execution import MakerTakerFeeModel
from nautilus_trader.model import AccountType
from nautilus_trader.model import Money
from nautilus_trader.model import OmsType
from nautilus_trader.model import Venue
engine = BacktestEngine(BacktestEngineConfig())
engine.add_venue(
venue=Venue("BINANCE"),
oms_type=OmsType.NETTING,
account_type=AccountType.CASH,
starting_balances=[Money.from_str("10_000 USDT")],
fee_model=MakerTakerFeeModel(
maker_rate=Decimal("0.001"),
taker_rate=Decimal("0.001"),
),
)
```
The high-level API accepts the same enum values but represents starting balances as strings:
```python
from decimal import Decimal
from nautilus_trader.config import BacktestVenueConfig
from nautilus_trader.execution import MakerTakerFeeModel
from nautilus_trader.model import AccountType
from nautilus_trader.model import BookType
from nautilus_trader.model import OmsType
venue = BacktestVenueConfig(
name="SIM",
oms_type=OmsType.NETTING,
account_type=AccountType.CASH,
book_type=BookType.L1_MBP,
starting_balances=["10_000 USDT"],
fee_model=MakerTakerFeeModel(
maker_rate=Decimal("0"),
taker_rate=Decimal("0"),
),
)
```
## Margin models
Margin accounts use `LeveragedMarginModel` by default. Pass `StandardMarginModel` when the
simulation should reserve the instrument's fixed initial and maintenance margin percentages
without reducing them by account leverage.
```python
from decimal import Decimal
from nautilus_trader.config import BacktestVenueConfig
from nautilus_trader.execution import MakerTakerFeeModel
from nautilus_trader.model import AccountType
from nautilus_trader.model import BookType
from nautilus_trader.model import OmsType
from nautilus_trader.model import StandardMarginModel
venue = BacktestVenueConfig(
name="SIM",
oms_type=OmsType.NETTING,
account_type=AccountType.MARGIN,
book_type=BookType.L1_MBP,
starting_balances=["1_000_000 USD"],
margin_model=StandardMarginModel(),
fee_model=MakerTakerFeeModel(
maker_rate=Decimal("0"),
taker_rate=Decimal("0"),
),
)
```
`BacktestVenueConfig` accepts the built-in `StandardMarginModel` and `LeveragedMarginModel`
objects directly. The current high-level configuration does not load custom margin models from
class-path strings.Shown in full with attribution under the source's licence. Licence: LGPL-3.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.