---
title: "1.2.3 Futures: specifications, margin, roll and contango"
description: "What a futures contract specifies, how margin and daily settlement work, why it converges to spot and how liquidity migrates in the roll."
url: "https://pythonparatrading.com/en/python-trading-course/level-1/futures-contract-specs-margin-and-roll/"
lang: "en"
image: "https://pythonparatrading.com/og/en/python-trading-course/level-1/futures-contract-specs-margin-and-roll.png"
---

# 1.2.3 · Futures: specifications, margin, roll and contango

> A future is a standardized commitment to buy or sell an asset on a date at a price set today. Nothing is paid on entry: collateral is deposited and the differences are collected or paid every day. This lesson takes apart a fictitious index contract, FIX, with seven years of settlement prices for all its expiries.

- Course: [Level 1: Financial data, markets and analysis](https://pythonparatrading.com/en/python-trading-course/level-1/)
- Module: 1.2 · Asset classes
- Duration: 65 min
- Prerequisites: [1.1.5 · Costs, settlement, leverage and margin](https://pythonparatrading.com/en/python-trading-course/level-1/trading-costs-settlement-leverage-and-margin/), [1.2.1 · Stocks: splits, dividends and corporate actions](https://pythonparatrading.com/en/python-trading-course/level-1/stocks-splits-dividends-corporate-actions/)

## By the end of this lesson

- Read the specifications of a futures contract (multiplier, tick, tick value, expiries, settlement) and calculate its notional.
- Simulate the daily settlement of a position and its margin account, with initial margin, maintenance margin and margin calls.
- Explain the relationship between the future and the spot (cost of carry) and measure the basis and its convergence at expiry.
- Distinguish contango and backwardation and measure them in the term structure of the data.
- Recognize the migration of volume and open interest in the roll and know why it matters for building a continuous series.

## A standardized contract

A **future** is a contract by which two parties commit to buy and sell an asset (the **underlying**) on a future date
(the **expiry**) at a price set today. Unlike a private forward contract (*forward*, lesson 1.2.4), a future is traded
on an exchange, with identical terms for everyone, and a central counterparty stands between buyer and seller (lesson
1.1.1). The only thing that is negotiated is the price; everything else is set by the **contract specifications**.

The course data includes a fictitious future, **FIX**, on a price index of stocks (without dividends). Its
specifications:

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

esp = pd.read_csv("fix_especificaciones.csv").iloc[0]
print(esp.drop("regla_vencimiento").to_string())
print(esp["regla_vencimiento"])
```
```output
multiplicador                50
tick                       0.25
valor_tick                 12.5
margen_inicial            16500
margen_mantenimiento      15000
meses                   H,M,U,Z
tercer viernes del mes del contrato (si no hay sesión, la anterior); liquidación final en efectivo al cierre del índice ese día; último día de negociación = vencimiento
```

Each field answers a question:

| Field | Question | FIX |
|---|---|---|
| Underlying | On what? | FIX price index |
| Multiplier | How much is one point worth? | 50 USD |
| Tick | What is the minimum price change? | 0.25 points |
| Tick value | How much is gained or lost per tick and contract? | 0.25 × 50 = 12.50 USD |
| Months | Which expiries are there? | March, June, September, December (H, M, U, Z) |
| Expiry | Which day? | Third Friday of the month (or the previous session) |
| Final settlement | How is it closed out? | In cash, at the index close that day |
| Margins | What collateral is deposited? | 16,500 USD initial, 15,000 maintenance |

The month codes (H March, M June, U September, Z December) are the convention of US exchanges; the `FIXH24` contract
is the March 2024 one. With a price and the specifications, everything else can be calculated:

```python
indice = pd.read_csv("fix_indice_diario.csv", parse_dates=["fecha"],
                     index_col="fecha")["indice"]
S = indice["2025-06-02"]
nominal = S * esp["multiplicador"]
print(f"Index: {S:.2f}  notional of one contract: {nominal:,.0f} USD")
print(f"Initial margin: {esp['margen_inicial']:,} USD"
      f" = {esp['margen_inicial'] / nominal:.1%} of notional")
print(f"Leverage: {nominal / esp['margen_inicial']:.1f} to 1")
print(f"1% of the index: {0.01 * nominal:,.0f} USD per contract")
```
```output
Index: 6359.10  notional of one contract: 317,955 USD
Initial margin: 16,500 USD = 5.2% of notional
Leverage: 19.3 to 1
1% of the index: 3,180 USD per contract
```

One contract controls 317,955 USD of index with 16,500 of collateral: leverage of 19.3 to 1. A 1% move in the index
is 3,180 USD, almost a fifth of the margin. To size a futures position you always have to think in notional, never in
margin (lesson 0.1.2).

Real contracts follow the same scheme. Some figures from their official specifications:

| Contract | Multiplier | Tick | Expiry and final settlement |
|---|---|---|---|
| E-mini S&P 500 (CME) | 50 USD × index | 0.25 points = 12.50 USD | Cash; special opening quotation of the index on the third Friday of the month |
| IBEX 35 future (MEFF) | 10 EUR × index | Set by circular | Third Friday; average of the index from 16:15 to 16:45, one value per minute |
| Mini IBEX 35 future (MEFF) | 1 EUR × index | 5 points = 5 EUR | Third Friday; same as the IBEX 35 |

FIX mimics the E-mini S&P 500 in multiplier and tick. The difference is in the final settlement: in the E-mini it is
not the index close but a special quotation calculated with the opening prices of its stocks on expiry day (rule
35803.A of chapter 358), and trading in the expiring contract ends when the NYSE session starts that day. At MEFF, the
daily settlement price of the first expiry is the volume-weighted average of the order book trades between 17:29 and
17:30. Details like these matter when comparing a future with its index on the expiry date.

## Many live contracts at once

Every day several expiries of the same future trade. `fix_contratos.parquet` has one row per session and contract,
with the daily settlement price (the one the clearing house sets at the close to calculate profits and losses), the
volume and the open interest (live contracts, not closed out):

```python
fut = pd.read_parquet("fix_contratos.parquet")
fut["dias"] = (fut["vencimiento"] - fut["fecha"]).dt.days
dia = fut[fut["fecha"] == "2025-06-02"]
dia[["contrato", "vencimiento", "dias", "liquidacion", "volumen",
     "interes_abierto"]]
```
```output
     contrato vencimiento  dias  liquidacion  volumen  interes_abierto
4867   FIXM25  2025-06-20    18      6367.75   315854           786283
4868   FIXU25  2025-09-19   109      6419.00     4406            24548
4869   FIXZ25  2025-12-19   200      6462.50      729             3201
```

On June 2, 2025 there are three live expiries. The June one, 18 days out, concentrates almost everything: 786,283
contracts of open interest versus 24,548 for the September one. It is the **front month**. The others exist, but
hardly anyone trades them until their turn approaches.

The header figure is the “ladder” of 2024 and 2025: each contract trades for about nine months, but it is only the
front month during the last three. The thick line marks when each one has the largest open interest. They all expire
on a Friday:

```python
venc = fut.groupby("contrato")["vencimiento"].first()
venc = venc[venc.dt.year == 2025]
pd.DataFrame({"vencimiento": venc.dt.date,
              "dia": venc.dt.day_name()})
```
```output
         vencimiento     dia
contrato
FIXH25    2025-03-21  Friday
FIXM25    2025-06-20  Friday
FIXU25    2025-09-19  Friday
FIXZ25    2025-12-19  Friday
```

## Margin and daily settlement

Buying a future does not cost its notional. Buyer and seller deposit collateral, the **initial margin**, and from then
on the clearing house settles every day the difference between today's settlement price and yesterday's (*mark to
market*): the winning side collects and the losing side pays, in cash, before the next session. The example in the
MEFF specifications sums it up: buying 30 IBEX 35 futures at 10,000 with a settlement of 10,020 at the end of the
session gives (10,020 − 10,000) × 30 × 10 = +6,000 euros that day.

```mermaid
flowchart LR
  C[Buyer] --> MC[Member]
  V[Seller] --> MV[Member]
  MC -- daily settlement --> K[Clearing house]
  MV -- daily settlement --> K
```

If the losses leave the account balance below the **maintenance margin**, the broker issues a **margin call**: cash
has to be deposited until the account is back at the initial margin. If it is not deposited, the broker closes the
position.

```mermaid
stateDiagram-v2
  [*] --> Open
  Open --> Call: balance below minimum
  Call --> Open: deposits cash
  Call --> Closed: does not deposit
  Open --> Closed: sold or expires
  Closed --> [*]
```

With the FIX settlement prices, the margin account of a long in the March 2025 contract can be simulated, opened on
December 16, 2024 and held until expiry:

```python
def cuenta_margen(precios, contratos=1, lado=1):
    """Margin account balance with daily settlement.

    lado = 1 for a long, -1 for a short. If the balance falls below the
    maintenance margin, whatever is needed to return to the initial
    margin is deposited.
    """
    saldo, filas = float(esp["margen_inicial"]) * contratos, []
    anterior = precios.iloc[0]
    for fecha, precio in precios.items():
        puntos = lado * (precio - anterior)
        pyg = puntos * esp["multiplicador"] * contratos
        saldo += pyg
        aporte = 0.0
        if saldo < esp["margen_mantenimiento"] * contratos:
            aporte = esp["margen_inicial"] * contratos - saldo
            saldo += aporte
        filas.append((fecha, precio, pyg, aporte, saldo))
        anterior = precio
    cols = ["liquidacion", "pyg", "aporte", "saldo"]
    tabla = pd.DataFrame(filas, columns=["fecha"] + cols)
    return tabla.set_index("fecha")

h25 = fut[fut["contrato"] == "FIXH25"].set_index("fecha")["liquidacion"]
cm = cuenta_margen(h25.loc["2024-12-16":])
cm.loc["2025-02-26":"2025-03-07"]
```
```output
            liquidacion     pyg  aporte    saldo
fecha
2025-02-26      5836.25 -1150.0  2500.0  16500.0
2025-02-27      5757.50 -3937.5  3937.5  16500.0
2025-02-28      5753.75  -187.5     0.0  16312.5
2025-03-03      5601.25 -7625.0  7812.5  16500.0
2025-03-04      5618.25   850.0     0.0  17350.0
2025-03-05      5503.50 -5737.5  4887.5  16500.0
2025-03-06      5334.50 -8450.0  8450.0  16500.0
2025-03-07      5234.75 -4987.5  4987.5  16500.0
```

At the end of February 2025 the index starts to fall sharply. Each day of large losses leaves the balance below 15,000
USD and forces a deposit to get back to 16,500: 2,500 USD on February 26, 3,937.50 on the 27th, 7,812.50 on March 3
and, from March 5 to 7, 4,887.50, 8,450 and 4,987.50. Over the six days in the table with a deposit, the account asks
for 32,575 USD: almost twice the entire initial margin.

```python
llamadas = cm[cm["aporte"] > 0]
print("Margin calls:", len(llamadas))
print(f"Cash deposited: {llamadas['aporte'].sum():,.2f} USD")
print(f"Position P&L: {cm['pyg'].sum():,.2f} USD")
print(f"Final account balance: {cm['saldo'].iloc[-1]:,.2f} USD")
```
```output
Margin calls: 12
Cash deposited: 64,112.50 USD
Position P&L: -65,332.50 USD
Final account balance: 15,280.00 USD
```

*Fig. — A long FIXH25 position from 16 December 2024 to expiry: cumulative P&L and cash paid in on margin calls.* Two lines in thousands of USD. The cumulative P&L of one long contract hovers near zero until February and drops sharply from late February to −65.3k at the 21 March 2025 expiry. As a step line, highlighted, the cash paid in on the 12 margin calls, rising almost as a mirror image to 64.1k.

The position loses 65,332.50 USD: four times the initial margin. The investor has had to deposit 64,112.50 USD in 12
calls, and at expiry has 15,280 left in the account. The numbers add up: 16,500 + 64,112.50 − 65,332.50 = 15,280. The
initial margin is not the maximum loss: it is only what the clearing house asks for to cover one or two bad days.

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

Real margins are set by the clearing house and they change: in volatile episodes they go up, precisely when there are
more losses. A system with futures needs cash in reserve for margin calls; without it, the broker closes the position
at the worst moment, even if the idea was right. In FIXH25, whoever could not deposit on March 3 would have closed
with losses near the low.

</aside>

## Basis, cost of carry and convergence

Why does a future trade at a price different from spot? Because buying the future and buying the index are not the
same. Whoever buys the index pays its full value today (and stops earning interest on that money) and receives the
dividends; whoever buys the future pays nothing today and does not receive dividends. For there to be no arbitrage,
the future has to compensate for that difference, the **cost of carry**:

$$
F_t = S_t \, e^{(r - q)\,\tau}
$$

where $S_t$ is the index, $r$ the interest rate, $q$ the dividend yield of the index and $\tau$ the time to expiry in
years. The difference $F_t - S_t$ is the **basis**. On June 2, 2025, with the three-month rate from the course curve
and a dividend yield of 1.35%:

```python
curva = pd.read_csv("curva_tipos_diaria.csv", parse_dates=["fecha"],
                    index_col="fecha")
r = curva.loc["2025-06-02", "3m"] / 100
q = 0.0135
dia = dia.assign(teorico=S * np.exp((r - q) * dia["dias"] / 365))
dia["base"] = dia["liquidacion"] - S
print(f"Index {S}, r = {r:.3%}, q = {q:.2%}")
dia[["contrato", "dias", "liquidacion", "teorico", "base"]].round(2)
```
```output
Index 6359.1, r = 4.354%, q = 1.35%
     contrato  dias  liquidacion  teorico    base
4867   FIXM25    18      6367.75  6368.53    8.65
4868   FIXU25   109      6419.00  6416.40   59.90
4869   FIXZ25   200      6462.50  6464.64  103.40
```

The three settlement prices are less than three points from their theoretical value: the difference is rounding to
the tick and a little noise. The basis grows with maturity: 8.65 points at 18 days, 59.90 at 109 and 103.40 at 200.
And since the time to expiry shortens every day, a contract's basis is gradually used up until it disappears:

```python
z25 = fut[fut["contrato"] == "FIXZ25"].set_index("fecha")
base = (z25["liquidacion"] - indice.reindex(z25.index)).rename("base")
pd.concat([z25["dias"], base.round(2)], axis=1).iloc[[0, 50, 100,
                                                      150, -2, -1]]
```
```output
            dias    base
fecha
2025-03-19   275  109.70
2025-05-30   203  103.12
2025-08-12   129   63.00
2025-10-22    58   27.06
2025-12-18     1    0.65
2025-12-19     0    0.00
```

*Fig. — Basis of the FIXZ25 future against the index, from its first trading day to its expiry.* Daily line of the basis, future minus index in points, from 19 March to 19 December 2025. It starts at 109.7 points 275 days before expiry, declines with small wiggles almost in a straight line and reaches zero, highlighted, on expiry day, when the final settlement is the index close.

FIXZ25 starts trading in March 2025 with a basis of 109.70 points at 275 days and ends on December 19 with zero basis:
its final settlement is the index close. That is why an index future “loses” against the index when the rate exceeds
the dividend yield: it is not a poor return, it is the interest the buyer of the future does not pay and that the
unspent money does earn.

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

In commodity futures, the relationship changes: the cost of carry includes storage and a “convenience yield” for
holding the physical commodity, and the term structure also reflects expected supply and demand. In financial futures
(indexes, bonds, currencies), arbitrage ties it almost exactly to the rate and to the yield of the underlying.

</aside>

## Contango and backwardation

The **term structure** is the price of each expiry on the same day. It has two basic shapes:

- **Contango**: the far expiries trade more expensive than the near ones (and than spot). In an index, when
  $r > q$.
- **Backwardation**: the far expiries trade cheaper. In an index, when $r < q$.

```python
def curva_futuros(fecha):
    d = fut[(fut["fecha"] == fecha) & (fut["dias"] > 0)]
    s = indice[fecha]
    return d.assign(sobre_contado_pct=100 * (d["liquidacion"] / s - 1))

for fecha in ["2021-06-01", "2025-06-02"]:
    print(fecha, f"3m rate: {curva.loc[fecha, '3m']:.2f} %")
    print(curva_futuros(fecha)[["contrato", "dias", "liquidacion",
                                "sobre_contado_pct"]].round(2))
```
```output
2021-06-01 3m rate: 0.16 %
     contrato  dias  liquidacion  sobre_contado_pct
1836   FIXM21    17      4040.75              -0.07
1837   FIXU21   108      4022.25              -0.52
1838   FIXZ21   199      4010.75              -0.81
2025-06-02 3m rate: 4.35 %
     contrato  dias  liquidacion  sobre_contado_pct
4867   FIXM25    18      6367.75               0.14
4868   FIXU25   109      6419.00               0.94
4869   FIXZ25   200      6462.50               1.63
```

*Fig. — Term structure of the FIX futures on two dates: backwardation in 2021 and contango in 2025.* Two curves with the price of each expiry over the spot index, in percent, against days to expiry. On 2 June 2025, with a 4.35% rate, in blue, the curve rises: +0.14% at 18 days, +0.94% at 109 and +1.63% at 200. On 1 June 2021, with a 0.16% rate, in orange, it falls: −0.07%, −0.52% and −0.81% at 17, 108 and 199 days.

On June 1, 2021, with the three-month rate at 0.16%, below the dividend yield, the curve slopes down: backwardation.
On June 2, 2025, with the rate at 4.35%, it slopes up: contango. To measure the periods with all the data, it is
enough to compare the two nearest expiries each day and annualize the difference:

```python
vivos = fut[fut["dias"] > 0].sort_values(["fecha", "vencimiento"])
dos = vivos.groupby("fecha").head(2)
par = dos.groupby("fecha").agg(f1=("liquidacion", "first"),
                               f2=("liquidacion", "last"),
                               d1=("dias", "first"),
                               d2=("dias", "last"))
par["carry"] = np.log(par["f2"] / par["f1"]) / ((par["d2"] - par["d1"])
                                                 / 365)
anual = par.groupby(par.index.year)["carry"]
pd.DataFrame({"contango_pct_dias": 100 * anual.apply(lambda x:
                                                     (x > 0).mean()),
              "carry_medio_pct": 100 * anual.mean()}).round(1)
```
```output
       contango_pct_dias  carry_medio_pct
fecha
2019                62.7              0.2
2020                 0.0             -1.4
2021                 0.0             -1.4
2022                62.5              0.7
2023               100.0              3.5
2024               100.0              3.5
2025               100.0              2.7
```

All of 2020 and 2021 in backwardation, with an average carry of −1.4% a year: rates were close to zero and the index
dividend weighed more. All of 2023, 2024 and 2025 in contango, with a carry of 2.7 to 3.5 points a year. 2019 and 2022
are transition years, with 63% of sessions in contango.

What changes for an investor? Whoever holds a long futures position and rolls it every quarter sells the expiring
contract (close to spot) and buys the next one (more expensive in contango). That “roll cost” is not an extra loss: it
is the same cost of carry that the basis gradually uses up, and it is offset by the interest on the cash that has not
been invested. Comparing the return of a future with that of the index without adding that interest makes the future
look as if it returns less than it does.

## The roll: when liquidity moves

A few days before expiry, most positions are moved to the next contract: the front one is closed and the next one is
opened, often with a single calendar *spread* order. Volume and open interest migrate:

```python
roll = fut[fut["contrato"].isin(["FIXM25", "FIXU25"])
           & fut["fecha"].between("2025-06-05", "2025-06-23")]
tabla = roll.pivot(index="fecha", columns="contrato",
                   values="interes_abierto")
cruce = tabla[tabla["FIXU25"] > tabla["FIXM25"]].index[0]
print("The next contract overtakes the front one on", cruce.date())
tabla
```
```output
The next contract overtakes the front one on 2025-06-13
contrato      FIXM25    FIXU25
fecha
2025-06-05  778177.0   34906.0
2025-06-06  764556.0   49050.0
2025-06-09  734660.0   79671.0
2025-06-10  672936.0  141139.0
2025-06-11  563376.0  247645.0
2025-06-12  413715.0  393825.0
2025-06-13  263789.0  540829.0
2025-06-16  153647.0  648266.0
2025-06-17   90019.0  709669.0
2025-06-18   58420.0  741939.0
2025-06-20   44111.0  763316.0
2025-06-23       NaN  805582.0
```

*Fig. — The June 2025 roll: open interest (top) and volume (bottom) of the expiring contract, FIXM25, and the next one, FIXU25.* Two daily panels from 27 May to 27 June 2025. Top, FIXM25 open interest stays near 780 thousand contracts until 6 June and falls to 44 thousand on expiry day, the 20th; FIXU25 open interest rises from 25 thousand and overtakes it on 13 June, highlighted, with 541 thousand. Bottom, FIXM25 volume dominates until 11 June and FIXU25 volume jumps from the 12th, peaking at 807 thousand on the 13th.

On June 5, FIXM25 has 778,177 open contracts and FIXU25, 34,906. A week later they cross: on June 12 they are almost
level (413,715 versus 393,825) and on Friday the 13th the September contract already has more open interest. That
same day the volume of FIXU25 shoots up (807,106 contracts): it is the busiest day of the roll. On June 20, expiry
day, FIXM25 has 44,111 contracts left, 6% of the peak, which are settled in cash at the index close.

For a trading system, this has two consequences. First, whoever trades the front contract during the roll week does
so in a contract that is emptying: spreads widen and the cost rises. Second, to have a long series you have to chain
contracts, and the rule for jumping from one to the next (by date, by volume, by open interest) and how the price
jump between them is corrected are decisions that change the results of a backtest. That construction is lesson
1.4.6.

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

Simply stitching together the prices of each day's front contract produces a series with a jump at every roll: the
basis of the new contract versus that of the old one. In contango, the series rises artificially at every roll; in
backwardation, it falls. An indicator or a stop calculated on that series sees moves that nobody has gained or lost.

</aside>

## What this changes in your data

- **The price of a future is a settlement price.** The standard daily data point is not the last trade, but the price
  the clearing house sets. To compare with the index you have to know at what time and how each one is calculated.
- **Size is measured in notional.** One FIX contract is about 300,000 USD; the margin is collateral, not the risk.
- **Cash in reserve is part of the strategy.** Margin calls happen on bad days and can add up to several times the
  initial margin.
- **The basis is not return.** Future and index differ by the cost of carry; the return of a future is compared with
  that of the index minus the interest rate, not with the index alone.
- **Continuous series are built.** There is no ten-year “futures price”: there is a roll rule and an adjustment
  (lesson 1.4.6).

## Exercises

1. Repeat the margin account simulation for a **short** in FIXH25 from December 16, 2024. How many margin calls does
   it receive and how much cash does the account accumulate by expiry?

**Solution.**

```python
corto = cuenta_margen(h25.loc["2024-12-16":], lado=-1)
print("Margin calls:", (corto["aporte"] > 0).sum())
print(f"Deposited: {corto['aporte'].sum():,.2f} USD")
print(f"P&L: {corto['pyg'].sum():,.2f} USD")
print(f"Final balance: {corto['saldo'].iloc[-1]:,.2f} USD")
```
```output
Margin calls: 5
Deposited: 9,987.50 USD
P&L: 65,332.50 USD
Final balance: 91,820.00 USD
```

The short gains exactly what the long loses, 65,332.50 USD, and ends with 91,820 USD in the account. But the path is
not comfortable: it receives 5 margin calls, for 9,987.50 USD: four in the second half of December 2024 and one on
February 19, 2025, days on which the index rises. A future is a zero-sum game between buyer and seller before costs;
the clearing house only moves the cash from one to the other every day.

2. For each 2024 expiry, find the first day on which the open interest of the next contract exceeds that of the
   expiring one. How many sessions before expiry does it happen?

**Solution.**

```python
oi = fut.pivot(index="fecha", columns="contrato",
               values="interes_abierto")
sesiones = indice.index
pares = [("FIXH24", "FIXM24"), ("FIXM24", "FIXU24"),
         ("FIXU24", "FIXZ24"), ("FIXZ24", "FIXH25")]
for viejo, nuevo in pares:
    v = fut.loc[fut["contrato"] == viejo, "vencimiento"].iloc[0]
    x = oi[[viejo, nuevo]].dropna()
    x = x[x.index > v - pd.Timedelta(days=30)]  # the last month
    dia_cruce = x[x[nuevo] > x[viejo]].index[0]
    antes = ((sesiones > dia_cruce) & (sesiones <= v)).sum()
    print(viejo, "->", nuevo, dia_cruce.date(), f"({antes} sessions)")
```
```output
FIXH24 -> FIXM24 2024-03-11 (4 sessions)
FIXM24 -> FIXU24 2024-06-14 (4 sessions)
FIXU24 -> FIXZ24 2024-09-16 (4 sessions)
FIXZ24 -> FIXH25 2024-12-16 (4 sessions)
```

In the four 2024 rolls the crossover happens four sessions before expiry (counting expiry day itself), in the
previous week. A roll rule “by open interest” would switch contracts on those days; a “fixed date” rule, for example
eight sessions before, would do so earlier, when the new contract still has less liquidity. The last-month filter is
needed: when the new contract starts trading, nine months earlier, both are far expiries and their small open
interest can cross by chance.

3. A colleague says that ETFs on index futures “lose money at every roll because of contango”. Explain which part of
   the statement is correct and what is missing.

**Solution.**

It is true that in contango the new contract costs more than the expiring one, and that the price of a long future
“falls” toward spot as expiry approaches. What is missing is that this contango is, in a financial future, the cost of
carry: the interest rate minus the dividend yield. Whoever buys the future instead of the index does not pay out the
notional and earns interest on that cash, which offsets the basis. If the interest on the cash is added (as a
well-managed ETF does), the return resembles that of the total return index, minus costs. In commodities, where the
term structure reflects storage and expectations, the roll can indeed cost much more than the interest.

## Self-assessment

1. The FIX future trades at 6,400 points with a multiplier of 50 USD and a tick of 0.25. How much does one contract gain or lose per tick and what is its notional?

   - A. 0.25 USD per tick; notional of 6,400 USD
   - B. 12.50 USD per tick; notional of 320,000 USD
   - C. 50 USD per tick; notional of 320,000 USD
   - D. 12.50 USD per tick; notional of 16,500 USD

   *Answer B: 12.50 USD per tick; notional of 320,000 USD.* Tick value = 0.25 × 50 = 12.50 USD; notional = 6,400 × 50 = 320,000 USD. The 16,500 USD is the initial margin: what is deposited, not what is controlled.

2. An account has an initial margin of 16,500 USD and a maintenance margin of 15,000. After a daily loss, the balance is 14,200 USD. What happens?

   - A. Margin call: 2,300 USD has to be deposited to get back to the initial margin
   - B. Nothing: there is still a positive balance
   - C. Margin call: 800 USD has to be deposited to get back to maintenance
   - D. The position is closed automatically

   *Answer A: Margin call: 2,300 USD has to be deposited to get back to the initial margin.* When it falls below maintenance, the account has to return to the initial margin: 16,500 − 14,200 = 2,300 USD. If it is not deposited in time, the broker can close the position.

3. With an interest rate of 4.35% and an index dividend yield of 1.35%, what term structure is expected in the futures on that index?

   - A. Backwardation: the far expiries cheaper
   - B. Flat: all expiries at the same price
   - C. Contango: the far expiries more expensive, around 3% a year above spot
   - D. It cannot be known without knowing the market's opinion

   *Answer C: Contango: the far expiries more expensive, around 3% a year above spot.* By no-arbitrage, F = S·e^((r−q)τ). With r − q = 3%, each expiry trades approximately 3% a year above spot. In a financial future the curve is set by the cost of carry, not by a forecast.

4. What happens to the basis (future − spot) on the expiry date?

   - A. It equals the pending dividend
   - B. It equals the initial margin
   - C. It depends on that day's volume
   - D. It is zero: the final settlement price is set with the index itself

   *Answer D: It is zero: the final settlement price is set with the index itself.* In FIX, the final settlement is the index close that day, so the basis vanishes. In real contracts the reference changes (the special opening quotation in the E-mini S&P 500, an average of the IBEX 35 between 16:15 and 16:45 at MEFF), but the idea is the same.

5. In the June 2025 roll week, the open interest of FIXU25 overtakes that of FIXM25 on June 13. Why does it matter for a trading system?

   - A. It does not matter: the two contracts are the same asset
   - B. Because the front contract stops trading that day
   - C. Because from then on the liquidity is in the next expiry: staying in the front contract makes execution more expensive, and a continuous series has to decide when to switch
   - D. Because the margin doubles

   *Answer C: Because from then on the liquidity is in the next expiry: staying in the front contract makes execution more expensive, and a continuous series has to decide when to switch.* The front contract keeps trading until expiry (June 20), but with less and less open interest. When and how to move from one contract to the next is the central decision of a continuous series (lesson 1.4.6).

## Key points

- The contract sets everything except the price: underlying, multiplier, tick, months, last day and settlement method. In FIX, 50 USD per point and 12.50 USD per tick: a notional of over 300,000 USD with 16,500 of margin.
- Daily settlement turns every move into cash. A long in FIXH25 from mid-December 2024 lost 65,332 USD until expiry and received 12 margin calls: the initial margin is not the maximum loss.
- In a financial future, F = S·e^((r−q)τ): the basis is the cost of carry and it vanishes at expiry.
- Contango (far expiries more expensive) when the rate exceeds the dividend yield; backwardation when it does not. In FIX, backwardation throughout 2020 and 2021, with rates close to zero; contango since 2023.
- In the ~8 sessions before expiry, volume and open interest move to the next contract. Who rolls and when conditions any continuous series.

## Resources

### Research

- [Seasonality in Python. Searching for Intraday Patterns](https://pythonparatrading.com/en/seasonality-intraday-preprocessing/) · Research-0024 · 9 min

### Documentation

- [CME Rulebook, chapter 358: E-mini S&P 500 (unit of 50 USD per point, tick of 0.25 = 12.50 USD, final settlement)](https://www.cmegroup.com/rulebook/CME/IV/350/358/358.pdf) · cmegroup.com
- [MEFF: Mini IBEX 35 futures specifications (in Spanish)](https://www.meff.es/esp/Derivados-Financieros/Futuros-sobre-Mini-IBEX35) · meff.es
- [MEFF: IBEX 35 futures specifications (in Spanish)](https://www.meff.es/esp/Derivados-Financieros/Futuros-sobre-IBEX35) · meff.es

### Data

- [Level 1 data: settlement prices of all FIX contracts (Parquet)](https://pythonparatrading.com/curso/datos/nivel-1/fix_contratos.parquet) · Download · fix_contratos.parquet
- [Level 1 data: FIX contract specifications (CSV)](https://pythonparatrading.com/curso/datos/nivel-1/fix_especificaciones.csv) · Download · fix_especificaciones.csv

Previous lesson: [1.2.2 · ETFs: replication, tracking error, leveraged ETFs and UCITS](https://pythonparatrading.com/en/python-trading-course/level-1/etfs-replication-tracking-error-ucits/)

Next lesson: [1.2.4 · Forex: pairs, pips, lots, rollover and CFDs](https://pythonparatrading.com/en/python-trading-course/level-1/forex-pairs-pips-lots-and-rollover/)
