Skip to main content

NSE/NSCCL SPAN margin calculator from CME-SPAN .spn files, with an order-basket margins API

Project description

marginism

Compute NSE / NSCCL SPAN margins directly from the exchange's daily CME-SPAN risk-parameter files (.spn, XML fileFormat 4.00), the same inputs a broker's margin calculator uses.

spanrisk.xml in this folder is the XSD schema that documents the .spn format; this library implements the SPAN algorithm against files that conform to it (e.g. nsccl.YYYYMMDD.s.spn).

Why this works without an option pricer

Each contract in a .spn file ships a precomputed 16-scenario risk array — the per-unit profit/loss under 16 combinations of price move (±1/3, ±2/3, ±3/3 of the scan range, plus two "extreme" moves) and volatility up/down. SPAN margin is therefore pure arithmetic over those arrays; no Black-Scholes is needed at calculation time.

The SPAN calculation

Per combined commodity (one underlying — futures + options margined together):

span_risk = max( scan_risk
                 + calendar (intra-commodity) spread charge
                 + spot/delivery charge          # 0 in NSCCL files
                 - inter-commodity spread credit  # 0 in NSCCL files
               , short_option_minimum )
  • Scan risk — the largest portfolio loss across the 16 scenarios: max_j Σ (signed_qty × risk_array[j]).
  • Calendar spread charge — scan assumes all expiries move together, so a flat charge is added back for the basis risk of long-near / short-far positions (dSpread definitions, method F).
  • Short option minimum (SOM) — a floor for short-option books (som_rate = 0 in these NSCCL files).

A broker's initial margin = SPAN margin + Exposure (ELM) margin. Exposure margin is not in the SPAN file (it's an exchange % of notional), so it is configured in ExposureConfig and applied to futures and short options.

Install / layout

Pure standard library (Python 3.8+), no dependencies. Drop the marginism/ folder on your path (or pip install -e .).

Pointing to your .spn file

You just give the path. Same folder or a different folder, macOS or Windows:

# Same folder as your script
SPN = "nsccl.20260529.s.spn"

# Different folder — macOS / Linux (forward slashes)
SPN = "/Users/you/Downloads/nsccl.20260529.s.spn"

# Different folder — Windows (use a raw string r"..." or forward slashes)
SPN = r"C:\Users\you\Downloads\nsccl.20260529.s.spn"
SPN = "C:/Users/you/Downloads/nsccl.20260529.s.spn"

Quick start

from marginism import SpanCalculator, Position

calc = SpanCalculator.from_file(
    SPN,
    symbols=["NIFTY", "RELIANCE"],   # parse only what you need (fast / light)
)

result = calc.calculate([
    # quantity is entered DIRECTLY in units: NIFTY lot size 65 -> 65 = 1 lot,
    # 130 = 2 lots. long +, short -
    Position("NIFTY", "CE", quantity=-65, expiry="20260630", strike=24000),
    Position("NIFTY", "PE", quantity=-65, expiry="20260630", strike=24000),
])

print(result.summary())
print(result.marginism, result.exposure_margin, result.total_margin)

Order-style API (single or multiple legs)

RiskEngine accepts orders by tradingsymbol and returns a broker-style dict (per-leg + consolidated initial/final + margin_benefit). Pure local computation — no network, no service.

from marginism import RiskEngine

eng = RiskEngine.from_file(SPN)

# one leg or many — a single order is just a basket of size one
res = eng.basket([
    {"exchange": "NFO", "tradingsymbol": "NIFTY26JUNFUT",
     "transaction_type": "BUY", "quantity": 65},
    {"exchange": "NFO", "tradingsymbol": "NIFTY26JUN23000PE",
     "transaction_type": "BUY", "quantity": 65},
])
data = res["data"]
print(data["final"]["total"], data["margin_benefit"])

quantity is entered directly in units (e.g. 65 for one NIFTY lot, 130 for two); transaction_type is BUY/SELL. The engine is exchange-agnostic — load an NFO, CDS, or MCX .spn file.

Two symbol formats, plus explicit fields

A contract can be named two equivalent ways, and both resolve automatically:

