Crypto perpetuals - sbOogway/sbt2 GitHub Wiki

Crypto perpetuals

The first asset class. First data source: Source Bybit (linear perps, L2 and trades).

Definition

Concern Choice
Key nautilus AssetClass.CRYPTOCURRENCY + InstrumentClass.SWAP
Instrument CryptoPerpetual, from the exchange's real spec
Calendar 24/7, no sessions
Annualization 365 days
Account margin account in the settlement currency (USDT for linear perps), netting (one-way mode), leverage
Liquidation off by default; venue config liquidation_enabled, liquidation_trigger_ratio, liquidation_cancel_open_orders, or the spec's liquidation key. Only works on runs that stream quotes (below)
Carry funding, settled natively by nautilus's simulated venue (below)
Reference prices mark price
Valuation price mark price, for mark-to-market equity: PortfolioConfig(use_mark_prices=True), fed by MarkPriceUpdate from the catalog
Buy-and-hold convention the perp's own mark-price series held with no funding, paying only the entry fee at the taker_rate of the run's venue fee model (v2 instruments carry no fees); a fee model without a taker rate fails. Behaves like spot without needing spot data.

Funding

Nautilus v2's simulated venue settles funding itself; sbt2 has no funding code. (Nautilus 1.231 delivered funding rates to strategies but never charged the account, which is why an earlier design had a custom module.)

  • At each funding boundary the venue charges or credits position notional at mark price × funding rate to every open position. A positive rate debits longs and credits shorts. With no mark price it falls back to top of book.
  • Each payment is a PositionAdjusted event of type Funding: it changes the position's realized PnL and the account balance together, so funding is in equity, PnL and every metric.
  • The carry ledger is read from those adjustments after the run (see Results).
  • The boundary is next_funding_ns when the update has one, otherwise the update's own ts_event, and only when that ts_event is an exact multiple of interval since the Unix epoch (for 8h: 00:00, 08:00 and 16:00 UTC). A record off that grid, even by 1 ns, is silently never charged. Bybit's funding history gives settlement times with the interval (usually 8h, 4h for some instruments such as XAUT), so each record settles at its own time. The source's parser fills in a missing interval from the instrument spec (for Bybit, the snapshot's fundingInterval); a record without one would never settle.
  • A 1 BTC long at a 50,000 mark and a +0.01% rate is debited exactly 5.00 USDT at the boundary. A position opened at the funding timestamp pays it. These rules are pinned by the nautilus characterization tests (see Quality).

Funding rates and mark prices are downloaded by the source and ingested into the catalog as FundingRateUpdate / MarkPriceUpdate, and stream with the run.

Liquidation

Nautilus's simulated venue checks maintenance margin on every data event, but it prices open positions only at the top-of-book quote (bid for longs, ask for shorts), not at mark price. A run that streams trades and mark prices but no quotes, which is every bar strategy, on trades or on candles, can therefore never liquidate. Instead nautilus logs a warning for every trade while a position is open. Pinned by the characterization test test_liquidation.py (see Quality).

  • The crypto-perp default is liquidation off. A run can turn it on with liquidation = true in its spec (see Spec), and pre-flight refuses that unless the run streams quotes (see Run).
  • With liquidation off, a position whose equity falls below maintenance margin stays open, and equity can go negative. Treat a run that gets near zero equity as blown.
  • The check is costly as well as noisy: on a month of BTCUSDT (76M trades) the run took 2 min 27 s with liquidation on and 54 s with it off.

Decisions

Decision Why
Funding settled by nautilus's venue, no custom module v2 does it at mark price and records it on the position; the earlier SimulationModule plan existed only because 1.231 didn't.
Funding uses mark price That's what perp exchanges charge on.
365-day annualization Crypto trades every day. v1 used 252.
Benchmark = perp price, no funding, entry fee only A perp benchmark that pays funding blurs the comparison; spot data isn't downloaded, and the perp price tracks spot closely.
Mark-to-market at mark price The exchange values positions at mark price for margin and liquidation too.
Liquidation off by default; on only for runs that stream quotes Nautilus liquidates only on quotes, so with trades alone it was silently never applied, while logging a warning per trade and slowing the run 2.7×.

Open items

  • Delisted symbols aren't served by the first source, so cross-sectional runs carry a survivorship warning.
  • How does nautilus's liquidation compare with the exchange's rules?