Skip to main content

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.
  • Expiry-day ELM: an extra ELM (default 2%, ExposureConfig.expiry_day_elm_pct) is added on short options that expire on the trading date. The trading date defaults to the SPAN file's business date; override with calculate(..., as_of_date=...) / basket(..., as_of_date=...). Reported under additional. Set the rate to 0 to disable.

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.

Release files for marginism 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for marginism 0.1.1
File Size Uploaded
marginism-0.1.1.tar.gz 25.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for marginism 0.1.1
File Interpreter ABI Platform
marginism-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 54.8 kB

Release files / marginism-0.1.1.tar.gz

Download URL marginism-0.1.1.tar.gz
Size 25.2 kB
Tags Source
SHA-256 checksum
How to use checksums
00144b86089532d7fce3c64630af89bc44e20a6cfa24baac473c6217339c628e
BLAKE2b-256 checksum
How to use checksums
4a053a0934927223e52959e95b17538eb7f0c84430cb4d3a7836fc8be1985ce8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.0

Release files / marginism-0.1.1-py3-none-any.whl

Download URL marginism-0.1.1-py3-none-any.whl
Size 29.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6029524a63ecda4e719c65ce7be5a7a929e3b165d81e0399c68477c18dafca4a
BLAKE2b-256 checksum
How to use checksums
e8df371b99f4f24be08366bbbe8925dfbafdf7f12a330ba424002d242686f3f9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.0

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page