Style Future Option
compact NIFTY26JUNFUT NIFTY26JUN23700CE (monthly), NIFTY2660223700CE (weekly)
full-date NIFTY30JUN26FUT NIFTY30JUN2623700CE

Or skip tradingsymbols and pass fields directly:

eng.basket([
    {"symbol": "NIFTY", "instrument": "CE", "expiry": "2026-06-30",
     "strike": 23700, "transaction_type": "SELL", "quantity": 65},
])

Command line

python -m marginism <file.spn> --list                 # all symbols
python -m marginism <file.spn> --info NIFTY            # contracts/expiries
python -m marginism <file.spn> \
    --pos NIFTY:FUT:-65:20260630 \
    --pos NIFTY:CE:65:20260630:24000                     # margin for positions

Important notes

  • Lot sizes are not in the SPAN file. It works in underlying units, so enter quantity directly in units (NIFTY 65 = 1 lot, 130 = 2 lots).
  • No exchange tokens in the file. Instruments are keyed by trading symbol (cc / pfCode, e.g. RELIANCE), with internal pfId/cId ids that are not NSE tokens. Map a token (e.g. 2885RELIANCE) via a separate instrument master before calling this library.
  • Exposure rates in ExposureConfig are NSE defaults (index 2%, stock ~3.5%); override per circular via overrides={"RELIANCE": 0.05}.
  • Long options carry no exposure margin (risk capped at premium); their risk array still participates in the portfolio scan so hedges net correctly.
  • net_option_value is the mark-to-market value of option legs (premium): negative when net short (premium received), positive when net long.

Module map

Module Responsibility
parser.py streaming iterparse of .spn → data model (symbol filter)
model.py dataclasses: SpanFile, CombinedCommodity, contracts, risk arrays
algorithm.py SPAN math: scan risk, calendar spreads, SOM, net option value
portfolio.py Position input + expiry normalisation
exposure.py exposure / ELM configuration (index 2% / stock 3.5%)
calculator.py SpanCalculator — load once, evaluate many portfolios
symbols.py tradingsymbol ⇄ SPAN contract resolution
api.py RiskEnginebasket()/orders(), single or many legs
cli.py python -m marginism

100% standard library, runs fully offline — give it a .spn file and call a function.

Reference

Disclaimer

The software is provided "as is", without warranty of any kind. The author accepts no responsibility or liability for any errors or inaccuracies in the calculations, or for any trading losses, damages, or decisions arising from its use. Margins depend on the SPAN file and exposure rates you supply, may differ from your broker's, and must be independently verified before trading. Not financial advice; use at your own risk.

This is an independent project built by an independent developer. It is not affiliated with, sponsored by, endorsed by, or connected to NSE, NSE Clearing (NSCCL), the Chicago Mercantile Exchange (CME), or any broker or exchange.

SPAN® is a registered trademark of Chicago Mercantile Exchange Inc. All other trademarks are the property of their respective owners. Any names are used only for identification/descriptive purposes (nominative use) and do not imply any affiliation, endorsement, or license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

marginism-0.1.0.tar.gz (24.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

marginism-0.1.0-py3-none-any.whl (28.7 kB view details)

Uploaded Python 3

File details

Details for the file marginism-0.1.0.tar.gz.

File metadata

  • Download URL: marginism-0.1.0.tar.gz
  • Upload date:
  • Size: 24.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for marginism-0.1.0.tar.gz
Algorithm Hash digest
SHA256 43fd4e9e71f750cc2acb2a8e59237cbbe7f825e347add8c3ccb65b58745a4dad
MD5 f6c68c8e7b6cd88ddeb42bbe5a977b6e
BLAKE2b-256 62b03e35b049f7253936ebce5cd39a0cfa88204a711fe355106999813057b469

See more details on using hashes here.

File details

Details for the file marginism-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: marginism-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 28.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for marginism-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8337ea71823d379a0f90aed70d4b05c33264b4dbafae2413bb185c1431352083
MD5 df6609d5b5177ba736c42d5205357ee9
BLAKE2b-256 03ef8e2162612f207e948a67b0efddd2e91addf9957029bfc8708f828b47ab02

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page