Lesson 3.1.3 · 65 min
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.
- Module
- 3.1 · Futures in depth
- Duration
- 65 min
- Prerequisites
- 3.1.1 · Main futures contracts, 3.1.2 · Futures curve: basis, cost of carry, contango and roll yield, 1.2.3 · Futures: specifications, margin, roll and contango
- Author
- Jesús Cuesta
- Updated
Level 3 lessons
3.1 · Futures in depth
3.2 · Futures spreads
- 3.2.1 Calendar spreads, butterflies and condors
- 3.2.2 Intercommodity spreads: crack, spark and crush
- 3.2.3 Rate and index spreads: 2s10s, NOB, NQ/ES and Europe versus the U.S.
- 3.2.4 Hedge ratios: by notional, by DV01 and by volatility
- 3.2.5 Spread data and backtesting: listed, synthetic and legged
- 3.2.6 Seasonality of spreads: multi-year analysis, patterns and traps
3.3 · Advanced forex
3.4 · Option theory and pricing
- 3.4.1 Payoffs, put-call parity and arbitrage bounds
- 3.4.2 Binomial trees, Black-Scholes-Merton, Black-76 and Monte Carlo
- 3.4.3 Greeks: delta, gamma, vega, theta, rho, vanna, volga and charm
- 3.4.4 Implied volatility: Newton-Raphson, Brent, py_vollib and QuantLib
- 3.4.5 Smile, skew and term structure; volatility surface with SVI
- 3.4.6 Realized vs implied volatility; volatility risk premium; VIX and VSTOXX
- 3.4.7 Advanced models: Heston, SABR and local volatility
3.5 · Option structures in Python
- 3.5.1 Directional and vertical structures: call, put, covered call, collar and spreads
- 3.5.2 Volatility and range structures: straddles, strangles, condors and butterflies
- 3.5.3 Calendars, diagonals, ratios, backspreads, risk reversals and jade lizard
- 3.5.4 A custom tool: payoff, aggregate Greeks and scenarios
- 3.5.5 Management: adjustments, rolls, early closes, early assignment and pin risk
3.6 · Systematic volatility and options strategies
3.7 · Crypto derivatives and specific strategies
- 3.7.1 Perpetuals: funding mechanics, mark price and liquidations
- 3.7.2 Funding arbitrage, basis with futures and cross-exchange arbitrage
- 3.7.3 Crypto options, on-chain data and DeFi
- 3.7.4 ccxt for trading on multiple exchanges
- 3.7.5 MiCA: the EU framework for crypto-assets and their service providers (CASPs)
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:
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"]] 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 4Physically 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 source
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 --> GA 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:
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) 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.4The 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.
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:
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) 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.78The 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:
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) 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.32Per 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:
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) 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.5In 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:
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) 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
RVAand 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 source
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):
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))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.
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"])no credit: 44900.0 with 50%: 34800.0A 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:
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}") 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.7In 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.
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:
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()) 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
- Use
margen_escenariosto calculate the margin of a calendar butterfly in crude oil (long 1PECF26, short 2PECG26, long 1PECH26). What spread charge does the function apply and why is it probably too high?
Solution
print(margen_escenarios({"PECF26": 1, "PECG26": -2, "PECH26": 1})){'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.
- 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
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}") 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.0With 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.
- With the
carttable, 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.
Each answer is folded under its question
Self-assessment
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?
- AThat 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
- BThat it does not matter when you roll
- CThat you always have to roll on expiry day
- DThat corn has no roll
Show answer
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.
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?
- ASelling the old contract and buying the new one at market separately
- BWith 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
- CLetting the contract expire
- DIt does not matter: the cost is the same
Show answer
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).
A position long PECF26 and short PECG26 has zero scanning risk in the lesson's calculation. Why is the margin not zero?
- ABecause the clearing house charges a fixed fee
- BBecause shorts always pay more margin
- CBecause it is a calculation error
- DBecause 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
Show answer
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.
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?
- ANone: margin is not a loss
- BThat more contracts have to be traded
- CThat it needs reserve cash: margin rises exactly when there are losses, and whoever cannot post it has to cut positions at the worst moment
- DThat margin falls in crises
Show answer
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.
The lesson's portfolio has a notional of 426% of capital and a margin of 14.7%. Which number best describes its risk?
- AThe notional: the portfolio is leveraged 4.3 times
- BThe margin: it risks 14.7% of capital
- CNeither: 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
- DThe sum of the two
Show answer
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.