---
title: "3.1.1 Main futures contracts"
description: "Indices, rates, energy, metals, agriculturals and FX: specs, notional, risk per contract, micros, delivery calendar and liquidity of 23 futures."
url: "https://pythonparatrading.com/en/python-trading-course/level-3/main-futures-contracts/"
lang: "en"
image: "https://pythonparatrading.com/og/en/python-trading-course/level-3/main-futures-contracts.png"
---

# 3.1.1 · Main futures contracts

> A diversified futures system trades indices, bonds, energy, metals, agriculturals and currencies at the same time, and each contract is a different object: another size, another tick, another currency, another delivery calendar. This lesson goes through the 23 synthetic futures of the level, which imitate the most traded real contracts, and measures what matters before trading any of them: how much risk a contract brings, how much it costs, when you have to get out and where the liquidity is.

- 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: 60 min
- Prerequisites: [1.2.3 · Futures: specifications, margin, roll and contango](https://pythonparatrading.com/en/python-trading-course/level-1/futures-contract-specs-margin-and-roll/), [1.4.6 · Continuous futures series: roll rules, difference adjustment and ratio adjustment](https://pythonparatrading.com/en/python-trading-course/level-1/continuous-futures-series-and-roll-adjustment/), [1.1.5 · Costs, settlement, leverage and margin](https://pythonparatrading.com/en/python-trading-course/level-1/trading-costs-settlement-leverage-and-margin/)

## By the end of this lesson

- Read the specifications of a future in each sector (multiplier, tick, months, expiry rule, settlement) and decode its contract codes.
- Calculate the USD notional and the annual risk of a contract, also when it is quoted in another currency, and compare them across sectors.
- Explain what micros and minis are for and measure what they cost in commission per unit of notional.
- Distinguish cash settlement from physical delivery, and place the first notice day and the expiry in the calendar of a contract.
- Measure where the liquidity is (volume, open interest, distribution along the curve) and how much 23 markets really diversify.

## Twenty-three spec sheets

A diversified futures system does not trade “futures”: it trades a US index quoted in points, a European bond quoted as
a percentage of par, crude oil in dollars per barrel and corn in cents per bushel. Each one has its specifications
(lesson 1.2.3) and each set of specifications changes what a point is worth, what trading costs and when you have to
get out. Before writing the first rule, all of them have to be put in the same unit.

The level data has 23 fictitious markets that imitate the most traded real contracts in each sector, with every listed
expiry in each session from 2010 to 2025, and six micros and minis that use the prices of their base market with a
tenth of the multiplier. It is synthetic data: the names are made up and the magnitudes (multipliers, ticks, margins,
volatilities) are plausible, but it is not market data.

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

esp = pd.read_csv("futuros3_especificaciones.csv",
                  index_col="mercado")
base = esp[esp["mercado_base"].isna()]
print(len(base), "markets and", len(esp) - len(base), "micro or mini")
base.groupby("sector")["imita"].apply(
    lambda s: ", ".join(x.split(" (")[-1].rstrip(")") for x in s))
```
```output
23 markets and 6 micro or mini
sector
agricolas                              ZC, ZW, ZS, ZM, ZL
divisas                                                6E
energia      CL, RB, HO, NG, PJM Western Hub Peak mensual
indices                           ES, NQ, RTY, FESX, MEFF
metales                                            GC, SI
tipos                                ZT, ZF, ZN, ZB, FGBL
Name: imita, dtype: str
```

Six sectors. Indices: the E-mini S&P 500 (ES), the E-mini Nasdaq-100 (NQ), the E-mini Russell 2000 (RTY), the Euro
Stoxx 50 (FESX) and MEFF's IBEX 35. Rates: the US Treasury 2-, 5- and 10-year notes and 30-year bond (ZT, ZF, ZN, ZB)
and the German Bund (FGBL). Energy: WTI crude oil (CL), gasoline (RB), heating oil (HO), natural gas (NG) and a monthly
electricity contract. Metals: gold (GC) and silver (SI). Agriculturals: corn (ZC), wheat (ZW), soybeans (ZS), soybean
meal and soybean oil (ZM, ZL). And one currency: the euro against the dollar (6E), here the “Vesperian evro”, `QEV`.

```mermaid
flowchart LR
  F[Futures] --> FI[Financials]
  F --> MP[Commodities]
  FI --> IX[Indices]
  FI --> TP[Rates]
  FI --> DV[Currencies]
  MP --> EN[Energy]
  MP --> MT[Metals]
  MP --> AG[Agriculturals]
  IX --> EF[Cash]
  TP --> FA[Physical with notice]
  DV --> FS[Physical]
  EN --> FS
  MT --> FA
  AG --> FA
```

The way they settle at expiry splits the markets into three groups, and the group decides when a system that does not
want the underlying has to get out: indices are cash-settled; the currency and energy (except the course's
electricity, which is also cash-settled) are delivered; bonds, metals and agriculturals are delivered with a **first
notice day**, from which the seller can give notice of delivery. The calendar section comes back to this.

```python
cols = ["divisa", "multiplicador", "unidad_cotizacion", "tick",
        "valor_tick"]
base.loc[["RVA", "RVH", "TPC", "TPE", "PEC", "GNA", "MTO", "GRM",
          "DQE"], cols]
```
```output
        divisa  multiplicador unidad_cotizacion      tick  valor_tick
mercado
RVA        USD           50.0  puntos de índice  0.250000      12.500
RVH        QEV           10.0  puntos de índice  1.000000      10.000
TPC        USD         1000.0     % del nominal  0.015625      15.625
TPE        QEV         1000.0     % del nominal  0.010000      10.000
PEC        USD         1000.0        USD/barril  0.010000      10.000
GNA        USD        10000.0         USD/MMBtu  0.001000      10.000
MTO        USD          100.0          USD/onza  0.100000      10.000
GRM        USD           50.0   centavos/bushel  0.250000      12.500
DQE        USD       125000.0      USD por evro  0.000050       6.250
```

The multiplier turns the quote into money: 50 USD per point in `RVA`, 1,000 USD per percentage point in the 10-year
note `TPC` (a notional of 100,000 USD), 1,000 barrels in crude oil, 10,000 MMBtu in gas, 100 ounces in gold, 5,000
bushels in corn (50 USD per cent) and 125,000 evros in `DQE`. The tick of the 10-year note is half of a thirty-second
of a point (0.015625 = 15.625 USD), the convention of Treasury futures, and `RVH` and `TPE` are quoted in evros: what
they gain or lose has to be converted to dollars.

The specifications of the real Eurex and MEFF contracts, read on their official pages, match what the data imitates in
the figures that can be compared:

| Real contract | Multiplier | Tick | Expiries | Expiry and settlement |
|---|---|---|---|---|
| E-mini S&P 500 (CME) | 50 USD × index | 0.25 points = 12.50 USD | Quarterly | Third Friday; cash, at the special opening quotation |
| EURO STOXX 50 (Eurex, FESX) | 10 EUR × index | 1 point = 10 EUR | The nearest twelve quarterly | Third Friday (close at 12:00 CET); cash |
| IBEX 35 (MEFF) | 10 EUR × index | Whole points, set by circular | Ten quarterly, two monthly and semi-annual | Third Friday; index average from 16:15 to 16:45; cash |
| Mini IBEX 35 (MEFF) | 1 EUR × index | 5 points = 5 EUR | Same as the IBEX 35 | Same as the IBEX 35 |
| Euro-Bund (Eurex, FGBL) | 100,000 EUR, 6% coupon | 0.01% = 10 EUR | The nearest three quarterly | Delivery on the 10th of the month; last trading two business days before |

The mini in the data (`RVHM`) has a tick of 1 point and MEFF's real one, of 5: it is one of the simplifications of the
data. Eurex also lists a EURO STOXX 50 micro of 1 EUR per point, and MEFF has delisted its Micro IBEX 35 effective
October 1, 2026 (circular C-EX-DF-2026-07). Specifications change: before trading a real contract you read the
exchange's, not a book's or a course's. The CME Group contracts that the other markets imitate (NQ, RTY, ZN, CL, NG,
GC, ZC, ZS, 6E and the micros) have their specifications in the rulebook of each exchange of the group; here only the
figures of the data are used.

Contracts are named with the market root, one letter per month and two digits for the year:

```python
MESES = "FGHJKMNQUVXZ"

def descifra(contrato):
    """PECZ25 -> ('PEC', 2025, 12)."""
    raiz, letra, anio = contrato[:-3], contrato[-3], contrato[-2:]
    return raiz, 2000 + int(anio), MESES.index(letra) + 1

print(descifra("PECZ25"), descifra("GRMH26"), descifra("TPEU24"))
base[["meses", "meses_listados", "liquidacion_fisica"]].loc[
    ["RVA", "RVH", "TPC", "PEC", "GNA", "MTO", "GRM", "GRS"]]
```
```output
('PEC', 2025, 12) ('GRM', 2026, 3) ('TPE', 2024, 9)
                meses  meses_listados  liquidacion_fisica
mercado
RVA              HMUZ              13               False
RVH      FGHJKMNQUVXZ              13               False
TPC              HMUZ               9                True
PEC      FGHJKMNQUVXZ              18                True
GNA      FGHJKMNQUVXZ              24                True
MTO            GJMQVZ              18                True
GRM             HKNUZ              18                True
GRS           FHKNQUX              16                True
```

The months tell which expiries exist: quarterly (`HMUZ`) in US indices, bonds and the currency; every month in the
Spanish index and in energy; six even months in gold (`GJMQVZ`); the harvest months in agriculturals (`HKNUZ` in corn,
`FHKNQUX` in soybeans). `meses_listados` is how far the curve goes: 9 months in bonds (three expiries), 18 in crude oil,
24 in gas. That an expiry is listed does not mean it trades: the liquidity section measures that.

## Notional, tick and risk of a contract

Comparing the 23 markets needs one series per market: the contract held each day. The data has the roll rule of each
contract (`fecha_roll`, the session in which you move to the next one) and with it the series is built as in lesson
1.4.6, with the daily return always calculated with the same contract:

```python
curvas = pd.read_parquet("futuros3_curvas.parquet")
ctr = pd.read_csv("futuros3_contratos.csv",
                  parse_dates=["vencimiento", "primer_aviso",
                               "fecha_alta", "fecha_roll"])

def que_se_tiene(fechas, mercado):
    """The first contract whose roll date is after each date (on
    the roll date the next one is already held)."""
    cm = ctr[ctr["mercado"] == mercado].reset_index(drop=True)
    pos = np.searchsorted(cm["fecha_roll"].to_numpy(),
                          fechas.to_numpy(), side="right")
    return pd.Series(cm["contrato"].to_numpy()[pos], index=fechas)

def serie(mercado):
    """Price and daily return (of the same contract) of the one
    held: the return on the roll day is that of the old contract."""
    c = curvas[curvas["mercado"] == mercado]
    P = c.pivot(index="fecha", columns="contrato",
                values="liquidacion")
    tiene = que_se_tiene(P.index, mercado)
    i = P.columns.get_indexer(tiene)
    filas = np.arange(len(P))
    precio = P.to_numpy()[filas, i]
    ayer = np.r_[i[0], i[:-1]]
    hoy_viejo = P.to_numpy()[filas, ayer]
    antes = np.r_[np.nan, P.to_numpy()[filas[1:] - 1, ayer[1:]]]
    return pd.DataFrame({"contrato": tiene.to_numpy(),
                         "precio": precio,
                         "ret": np.log(hoy_viejo / antes)},
                        index=P.index)

S = {m: serie(m) for m in base.index}
S["PEC"].loc["2025-11-07":"2025-11-14"]
```
```output
           contrato  precio       ret
fecha
2025-11-07   PECZ25   76.42  0.015694
2025-11-10   PECZ25   75.86 -0.007355
2025-11-11   PECZ25   77.49  0.021259
2025-11-12   PECF26   75.59  0.012950
2025-11-13   PECF26   73.59 -0.026815
2025-11-14   PECF26   73.53 -0.000816
```

On November 12, 2025, crude oil moves from `PECZ25` to `PECF26`. The visible price jumps (from 77.49 to 75.59), but
that day's return, 1.30%, is the December contract's between the 11th and the 12th: the jump between contracts is
neither a gain nor a loss. With the series of each market, the notional of a contract is price × multiplier (× USD per
evro for those quoted in `QEV`), and its **annual risk** is the notional times the annual volatility of the return:

```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 ficha_del_dia(dia, mercados):
    filas = {}
    for m in mercados:
        b = esp.loc[m, "mercado_base"]
        s = S[b if isinstance(b, str) else m]
        cambio = usd_qev[dia] if esp.loc[m, "divisa"] == "QEV" else 1
        precio = s.loc[dia, "precio"]
        nominal = precio * esp.loc[m, "multiplicador"] * cambio
        vol = s["ret"].loc[:dia].tail(252).std() * np.sqrt(252)
        filas[m] = {"contrato": s.loc[dia, "contrato"],
                    "precio": precio, "nominal_usd": nominal,
                    "vol_anual": vol, "riesgo_usd": vol * nominal,
                    "tick_pb": 1e4 * esp.loc[m, "valor_tick"]
                    / (precio * esp.loc[m, "multiplicador"])}
    return pd.DataFrame(filas).T.infer_objects()

ficha = ficha_del_dia(DIA, esp.index)
ficha.loc[base.index].sort_values("riesgo_usd").round(
    {"nominal_usd": 0, "vol_anual": 3, "riesgo_usd": 0,
     "tick_pb": 2})
```
```output
        contrato        precio  nominal_usd  vol_anual  riesgo_usd  tick_pb
mercado
TPB       TPBH26    109.164062     109164.0      0.041      4453.0     0.72
TPA       TPAH26    104.449219     208898.0      0.023      4730.0     0.37
GRM       GRMH26    335.750000      16788.0      0.285      4790.0     7.45
TPC       TPCH26    113.078125     113078.0      0.058      6513.0     1.38
GRT       GRTH26    461.500000      23075.0      0.318      7349.0     5.42
GRH       GRHF26    299.200000      29920.0      0.254      7606.0     3.34
GRA       GRAF26     53.110000      31866.0      0.275      8750.0     1.88
TPE       TPEH26    128.120000     174586.0      0.058     10112.0     0.78
GRS       GRSF26   1095.750000      54788.0      0.204     11168.0     2.28
DQE       DQEZ25      1.363950     170494.0      0.075     12826.0     0.37
TPD       TPDH26    122.281250     122281.0      0.113     13824.0     2.56
RVE       RVEZ25   6946.000000      94651.0      0.186     17629.0     1.44
ELB       ELBF26     58.150000      46520.0      0.506     23540.0     8.60
PEC       PECF26     76.690000      76690.0      0.307     23550.0     1.30
MTO       MTOG26   2170.700000     217070.0      0.130     28326.0     0.46
PEG       PEGF26      2.066000      86772.0      0.361     31362.0     0.48
GNA       GNAF26      7.239000      72390.0      0.438     31690.0     1.38
MTP       MTPH26     28.320000     141600.0      0.241     34115.0     1.77
PEH       PEHF26      2.582400     108461.0      0.342     37094.0     0.39
RVC       RVCZ25   3232.000000     161600.0      0.257     41496.0     0.31
RVH       RVHZ25  19700.000000     268447.0      0.223     59866.0     0.51
RVA       RVAZ25   7851.750000     392588.0      0.177     69320.0     0.32
RVB       RVBZ25  26222.000000     524440.0      0.221    116098.0     0.10
```

The table sorts the 23 markets by the risk of one contract, and the order looks nothing like that of the notional. The
2-year note (`TPA`) has a notional of 208,898 USD, almost that of gold, but with a volatility of 2.3% its risk is 4,730
USD a year; corn (`GRM`), with 16,788 USD of notional, has almost the same risk (4,790) because it moves 28.5% a year.
At the other end, a single `RVB` risks 116,098 USD a year. The header figure plots both dimensions on logarithmic
scales: each diagonal is a volatility, and the vertical distance between a bond and an index of similar notional is an
order of magnitude.

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

The `tick_pb` column is the tick size in basis points of the notional: the minimum cost of crossing the bid-ask spread
if it is one tick wide. It goes from 0.10 in `RVB` to 7.45 in corn and 8.60 in electricity. A system with high turnover
in agriculturals pays, proportionally, almost a hundred times more per trade than one with high turnover in indices
(lesson 2.4.7).

</aside>

```python
margen_usd = esp["margen_inicial"] * np.where(
    esp["divisa"] == "QEV", usd_qev[DIA], 1)
ficha["margen_pct"] = 100 * margen_usd / ficha["nominal_usd"]
ficha["apalancamiento"] = ficha["nominal_usd"] / margen_usd
# how many daily standard deviations of the notional the margin covers
ficha["desv_diarias"] = (margen_usd * np.sqrt(252)
                         / ficha["riesgo_usd"])
(ficha.loc[base.index, ["margen_pct", "apalancamiento",
                        "desv_diarias"]]
 .sort_values("apalancamiento").round(2).iloc[[0, 1, 2, -3, -2, -1]])
```
```output
         margen_pct  apalancamiento  desv_diarias
mercado
ELB           15.69            6.37          4.92
GNA           11.74            8.52          4.26
PEG            7.95           12.58          3.49
DQE            1.99           50.15          4.21
TPB            1.65           60.65          6.42
TPA            0.48          208.90          3.36
```

The initial margin goes from 15.69% of the notional in electricity to 0.48% in the 2-year note: leverage of 6 to 1 in
one case and 209 to 1 in the other. But measured in risk it is almost the same: in every market in the table the margin
covers between 3.4 and 6.4 daily standard deviations of the notional. The clearing house sets the margin by risk, so a
contract's leverage tells how little it moves, not how risky it is. Lesson 3.1.3 takes apart how that margin is
calculated and what happens when volatility changes.

## Micros and minis: granularity

A contract is indivisible. With a small account and a reasonable risk target, the problem is not the margin but the
size: a single contract can be too much risk. That is what micros and minis are for, which in the data have a tenth of
the multiplier of their base market:

```python
capital, riesgo_obj = 100_000, 0.20
micro = esp[esp["mercado_base"].notna()]
pares = pd.DataFrame({
    "base": micro["mercado_base"],
    "riesgo_base": ficha.loc[micro["mercado_base"],
                             "riesgo_usd"].to_numpy(),
    "riesgo_micro": ficha.loc[micro.index, "riesgo_usd"],
}, index=micro.index)
pares["n_base"] = capital * riesgo_obj / pares["riesgo_base"]
pares["n_micro"] = capital * riesgo_obj / pares["riesgo_micro"]
pares["capital_min_base"] = pares["riesgo_base"] / riesgo_obj
pares.round({"riesgo_base": 0, "riesgo_micro": 0, "n_base": 2,
             "n_micro": 1, "capital_min_base": -3})
```
```output
        base  riesgo_base  riesgo_micro  n_base  n_micro  capital_min_base
mercado
RVAM     RVA      69320.0        6932.0    0.29      2.9          347000.0
RVBM     RVB     116098.0       11610.0    0.17      1.7          580000.0
RVCM     RVC      41496.0        4150.0    0.48      4.8          207000.0
RVHM     RVH      59866.0        5987.0    0.33      3.3          299000.0
PECM     PEC      23550.0        2355.0    0.85      8.5          118000.0
MTOM     MTO      28326.0        2833.0    0.71      7.1          142000.0
```

With 100,000 USD and 20% annual risk (20,000 USD), the ideal position in `RVA` is 0.29 contracts. Buying one
multiplies the risk by 3.5; buying none leaves the market out. With the micro, the position is 2.9 contracts, which is
rounded to 3 with a small error. `capital_min_base` is the capital at which a single contract of the base market is
already the whole risk target: 347,000 USD in `RVA` and 580,000 in `RVB`. Below that, the market cannot be traded with
its large contract without concentrating the risk in it, which is why lesson 2.2.2 removed from the universe the
contracts that weighed too much relative to capital.

Granularity is not free:

```python
def coste_lado_pb(m, ticks=0.5):
    """Half a tick of bid-ask spread plus the commission, per
    contract and side, in basis points of the notional."""
    usd = (ticks * esp.loc[m, "valor_tick"] + esp.loc[m, "comision"])
    if esp.loc[m, "divisa"] == "QEV":
        usd *= usd_qev[DIA]
    return 1e4 * usd / ficha.loc[m, "nominal_usd"]

pd.DataFrame({m: {"base": coste_lado_pb(b), "micro": coste_lado_pb(m)}
              for m, b in micro["mercado_base"].items()}).T.round(2)
```
```output
      base  micro
RVAM  0.21   0.34
RVBM  0.09   0.18
RVCM  0.28   0.59
RVHM  0.31   0.46
PECM  0.95   1.63
MTOM  0.33   0.58
```

With half a tick of spread and the commission in the data, one side in `RVAM` costs 0.34 basis points of the notional
against 0.21 in `RVA`; in crude oil, 1.63 against 0.95. The micro's commission per contract (0.70 USD in `RVAM`) is a
third of the large one's (2.10), but it moves a tenth of the notional. For a low-turnover system it is a reasonable
price for being able to trade; for a high-turnover one, it can eat the edge.

## Calendar: months, expiry, notice and delivery

Each contract has four dates: the listing (first listed day), the roll (when the system moves to the next one), the
first notice day in physically delivered contracts with notice, and the expiry (last trading day):

```mermaid
stateDiagram-v2
  [*] --> Listed
  Listed --> Front: liquidity
  Front --> Roll: fecha_roll
  Roll --> Notice: first notice
  Roll --> Expired: cash
  Notice --> Delivery: long still in
  Notice --> Expired: closed
  Expired --> [*]
  Delivery --> [*]
```

```python
cal = ctr.set_index("contrato").loc[
    ["RVAZ25", "PECF26", "TPCZ25", "GRMZ25"]]
dias = lambda a, b: (b - a).dt.days
pd.DataFrame({
    "alta": cal["fecha_alta"].dt.date,
    "roll": cal["fecha_roll"].dt.date,
    "primer_aviso": cal["primer_aviso"].dt.date,
    "vencimiento": cal["vencimiento"].dt.date,
    "vida_dias": dias(cal["fecha_alta"], cal["vencimiento"]),
    "roll_a_venc": dias(cal["fecha_roll"], cal["vencimiento"]),
})
```
```output
                alta        roll primer_aviso vencimiento  vida_dias  roll_a_venc
contrato
RVAZ25    2024-11-01  2025-12-09          NaT  2025-12-19        413           10
PECF26    2024-07-01  2025-12-11          NaT  2025-12-19        536            8
TPCZ25    2025-03-01  2025-11-24   2025-11-28  2025-12-19        293           25
GRMZ25    2024-06-01  2025-11-13   2025-11-28  2025-12-12        559           29
```

- **`RVAZ25`** (index, cash) expires on the third Friday of December and has no notice: the roll, 10 calendar days
  before, is set by liquidity.
- **`PECF26`** (crude oil, physical delivery) is the January contract, but it expires on December 19: in crude oil,
  trading ends in the month before delivery. The roll is 8 days before.
- **`TPCZ25`** (10-year note) expires on December 19, but its first notice is November 28, the last business day of the
  previous month: from then on the seller can give notice of delivery. The roll in the data is November 24, 25 days
  before expiry.
- **`GRMZ25`** (corn) has its first notice on November 28 and expires on December 12; the roll is November 13, 10
  sessions before the notice.

*Fig. — The last 140 days of three contracts: when they have the largest open interest, when they are held, the roll, the first notice and the expiry.* Three rows, one per contract, with time in calendar days to expiry, from −140 to 0. RVAZ25, cash settled, has its market's largest open interest from −108 to −18 days, is held from −101 to −10 (the roll) and expires at 0. PECF26, physically delivered, has the largest open interest only from −45 to −17 and is held from −37 to −8. TPCZ25, physically delivered with notice, has the largest open interest from −120 to −31, is held from −115 to −25 and its first notice day, highlighted, is −21, three weeks before expiry.

The figure puts three of them on the same axis. In all three, the stretch in which the contract has the largest open
interest in its market starts a few days before it is held and ends a few days before the roll: open interest migrates
before the system moves. In the 10-year note, the whole useful stretch ends three weeks before expiry. A backtest that
keeps the contract “until it expires” because the price still exists is, in reality, trading in a contract without
liquidity and with delivery risk.

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

A long still holding a physically delivered future after the first notice can receive the commodity or the bond. Many
retail brokers do not accept delivery and close the position on their own before a date they set, at whatever price
there is. The date that counts for getting out is the first notice or the broker's, if earlier; never the expiry.

</aside>

## Where the liquidity is

```python
anio = curvas[curvas["fecha"] >= "2025-01-01"]
por_dia = anio.groupby(["mercado", "fecha"])[
    ["volumen", "interes_abierto"]].sum()
liq = por_dia.groupby("mercado").median()
liq["nominal_dia_musd"] = (liq["volumen"]
                           * ficha.loc[liq.index, "nominal_usd"]
                           / 1e6)
liq.sort_values("nominal_dia_musd", ascending=False).round(0).astype(
    int).iloc[[0, 1, 2, 3, -4, -3, -2, -1]]
```
```output
         volumen  interes_abierto  nominal_dia_musd
mercado
RVA      1817640          2271914            713583
RVB       655680           239321            343865
TPC      1429191          4356144            161610
TPE       689645          1150384            120402
GRA       115254           450506              3673
GRH       118998           426642              3560
GRT       133398           422790              3078
ELB         2422            30075               113
```

The notional traded per day (volume × notional of one contract, in millions of USD) separates the markets by several
orders of magnitude: `RVA` moves about 714,000 million a day and the 10-year note, 162,000; wheat, soybean meal and
soybean oil, between 3,100 and 3,700; electricity, 113 million, with a median of 2,422 contracts a day. These are
figures from a simulation, but the order (indices and bonds far above commodities, electricity far below) constrains
the capacity of a system (lesson 2.2.3): a large fund can have the same risk in every market only as long as its orders
are small against the volume of the thinnest one.

```python
anio = anio.assign(tiene=False)
for m in base.index:
    sel = anio["mercado"] == m
    t = que_se_tiene(pd.DatetimeIndex(anio.loc[sel, "fecha"]), m)
    anio.loc[sel, "tiene"] = (anio.loc[sel, "contrato"].to_numpy()
                              == t.to_numpy())
cuota = anio.groupby("mercado").apply(
    lambda g: g.loc[g["tiene"], "volumen"].sum() / g["volumen"].sum())
(100 * cuota).groupby(base["sector"]).agg(["min", "max"]).round(1)
```
```output
            min   max
sector
agricolas  59.2  64.9
divisas    91.3  91.3
energia    34.2  61.7
indices    86.9  91.8
metales    80.2  82.0
tipos      84.8  94.6
```

In indices, bonds and the currency, the contract held concentrates between 85% and 95% of the year's volume; in
metals, around 80%; in agriculturals, from 59% to 65%. In energy, much less: between 34.2% in electricity and 61.7% in
gasoline. Monthly energy contracts spend little time as the front contract and the volume is spread across several
months (and across calendar spreads, lesson 3.2.1). For a system, this means that in energy the next contract is also
liquid and you can choose where on the curve to be, a decision that lesson 3.1.2 connects with roll yield.

## Twenty-three markets are not twenty-three bets

If the markets moved together, 23 markets would give little diversification. The average correlation of daily
returns, within each sector and with the rest:

```python
R = pd.DataFrame({m: S[m]["ret"] for m in base.index}).loc["2011":]
C = R.corr()
sector = base["sector"]
fuera_diag = ~np.eye(len(C), dtype=bool)
resumen = {}
for s in ["indices", "tipos", "energia", "metales", "agricolas"]:
    f = (sector == s).to_numpy()
    dentro = C.to_numpy()[np.ix_(f, f)][fuera_diag[np.ix_(f, f)]]
    fuera = C.to_numpy()[np.ix_(f, ~f)]
    resumen[s] = {"dentro": dentro.mean(),
                  "con_el_resto": fuera.mean()}
print(pd.DataFrame(resumen).T.round(2))
print("currency vs the rest:", round(C.loc["DQE"].drop("DQE").mean(), 2))
```
```output
           dentro  con_el_resto
indices      0.82          0.00
tipos        0.76         -0.05
energia      0.41          0.03
metales      0.85         -0.02
agricolas    0.44          0.00
currency vs the rest: -0.0
```

*Fig. — Mean correlation of daily returns within each sector and with the other markets, 23 synthetic futures (2011-2025).* Horizontal bars by sector, two per sector. Within the sector: equity indices 0.82 (highlighted), bonds 0.76, metals 0.85, agriculturals 0.44 and energy 0.41. With the other markets, all close to zero: from −0.05 for bonds to +0.03 for energy.

Within each sector the correlations are high: 0.82 among the five indices, 0.76 among the bonds, 0.85 between gold
and silver. In energy and agriculturals they are lower (0.41 and 0.44) because they mix markets with their own factors
(electricity, gas, wheat). Across sectors, in this data, they are practically zero. Two consequences:

- Five indices with a correlation of 0.82 are, for risk purposes, little more than one. A system that gives the same
  weight to each market has five times more risk in indices than in currencies without having decided it. Allocating
  risk first by sector and then within each one corrects it (lesson 3.1.4).
- Real diversification comes from combining sectors. In the data, the correlation across sectors is almost zero by
  construction of the generator; in real markets it is not, and it changes with the regime (that between equities and
  bonds, for example, has changed sign several times), so the diversification of a real system has to be estimated and
  monitored.

## What this changes in your systems

- **Everything in risk, nothing in contracts.** A multi-market system decides how much risk it wants in each market
  and translates it into contracts with the notional and volatility of each one, in the account currency.
- **The calendar is part of the strategy.** Roll, first notice and expiry come from the specifications and belong in a
  table, not in the code: the rules change by contract and by exchange.
- **Granularity or cost.** With little capital, micros make it possible to trade markets that would otherwise be left
  out; with a lot, the large contracts are cheaper.
- **Liquidity is not evenly spread.** The markets at the bottom of the liquidity table limit the size of the whole
  system.

## Exercises

1. Calculate the notional of one `RVE` contract and one `RVH` contract on November 26, 2025 in evros and in dollars.
   Compare their volatility measured in evros with that of the return converted to dollars. Which one is relevant for
   the risk of a future?

**Solution.**

```python
fx_r = np.log(usd_qev).diff()
for m in ["RVE", "RVH"]:
    r_qev = S[m]["ret"].loc[:DIA].tail(252)
    r_usd = (r_qev + fx_r.reindex(r_qev.index)).dropna()
    nom_qev = S[m].loc[DIA, "precio"] * esp.loc[m, "multiplicador"]
    print(m, f"notional {nom_qev:,.0f} QEV = "
          f"{nom_qev * usd_qev[DIA]:,.0f} USD;",
          f"vol in QEV {r_qev.std() * np.sqrt(252):.3f},",
          f"in USD {r_usd.std() * np.sqrt(252):.3f}")
```
```output
RVE notional 69,460 QEV = 94,651 USD; vol in QEV 0.186, in USD 0.199
RVH notional 197,000 QEV = 268,447 USD; vol in QEV 0.223, in USD 0.230
```

A dollar investor who buys a future on a European index does not hold the notional in evros: only the daily result,
which is settled in evros and converted to dollars (and the margin deposited). That is why the currency risk of a
future is much smaller than that of buying the index in the cash market, and the relevant volatility is that of the
return in evros, converted at the day's exchange rate. The one measured by adding the exchange rate return would be that
of a cash investment in the European index. Lesson 3.3.3 deals with the currency risk of a multi-currency portfolio.

2. With the `ficha` table, how many contracts of each market would be needed for all of them to contribute 50,000 USD
   of annual risk? Which markets need less than one contract and why is it a problem?

**Solution.**

```python
n = 50_000 / ficha.loc[base.index, "riesgo_usd"]
print(n.round(2).sort_values().to_string())
```
```output
mercado
RVB     0.43
RVA     0.72
RVH     0.84
RVC     1.20
PEH     1.35
MTP     1.47
GNA     1.58
PEG     1.59
MTO     1.77
PEC     2.12
ELB     2.12
RVE     2.84
TPD     3.62
DQE     3.90
GRS     4.48
TPE     4.94
GRA     5.71
GRH     6.57
GRT     6.80
TPC     7.68
GRM    10.44
TPA    10.57
TPB    11.23
```

The large indices need less than one contract for 50,000 USD of risk, and the short notes more than ten. Rounding the
`RVB` fraction to 0 leaves the market out; to 1, it gives it more than twice the requested risk. The solutions are to
raise the capital, use the micro or accept that some markets do not fit (the universe block of lesson 2.2.2).

3. Explain why `PECF26` expires in December 2025 and what would happen in a backtest that, to keep things simple,
   assumed that all contracts expire on the third Friday of the month in their code.

**Solution.**

In crude oil, trading in a contract ends in the month before delivery (the rule in the data: three sessions before
the 25th of the previous month), because delivery takes place throughout the contract month. A backtest that assumed
it expired on the third Friday of January would hold the contract a month longer than possible: it would roll late,
use prices of a contract that no longer trades (or make them up) and miscalculate the carry, which depends on the
distance between expiries (lesson 3.1.2). The calendar of each contract has to come from its specifications.

## Self-assessment

1. On November 26, 2025, one RVA contract (multiplier 50 USD) is worth 392,588 USD and one TPA (2-year note, multiplier 2,000) is worth 208,898 USD. Which one adds more risk to a portfolio?

   - A. TPA, because its leverage (notional over margin) is ten times higher
   - B. Both the same, because the notionals are similar
   - C. RVA: with an annual volatility of 17.7% against 2.3%, its annual risk is about 69,300 USD per contract against about 4,700
   - D. It cannot be known without the initial margin

   *Answer C: RVA: with an annual volatility of 17.7% against 2.3%, its annual risk is about 69,300 USD per contract against about 4,700.* The risk of a contract is its notional times the volatility of its return. TPA has more leverage (209 to 1) because the clearing house asks little margin for an asset that moves little; matching the risk of one RVA would take almost fifteen TPA.

2. What does the code `GRMH26` mean?

   - A. The corn contract (GRM) for delivery in March (H) 2026
   - B. The 2026 corn contract that expires in June
   - C. Corn contract number 26 of the year
   - D. The corn micro

   *Answer A: The corn contract (GRM) for delivery in March (H) 2026.* Market root, delivery month letter (F January, G February, H March, J April, K May, M June, N July, Q August, U September, V October, X November, Z December) and two digits for the year.

3. A 100,000 USD account wants an annual risk of 20%. One RVA contract brings about 69,300 USD of risk a year and its micro RVAM, a tenth of that. What is reasonable?

   - A. Buy one RVA: it is the closest to the target
   - B. Never trade indices
   - C. Buy one RVA and reduce the leverage with the margin
   - D. Use the micro: 2.9 micros get close to the target, while one RVA would take the risk to 69% of capital

   *Answer D: Use the micro: 2.9 micros get close to the target, while one RVA would take the risk to 69% of capital.* With 100,000 USD and 20% risk, the target is 20,000 USD a year: 0.29 RVA contracts. Rounding to 1 multiplies the risk by 3.5. The micro lets you get close (3 micros, about 20,800 USD), at the price of paying more commission per unit of notional (0.34 against 0.21 basis points per side in the data).

4. Why does a system exit a bond future before its first notice day instead of waiting for the last trading day?

   - A. Because after the first notice the contract stops trading
   - B. Because from the first notice a long can receive a delivery notice, and the liquidity is already in the next contract
   - C. Because the margin is multiplied by ten
   - D. Because the specifications require it

   *Answer B: Because from the first notice a long can receive a delivery notice, and the liquidity is already in the next contract.* In physically delivered contracts with notice, the seller can give notice of delivery from the first notice day: a long still holding can end up receiving the bond. In TPCZ25 the first notice is 21 days before expiry and the roll in the data, 25 days before.

5. The five indices of the course have an average correlation of 0.82 with each other. What does it imply for a system that gives them the same risk as five weakly correlated markets?

   - A. That the risk of the indices adds up almost entirely: they are almost a single bet, and the portfolio has much more risk in that sector than it seems
   - B. Nothing: five markets are five bets
   - C. That only indices should be traded
   - D. That correlation does not affect risk

   *Answer A: That the risk of the indices adds up almost entirely: they are almost a single bet, and the portfolio has much more risk in that sector than it seems.* The variance of a sum depends on the correlations. With 0.82, five equal positions have almost the risk of a single position five times larger. That is why diversified systems allocate risk by sector and not only by market (lesson 3.1.4).

## Key points

- The specifications set everything except the price: multiplier, tick, months, last day and settlement method. The same “1 contract” goes from 16,788 USD of notional (corn) to 524,440 (RVB).
- What you compare across markets is the risk of one contract (notional × volatility), not the notional or the margin: in the data, from about 4,500 USD a year (2- and 5-year notes) to 116,098 (RVB).
- The initial margin covers 3 to 6 daily standard deviations of the notional: that is why a 2-year bond has leverage of 209 to 1 and electricity 6 to 1. Leverage does not measure risk.
- Micros and minis give granularity to small accounts (with 100,000 USD, 2.9 RVAM micros against 0.29 RVA) at the price of a higher cost per unit of notional.
- In physically delivered contracts you have to exit before the first notice day; in cash-settled ones, liquidity decides the roll. In energy, less than half the volume is in the contract you hold.
- The data is synthetic: the figures imitate the real contracts, but for trading the official specifications of each exchange are what counts.

## Resources

### Documentation

- [Eurex: EURO STOXX 50 Index Futures (FESX), specifications](https://www.eurex.com/ex-en/markets/idx/stx/euro-stoxx-50-derivatives/products/EURO-STOXX-50-Index-Futures-160088) · eurex.com
- [Eurex: Euro-Bund Futures (FGBL), specifications](https://www.eurex.com/ex-en/markets/int/long-term-interest-rates/fix/government-bonds/Euro-Bund-Futures-137298) · eurex.com
- [MEFF: IBEX 35 futures (in Spanish)](https://www.meff.es/esp/Derivados-Financieros/Futuros-sobre-IBEX35) · meff.es
- [MEFF: Mini IBEX 35 futures (in Spanish)](https://www.meff.es/esp/Derivados-Financieros/Futuros-sobre-Mini-IBEX35) · meff.es
- [MEFF: circular C-EX-DF-2026-07 (underlyings of index derivatives; delisting of the Micro IBEX 35, in Spanish)](https://www.meff.es/docs/esp/normativa/circulares/2026/C-EX-DF-2026-07-Subyacentes-de-los-Derivados-sobre-Indice-.pdf) · meff.es
- [CME Rulebook, chapter 358: E-mini S&P 500](https://www.cmegroup.com/rulebook/CME/IV/350/358/358.pdf) · cmegroup.com

### Data

- [Level 3 data: futures specifications (CSV)](https://pythonparatrading.com/curso/datos/nivel-3/futuros3_especificaciones.csv) · Download · futuros3_especificaciones.csv

Next 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/)
