---
title: "3.1.3 Futures roll, margins, SPAN and leverage"
description: "When and how to roll a future and what it costs, initial and maintenance margin, SPAN-style scenario margin and implied leverage."
url: "https://pythonparatrading.com/en/python-trading-course/level-3/futures-roll-margins-span-leverage/"
lang: "en"
image: "https://pythonparatrading.com/og/en/python-trading-course/level-3/futures-roll-margins-span-leverage.png"
---

# 3.1.3 · Roll management, margins, SPAN and implied leverage

> Holding a future forces two things a stock does not: switching contracts every few months and always having cash for the margin. This lesson measures in the synthetic data when liquidity migrates and how much rolling costs, builds a scenario-based margin calculation like the clearing houses', shows what happens to margin in a crisis and calculates the leverage of a diversified portfolio, which is much higher than its margin suggests.

- Course: [Level 3: Derivatives: futures, spreads, forex and options](https://pythonparatrading.com/en/python-trading-course/level-3/)
- Module: 3.1 · Futures in depth
- Duration: 65 min
- Prerequisites: [3.1.1 · Main futures contracts](https://pythonparatrading.com/en/python-trading-course/level-3/main-futures-contracts/), [3.1.2 · Futures curve: basis, cost of carry, contango and roll yield](https://pythonparatrading.com/en/python-trading-course/level-3/futures-curve-basis-contango-roll-yield/), [1.2.3 · Futures: specifications, margin, roll and contango](https://pythonparatrading.com/en/python-trading-course/level-1/futures-contract-specs-margin-and-roll/)

## By the end of this lesson

- Choose the roll date of each market according to its reference (first notice or expiry) and the migration of open interest.
- Execute the roll as a calendar spread and measure what it costs compared with trading the two legs separately.
- Distinguish initial, maintenance and spread margin, and calculate the margin of a portfolio by scenarios (scanning risk, spread charge, inter-market credit).
- Explain why margins rise in crises and simulate a margin rule that follows volatility.
- Calculate the notional leverage and the margin of a diversified portfolio, and why neither of them measures its risk.

## When to roll

A future expires; a futures position does not have to. Keeping it forces you to **roll**: close the contract held and
open the next one before the first stops being useful. Lesson 1.4.6 dealt with the roll from the data side (how to
splice a continuous series). Here it is dealt with from the trading side: when, at what cost and with what risk. The
rules of the synthetic data set the roll date of each contract from a reference in its specifications:

```python
import numpy as np
import pandas as pd

curvas = pd.read_parquet("futuros3_curvas.parquet")
ctr = pd.read_csv("futuros3_contratos.csv",
                  parse_dates=["vencimiento", "primer_aviso",
                               "fecha_alta", "fecha_roll"])
esp = pd.read_csv("futuros3_especificaciones.csv",
                  index_col="mercado")
MERCADOS = list(esp.index[esp["mercado_base"].isna()])
reglas = esp.loc[MERCADOS, ["meses", "referencia_roll", "dias_roll"]]
reglas["rolls_ano"] = reglas["meses"].str.len()
reglas.loc[["RVA", "RVH", "TPC", "PEC", "GNA", "MTO", "GRM", "DQE"]]
```
```output
                meses referencia_roll  dias_roll  rolls_ano
mercado
RVA              HMUZ     vencimiento          8          4
RVH      FGHJKMNQUVXZ     vencimiento          2         12
TPC              HMUZ    primer_aviso          3          4
PEC      FGHJKMNQUVXZ     vencimiento          6         12
GNA      FGHJKMNQUVXZ     vencimiento          4         12
MTO            GJMQVZ    primer_aviso          3          6
GRM             HKNUZ    primer_aviso         10          5
DQE              HMUZ     vencimiento          5          4
```

Physically delivered contracts with notice (bonds, metals, agriculturals) roll a number of sessions before the **first
notice**: 3 in the 10-year note and gold, 10 in corn. The rest, before **expiry**: 8 sessions in `RVA`, 2 in the
Spanish index (which has monthly contracts), 6 in crude oil. The number of rolls a year depends on the months that are
held: 4 in the quarterly ones, 12 in energy, 5 in corn, 6 in gold.

```mermaid
flowchart TB
  A[Current contract] --> B{Physical with notice?}
  B -- yes --> C[Roll before notice]
  B -- no --> D{Liquidity migrated?}
  D -- yes --> E[Roll on migration]
  D -- no --> F[Wait]
  C --> G[Spread order]
  E --> G
```

A system's rule does not have to be the data's, but it has to meet two conditions: exit before the first notice when
there is one, and be in the contract that has the liquidity. The second one can be measured:

```python
sesiones = pd.DatetimeIndex(sorted(curvas["fecha"].unique()))
oi = curvas.pivot_table(index="fecha", columns="contrato",
                        values="interes_abierto")

def migracion(mercado, desfases=range(-12, 4)):
    """Share of open interest of the contract being left (against
    the next one), by sessions relative to its roll date."""
    cm = ctr[(ctr["mercado"] == mercado)
             & (ctr["fecha_roll"].between("2011-01-01",
                                          "2024-12-31"))]
    sig = ctr[ctr["mercado"] == mercado]["contrato"].to_numpy()
    siguiente = dict(zip(sig[:-1], sig[1:]))
    filas = []
    for _, c in cm.iterrows():
        p = sesiones.searchsorted(c["fecha_roll"])
        for d in desfases:
            f = sesiones[p + d]
            a = oi.at[f, c["contrato"]]
            b = oi.at[f, siguiente[c["contrato"]]]
            filas.append((d, a / (a + b)))
    return pd.DataFrame(filas, columns=["d", "cuota"]).groupby(
        "d")["cuota"].mean()

mig = pd.DataFrame({m: migracion(m)
                    for m in ["RVA", "TPC", "PEC", "GRM"]})
(100 * mig.loc[[-12, -8, -5, -3, -1, 0, 1, 3]]).round(1)
```
```output
      RVA   TPC   PEC   GRM
d
-12  92.6  92.6  64.5  68.0
-8   84.4  92.6  62.5  44.0
-5   41.2  89.9  33.3  14.2
-3   12.7  48.4   9.1   4.1
-1    6.0   3.0   2.1   2.0
 0    5.7   2.0   2.0   2.0
 1    3.5   1.2   1.2   1.2
 3    1.3   0.4   0.4   0.4
```

*Fig. — Open interest migration around the roll: share of the expiring contract against the next one, average of the 2011-2024 rolls.* Four lines with the open interest share of the expiring contract against the next, from 15 sessions before the roll date to 3 after. Corn (GRM), from 69%, crosses 50% between 9 and 8 sessions before the roll; crude (PEC), from 65%, between 7 and 6; the index (RVA), from 93%, between 6 and 5; the 10-year note (TPC, highlighted) stays at 93% until session −6, crosses 50% around −3 and reaches 3% by −1. On the roll date the expiring contract keeps 2% to 6% of open interest.

The table and the figure average all the rolls from 2011 to 2024. In corn, 12 sessions before the roll the expiring
contract still has 68.0% of the open interest, 5 sessions before only 14.2%, and the migration is over before the roll;
in crude oil, from 64.5% to 33.3% over the same sessions. In the 10-year note, the old contract keeps 92.6% until 8
sessions before and the switch is concentrated in three sessions (from 89.9% at −5 to 3.0% at −1): it is the pattern
of real bonds, which almost all roll on the same days before the first notice. On the roll date, the expiring contract
has between 2.0% and 5.7% of the open interest left. Rolling later means trading in a contract that is emptying.

<aside class="callout" data-kind="nota">

In real markets, the roll calendar of the large commodity indices and of the ETFs that replicate futures is public, and
their volume is concentrated in a few days. Rolling exactly on those days means rolling at the same time as them; some
systems bring their roll forward or push it back a little so as not to coincide. What does not change is the first
notice condition.

</aside>

## The roll as a calendar spread

Rolling is selling one contract and buying the next at the same time: a **calendar spread**. Exchanges quote them as
an instrument of their own, with their own book, and a spread order is executed as a single trade. The data has the
close of the spread book of six markets together with the legs:

```python
sp = pd.read_parquet("spreads3_cotizados.parquet")
sp["tick"] = esp["tick"].reindex(sp["mercado"]).to_numpy()
sp["libro"] = (sp["ask"] - sp["bid"]) / sp["tick"]
sp["patas"] = ((sp["ask_cerca"] - sp["bid_lejos"])
               - (sp["bid_cerca"] - sp["ask_lejos"])) / sp["tick"]
sp.groupby("mercado")[["libro", "patas"]].mean().round(2)
```
```output
         libro  patas
mercado
GNA       1.25   2.81
GRM       1.25   2.79
MTO       1.24   2.76
PEC       1.25   2.77
RVA       1.22   2.83
TPC       1.25   2.78
```

The spread book trades with an average bid-ask spread of 1.22 to 1.25 ticks; the spread built with the two legs
(selling at the bid of one and buying at the ask of the other), 2.76 to 2.83. It is the known answer of the data: the
spread book quotes at 1 tick 75% of the time and each leg at 1-3 ticks. Rolling by legs costs more than twice as much
and also exposes you to **legging risk**: if you sell the old one and the price moves before you buy the new one, the
roll comes out worse. Lesson 3.2.5 measures that risk with minute data. In annual cost:

```python
fx = pd.read_parquet("fx3_diario.parquet")
usd_qev = fx[fx["divisa"] == "QEV"].set_index("fecha")[
    "usd_por_unidad"]
DIA = "2025-11-26"

def precio_que_se_tiene(mercado, dia):
    cm = ctr[ctr["mercado"] == mercado].reset_index(drop=True)
    k = cm["contrato"].iloc[cm["fecha_roll"].searchsorted(
        pd.Timestamp(dia), side="right")]
    fila = curvas[(curvas["fecha"] == dia)
                  & (curvas["contrato"] == k)]
    return fila["liquidacion"].iloc[0]

filas = {}
for m in ["RVA", "TPC", "PEC", "GNA", "MTO", "GRM"]:
    e = esp.loc[m]
    nominal = precio_que_se_tiene(m, DIA) * e["multiplicador"]
    medio_libro = sp.loc[sp["mercado"] == m, "libro"].mean() / 2
    medio_patas = sp.loc[sp["mercado"] == m, "patas"].mean() / 2
    por_roll = lambda t: t * e["valor_tick"] + 2 * e["comision"]
    filas[m] = {"rolls": len(e["meses"]),
                "libro_pb_ano": 1e4 * len(e["meses"])
                * por_roll(medio_libro) / nominal,
                "patas_pb_ano": 1e4 * len(e["meses"])
                * por_roll(medio_patas) / nominal}
pd.DataFrame(filas).T.round(2)
```
```output
     rolls  libro_pb_ano  patas_pb_ano
RVA    4.0          1.21          2.23
TPC    4.0          4.51          8.74
PEC   12.0         16.85         28.74
GNA   12.0         17.79         30.71
MTO    6.0          2.96          5.06
GRM    5.0         36.70         65.32
```

Per roll you pay half a bid-ask spread and two commissions (one per leg). Per year, with each market's rolls and the
notional of November 26, 2025: 1.21 basis points in `RVA` with the book (2.23 by legs), 16.85 in crude oil (28.74),
17.79 in gas (30.71) and 36.70 in corn (65.32). In indices it is irrelevant; in a market with small contracts, an
expensive tick and twelve rolls a year, the roll is a fixed cost of holding the position that a backtest without roll
costs does not see (lesson 2.4.7).

## Rolling earlier or later

With the roll you also choose where on the curve to be. Rolling earlier means holding a farther contract:

```python
def serie_con_roll(mercado, antes):
    """Returns of the contract held if you roll `antes` sessions
    before the first notice (or the expiry)."""
    c = curvas[curvas["mercado"] == mercado]
    P = c.pivot(index="fecha", columns="contrato",
                values="liquidacion")
    cm = ctr[ctr["mercado"] == mercado].reset_index(drop=True)
    ref = cm["primer_aviso"].fillna(cm["vencimiento"])
    p = P.index.searchsorted(ref.to_numpy()) - antes
    roll = P.index[np.clip(p, 0, len(P) - 1)].to_numpy()
    pos = np.searchsorted(roll, P.index.to_numpy(), side="right")
    pos = np.minimum(pos, len(cm) - 1)
    i = P.columns.get_indexer(cm["contrato"].to_numpy()[pos])
    f, Pv = np.arange(len(P)), P.to_numpy()
    ayer = np.r_[i[0], i[:-1]]
    r = np.log(Pv[f[1:], ayer[1:]] / Pv[f[1:] - 1, ayer[1:]])
    return pd.Series(r, index=P.index[1:]).loc["2011":]

vol = {m: {a: serie_con_roll(m, a).std() * np.sqrt(252)
           for a in (1, 5, 20, 40)} for m in ["RVA", "PEC", "GNA",
                                               "GRM"]}
(100 * pd.DataFrame(vol)).round(1)
```
```output
     RVA   PEC   GNA   GRM
1   19.0  36.1  43.4  25.4
5   19.0  35.4  41.5  25.0
20  19.0  32.7  35.2  22.8
40  19.0  29.7  29.5  20.5
```

In the index, volatility is the same (19.0%) whenever you roll: all expiries move the same. In markets with a
Samuelson effect (lesson 3.1.2), rolling 40 sessions earlier lowers the volatility of the contract held: from 43.4% to
29.5% in gas, from 36.1% to 29.7% in crude oil, from 25.4% to 20.5% in corn. It is not a free improvement: the farther
contract responds less to what moves the first one (a different bet), its carry is different and its liquidity is
lower (in energy, the next contract has volume; in other markets, it does not). What the table does give is a warning:
the volatility of a series depends on its roll rule, and a system that sizes by volatility has to estimate it with the
same rule it trades with.

## Initial and maintenance margin

Lesson 1.2.3 simulated a margin account with margin calls. In the data, each market has three margins:

```python
m = esp.loc[MERCADOS, ["margen_inicial", "margen_mantenimiento",
                       "margen_spread_calendario"]]
m["inicial_sobre_mant"] = m["margen_inicial"] / m[
    "margen_mantenimiento"]
m["spread_sobre_inicial_pct"] = 100 * m[
    "margen_spread_calendario"] / m["margen_inicial"]
m.loc[["RVA", "TPC", "PEC", "GNA", "ELB", "MTO", "GRM"],
      ["margen_inicial", "inicial_sobre_mant",
       "margen_spread_calendario", "spread_sobre_inicial_pct"]
      ].round(2)
```
```output
         margen_inicial  inicial_sobre_mant  margen_spread_calendario  spread_sobre_inicial_pct
mercado
RVA             20200.0                1.10                     610.0                      3.02
TPC              2700.0                1.08                     140.0                      5.19
PEC              5600.0                1.10                     670.0                     11.96
GNA              8500.0                1.10                    3300.0                     38.82
ELB              7300.0                1.11                    3200.0                     43.84
MTO              9600.0                1.10                     290.0                      3.02
GRM               840.0                1.11                     150.0                     17.86
```

- **Initial**: what is deposited when opening. In the data it is 1.1 times the maintenance margin (rounded to the
  hundred), a ratio that exists at some clearing houses for certain types of account; other clearing houses ask the
  same for initial as for maintenance and it is the broker that adds its own cushion.
- **Maintenance**: the minimum below which the margin call arrives.
- **Calendar spread**: the margin of a position long one month and short another of the same market. It is a fraction
  of the initial margin: 3% in `RVA` and in gold, where the two months move almost the same; 38.8% and 43.8% in gas and
  electricity, where the seasonal shape makes two different months move differently.

## SPAN: margin as the worst scenario

Clearing houses do not add up margins of individual contracts: they calculate the margin of the whole portfolio with
scenarios. The classic method is CME's SPAN, and other clearing houses use variants or their own methods. BME Clearing
describes its method for MEFF's financial derivatives (MEFFCOM2) as “similar to an SPAN model”: it evaluates the worst
possible loss of the portfolio across several theoretical scenarios and only offsets between instruments with an
average correlation of 70% or more. Eurex Clearing uses Prisma, which calculates margin at portfolio level by grouping
related products. The structure of SPAN is that of this diagram:

```mermaid
flowchart TB
  E[Scenarios] --> R[Scanning risk]
  R --> S[+ spread charge]
  S --> C[− credit]
  C --> M[Portfolio margin]
  O[Short option minimum] --> M
```

**Scanning risk** is the worst loss of the portfolio over a grid of price moves (and, for options, of volatility), with
a range that the clearing house sets per product. Since it moves all the months of the same product at once, a
calendar spread appears to have no risk: the **spread charge** corrects that. The **inter-product credit** recognizes
that a position long one product and short another correlated one risks less than the two separately. A simplified
calculation for futures, with the initial margin in the specifications as the range and a grid of moves of 0, ±1/3,
±2/3 and ±1 ranges (the parameters are this lesson's, not a real clearing house's):

```python
FRACCIONES = np.array([0, 1 / 3, -1 / 3, 2 / 3, -2 / 3, 1, -1])

def margen_escenarios(cartera, credito=0.0):
    """cartera: {contract: number of contracts}. Each market moves
    by its range (the initial margin of one contract, in USD); all
    the months of a market at once (correlation 1)."""
    por_mercado = {}
    for k, n in cartera.items():
        m = k[:3]
        por_mercado.setdefault(m, []).append(n)
    riesgo, cargo = {}, {}
    for m, ns in por_mercado.items():
        rango = esp.loc[m, "margen_inicial"]
        pyg = np.outer(FRACCIONES, ns).sum(axis=1) * rango
        riesgo[m] = max(0.0, -pyg.min())          # worst scenario
        largos = sum(n for n in ns if n > 0)
        cortos = -sum(n for n in ns if n < 0)
        cargo[m] = min(largos, cortos) * esp.loc[
            m, "margen_spread_calendario"]        # months not identical
    total = sum(riesgo.values()) + sum(cargo.values())
    # inter-market credit: fraction of the smaller risk of each pair
    if credito and len(riesgo) == 2:
        total -= credito * min(riesgo.values())
    return {"escenarios": float(sum(riesgo.values())),
            "cargo_spread": float(sum(cargo.values())),
            "total": float(total)}

for nombre, c in {"long 2 PECF26": {"PECF26": 2},
                  "long F26, short G26": {"PECF26": 1,
                                          "PECG26": -1},
                  "long 2 F26, short 1 G26": {"PECF26": 2,
                                              "PECG26": -1}}.items():
    print(f"{nombre:26s}", margen_escenarios(c))
```
```output
long 2 PECF26              {'escenarios': 11200.0, 'cargo_spread': 0.0, 'total': 11200.0}
long F26, short G26        {'escenarios': 0.0, 'cargo_spread': 670.0, 'total': 670.0}
long 2 F26, short 1 G26    {'escenarios': 5600.0, 'cargo_spread': 670.0, 'total': 6270.0}
```

Two long crude oil contracts ask 11,200 USD, two ranges. Long January and short February, the scan sees no risk (the
two move the same in every scenario) and the margin is the spread charge, 670 USD: 6% of what an outright position of
two contracts would ask. Two longs and one short come down to one net long (5,600) plus one spread (670). That is why
calendar spreads are traded with much less margin (lesson 3.2.1), and also why their leverage can be misleading: the
spread charge covers normal moves in the slope, not an extreme supply squeeze in the near month.

```python
cartera = {"RVAH26": 1, "RVBH26": -1}
sin = margen_escenarios(cartera)
con = margen_escenarios(cartera, credito=0.5)
print("no credit:", sin["total"], " with 50%:", con["total"])
```
```output
no credit: 44900.0  with 50%: 34800.0
```

A long in `RVA` and a short in `RVB` (two indices with a correlation of 0.91 in the data) ask 44,900 USD if they are
added as two independent risks. With a credit of 50% of the smaller one (an example value: in reality the clearing
house sets it for each pair of products and reviews it), 34,800. The credit exists because the clearing house
recognizes that the two legs offset each other in almost every scenario; the risk that they stop doing so does not go
away.

## Margins in a crisis

The scanning range is not fixed: clearing houses review it with recent volatility, and in a crisis they raise it. The
data has constant margins (calibrated with the last year), so to see the effect you have to simulate a rule. The data
README says that the margins cover between 3 and 10 daily standard deviations of the notional, 5.3 in `RVA`. A rule
that keeps those 5.3 with the volatility of the last few weeks:

```python
def serie(mercado):
    c = curvas[curvas["mercado"] == mercado]
    P = c.pivot(index="fecha", columns="contrato",
                values="liquidacion")
    cm = ctr[ctr["mercado"] == mercado].reset_index(drop=True)
    pos = np.searchsorted(cm["fecha_roll"].to_numpy(),
                          P.index.to_numpy(), side="right")
    i = P.columns.get_indexer(cm["contrato"].to_numpy()[pos])
    f, Pv = np.arange(len(P)), P.to_numpy()
    ayer = np.r_[i[0], i[:-1]]
    r = np.r_[np.nan, np.log(Pv[f[1:], ayer[1:]]
                             / Pv[f[1:] - 1, ayer[1:]])]
    return pd.DataFrame({"precio": Pv[f, i], "ret": r},
                        index=P.index)

rva = serie("RVA")
nominal = rva["precio"] * esp.loc["RVA", "multiplicador"]
K = 5.3                      # daily deviations (data README)
dinamico = K * rva["ret"].ewm(span=20).std() * nominal
t = dinamico.loc["2019-12-01":"2020-12-31"]
print(t.resample("ME").agg(["min", "max"]).round(-2).iloc[:7])
print(f"maximum / January: {t.max() / t.loc['2020-01'].mean():.1f}")
```
```output
                min      max
fecha
2019-12-31   4800.0   7200.0
2020-01-31   4100.0   5900.0
2020-02-29   5200.0  11900.0
2020-03-31  10200.0  32600.0
2020-04-30  16300.0  33400.0
2020-05-31  14700.0  23900.0
2020-06-30  13600.0  17300.0
maximum / January: 6.7
```

*Fig. — A margin that tracks volatility: 5.3 daily standard deviations (20-session exponential average) of the notional of one RVA contract, December 2019 to December 2020.* A line with the per-contract margin of a rule that tracks volatility, December 2019 to December 2020. In January 2020 it is around USD 5,000 (average 4,967, dashed line); it rises in March to a peak of 33,406 on 1 April (highlighted), 6.7 times the January average, and falls slowly: around 15,000 in summer and 8,000-10,000 in December.

In January 2020 the rule asks between 4,100 and 5,900 USD per contract; in March, up to 32,600, and the maximum, on
April 1, is 6.7 times the January average. Then it comes down slowly: in June it is still between 13,600 and 17,300,
because volatility takes time to be forgotten. The margins of real clearing houses do not follow this exact rule, but
they have the same underlying flaw: they are **procyclical**. They rise when there are losses, and a system that in
calm times uses almost all its cash as margin receives at the same time the calls for the losses and the margin
increases. If it cannot post more, it cuts positions at the worst moment.

<aside class="callout" data-kind="riesgo">

A practical rule for any futures system: the margin used in calm times has to be a small fraction of capital, so that a
margin several times larger and a few weeks of losses fit in the account. The portfolio in the next section uses 14.7%
of capital; with the margin multiplied by 6.7, as in the 2020 simulation, it would need almost all of it.

</aside>

## Implied leverage of a diversified portfolio

A diversified system (lesson 3.1.4) gives the same risk to each market. With 5 million USD, a 20% volatility target
and the diversification multiplier of 2.5 calculated in that lesson, the positions on November 26, 2025, in notional
and in margin:

```python
CAPITAL, RIESGO = 5_000_000, 0.20
filas = {}
for m in MERCADOS:
    s = serie(m)
    cambio = usd_qev[DIA] if esp.loc[m, "divisa"] == "QEV" else 1
    nominal = s.loc[DIA, "precio"] * esp.loc[m, "multiplicador"] \
        * cambio
    vol = s["ret"].loc[:DIA].tail(252).std() * np.sqrt(252)
    # IDM of 2.5 (lesson 3.1.4) and the same weight for each market
    n = np.round(2.5 / len(MERCADOS) * CAPITAL * RIESGO
                 / (nominal * vol))
    filas[m] = {"sector": esp.loc[m, "sector"], "contratos": n,
                "nominal": n * nominal,
                "margen": n * esp.loc[m, "margen_inicial"] * cambio}
cart = pd.DataFrame(filas).T.infer_objects()
por_sector = cart.groupby("sector")[["nominal", "margen"]].sum()
print((100 * por_sector / CAPITAL).round(1))
print("total:", (100 * por_sector.sum() / CAPITAL).round(1).to_dict())
```
```output
           nominal  margen
sector
agricolas     41.6     2.4
divisas       27.3     0.5
energia       28.4     2.6
indices       58.0     3.3
metales       25.9     1.4
tipos        244.9     4.4
total: {'nominal': 426.0, 'margen': 14.7}
```

The notional of the portfolio is 426% of capital: leverage of 4.3 times. More than half, 244.9% of capital, is bonds,
because a bond moves so little that it takes a lot of notional for it to contribute the same risk as an index. The
margin is 14.7% of capital. The header figure shows both numbers by sector.

Neither of them measures the risk of the portfolio. Notional leverage mixes 245% in bonds that move 6% a year with 28%
in energy that moves 35%. The margin is what the clearing house asks to cover one or two bad days, and it changes with
its rule. The risk is the one set by the size of each position (a 20% annual target) plus what volatility does not
capture: that all the bonds fall at once, as in the 2022 carry portfolio of lesson 2.3.4, or that correlations change
in a crisis. That is why a futures system is managed in risk, with stress scenarios, and margin is monitored as a
liquidity constraint.

## Exercises

1. Use `margen_escenarios` to calculate the margin of a calendar butterfly in crude oil (long 1 `PECF26`, short 2
   `PECG26`, long 1 `PECH26`). What spread charge does the function apply and why is it probably too high?

**Solution.**

```python
print(margen_escenarios({"PECF26": 1, "PECG26": -2, "PECH26": 1}))
```
```output
{'escenarios': 0.0, 'cargo_spread': 1340.0, 'total': 1340.0}
```

The net position is zero, so the scan sees no risk. The function counts two spreads (two longs and two shorts) and
charges twice, 1,340 USD. But a butterfly is the difference of two spreads with one leg in common, and its risk is
lower than that of two independent spreads: real clearing houses have charge tables by curve segment and can treat
these combinations differently. Lesson 3.2.1 builds calendar butterflies and condors.

2. Repeat the 2020 dynamic margin rule with a 60-session exponential average instead of 20. Does it rise less? Does it
   come down sooner or later?

**Solution.**

```python
lento = K * rva["ret"].ewm(span=60).std() * nominal
t60 = lento.loc["2019-12-01":"2020-12-31"]
print(t60.resample("ME").agg(["min", "max"]).round(-2).iloc[:7])
print(f"maximum / January: {t60.max() / t60.loc['2020-01'].mean():.1f}")
```
```output
                min      max
fecha
2019-12-31   7100.0   8200.0
2020-01-31   6200.0   7100.0
2020-02-29   6200.0  10000.0
2020-03-31   9800.0  35600.0
2020-04-30  34700.0  39200.0
2020-05-31  32600.0  38200.0
2020-06-30  26900.0  32700.0
maximum / January: 6.0
```

With 60 sessions the rule starts from a higher level in January (from 6,200 to 7,100 USD, because its window still
remembers the volatility of late 2019) and reacts later, but it does not rise less: its April maximum, 39,200, exceeds
that of the 20-session rule, because it accumulates more bad days in the window, and in June it is still between
26,900 and 32,700, when the other one has already come down by half. Relative to January, the maximum is 6.0 times
instead of 6.7. It is the dilemma of any risk measure: fast and jumpy or slow and with memory; the slow one does not
avoid the rise, it delays and prolongs it, and it ties up the account's cash for longer.

3. With the `cart` table, what would happen to the total margin if the clearing house doubled the margin of the five
   bonds? And if it doubled it for the five indices? What does it tell you about where the portfolio's margin exposure
   is?

**Solution.**

The margin of the bonds is 4.4% of capital and that of the indices, 3.3%: doubling that of the bonds would take the
total margin from 14.7% to 19.1%, and that of the indices, to 18.0%. Bonds have the largest notional and the largest
margin in the portfolio, even though each contract asks little, because there are many contracts. A change in the
margin of a sector with many positions weighs more than one in a sector with expensive but few contracts. It is another
way of seeing that the notional and the margin are concentrated in bonds even though the risk is spread out.

## Self-assessment

1. In the data, the open interest of corn (GRM) crosses 50% towards the next contract between 9 and 8 sessions before the roll date, and that of the 10-year note (TPC), around session −3. What does it imply for a system's roll date?

   - A. That each market has its window: rolling later than when liquidity migrates means trading the last stretch in a contract that is emptying, with wider spreads and, in physically delivered ones, close to the first notice
   - B. That it does not matter when you roll
   - C. That you always have to roll on expiry day
   - D. That corn has no roll

   *Answer A: That each market has its window: rolling later than when liquidity migrates means trading the last stretch in a contract that is emptying, with wider spreads and, in physically delivered ones, close to the first notice.* The roll date is set per market: before the contract being left loses its liquidity and, in physically delivered ones, before the first notice. On the roll date in the data, the expiring contract has between 2% and 6% of the open interest left.

2. In the calendar spreads of the data, the spread book trades with an average bid-ask spread of 1.25 ticks and the synthetic spread built from the two legs, 2.78. How should you roll?

   - A. Selling the old contract and buying the new one at market separately
   - B. With a calendar spread order: a single bid-ask spread, narrower, and without the risk of the price moving between the execution of one leg and the other
   - C. Letting the contract expire
   - D. It does not matter: the cost is the same

   *Answer B: With a calendar spread order: a single bid-ask spread, narrower, and without the risk of the price moving between the execution of one leg and the other.* Rolling is selling one contract and buying the next at the same time, which is exactly a calendar spread. Traded as a spread, you pay half the spread book's bid-ask spread; by legs, half the bid-ask spread of each, and you also run the legging risk (lesson 3.2.5).

3. A position long PECF26 and short PECG26 has zero scanning risk in the lesson's calculation. Why is the margin not zero?

   - A. Because the clearing house charges a fixed fee
   - B. Because shorts always pay more margin
   - C. Because it is a calculation error
   - D. Because the scan moves all the months of a market at once, as if the correlation were 1; the calendar spread charge (670 USD) covers the risk that the two months move differently

   *Answer D: Because the scan moves all the months of a market at once, as if the correlation were 1; the calendar spread charge (670 USD) covers the risk that the two months move differently.* Two contracts of the same market do not move exactly the same (the slope changes). The spread charge is small compared with the margin of an outright contract (5,600 USD in PEC) because the spread's risk is small: lesson 3.2.1 takes advantage of it.

4. A margin rule that covers 5.3 daily standard deviations of the notional goes from an average of 4,967 USD per RVA contract in January 2020 to 33,406 on April 1. What consequence does it have for a system?

   - A. None: margin is not a loss
   - B. That more contracts have to be traded
   - C. That it needs reserve cash: margin rises exactly when there are losses, and whoever cannot post it has to cut positions at the worst moment
   - D. That margin falls in crises

   *Answer C: That it needs reserve cash: margin rises exactly when there are losses, and whoever cannot post it has to cut positions at the worst moment.* Scenario-based margins depend on recent volatility: they are procyclical. A system that uses almost all its cash as margin in calm times receives margin calls and margin increases at the same time.

5. The lesson's portfolio has a notional of 426% of capital and a margin of 14.7%. Which number best describes its risk?

   - A. The notional: the portfolio is leveraged 4.3 times
   - B. The margin: it risks 14.7% of capital
   - C. Neither: its risk is the volatility target (20% a year), which depends on the volatility and correlation of the positions, not on their notional or their margin
   - D. The sum of the two

   *Answer C: Neither: its risk is the volatility target (20% a year), which depends on the volatility and correlation of the positions, not on their notional or their margin.* 57% of the notional is bonds (244.9% of capital), which move little. The margin depends on what the clearing house asks. Risk is measured in volatility (and in stress scenarios), and it is what sets the size of each position.

## Key points

- The roll date is set per market: before the first notice in physically delivered ones and when liquidity migrates in the rest. In the data, open interest crosses 50% between 9 and 3 sessions before the roll, depending on the market.
- Rolling is a calendar spread. With a spread order you pay half the bid-ask spread of a 1.25-tick book; by legs, half of each (2.78 ticks in total) plus legging risk. In corn, rolling costs 36.7 basis points a year with the book and 65.3 by legs.
- Rolling earlier reduces the volatility of the contract held in markets with a Samuelson effect (gas: from 43.4% to 29.5% when rolling 40 sessions earlier), at the price of moving away from the most liquid contract.
- Scenario margin takes the worst loss over a grid of price moves, adds a charge for spreads within the same market and subtracts a credit between correlated markets. A crude oil calendar spread asks 670 USD against 5,600 for an outright contract.
- Margins are procyclical: a rule that covers 5.3 daily deviations multiplies the RVA margin by 6.7 between January and April 2020.
- A portfolio with the same risk in 23 markets and a 20% volatility target has a notional of 426% of capital (244.9% in bonds) and a margin of 14.7%: neither leverage nor margin measures its risk.

## Resources

### Research

- [Introduction to Volatility - Liquidity](https://pythonparatrading.com/en/introduction-to-volatility-liquidity/) · Research-0001 · 5 min

### Documentation

- [BME Clearing: risk management (MEFFCOM2, a scenario method similar to SPAN)](https://www.bolsasymercados.es/en/securities-services/bme-clearing/services/risk-management.html) · bolsasymercados.es
- [Eurex Clearing: Prisma (portfolio-based margining)](https://www.eurex.com/ec-en/services/margining/eurex-clearing-prisma) · eurex.com
- [Eurex: Euro-Bund Futures (delivery day and last trading day)](https://www.eurex.com/ex-en/markets/int/long-term-interest-rates/fix/government-bonds/Euro-Bund-Futures-137298) · eurex.com

### Books

- [Robert Carver: Leveraged Trading (Harriman House, 2019)](https://www.harriman-house.com/authors/robert-carver/leveraged-trading/9780857197214) · harriman-house.com

### Data

- [Level 3 data: quoted calendar spreads (Parquet)](https://pythonparatrading.com/curso/datos/nivel-3/spreads3_cotizados.parquet) · Download · spreads3_cotizados.parquet
- [Level 3 data: contract calendar (CSV)](https://pythonparatrading.com/curso/datos/nivel-3/futuros3_contratos.csv) · Download · futuros3_contratos.csv

Previous lesson: [3.1.2 · Futures curve: basis, cost of carry, contango and roll yield](https://pythonparatrading.com/en/python-trading-course/level-3/futures-curve-basis-contango-roll-yield/)

Next lesson: [3.1.4 · Diversified futures systems: Carver's approach](https://pythonparatrading.com/en/python-trading-course/level-3/diversified-futures-systems-carver/)
