Lesson 7.4.2 · 60 min
ESMA and CFDs: leverage, close-out and negative balance
Since 2018 an EU retail client cannot open a CFD with more leverage than ESMA sets, and in Spain a CNMV resolution with the same rules has applied since 2019. This lesson turns those rules into a margin calculator and an account simulator, and tests them on the series from levels 2 and 3.
- Module
- 7.4 · Regulation, ethics and taxation
- Duration
- 60 min
- Prerequisites
- 1.2.4 · Forex: pairs, pips, lots, rollover and CFDs, 4.2.6 · Derivatives risk: portfolio Greeks, margin and liquidations, 7.4.1 · MiFID II: clients, suitability and algorithmic trading
- Author
- Jesús Cuesta
- Updated
Level 7 lessons
7.1 · Software engineering for trading
7.2 · Infrastructure and deployment
7.3 · MLOps for trading models
7.4 · Regulation, ethics and taxation
- 7.4.1 MiFID II: clients, suitability and algorithmic trading
- 7.4.2 ESMA and CFDs: leverage, close-out and negative balance
- 7.4.3 PRIIPs, the KID and US ETFs
- 7.4.4 MiCA after the transitional period: checking a provider in the registers
- 7.4.5 Market abuse: spoofing, layering and the bot that imitates them by accident
- 7.4.6 Trading taxes in Spain
- 7.4.7 Ethics: personal data, artificial intelligence and selling signals
7.5 · Quant career
7.6 · Final capstone
- 7.6.1 Capstone: common requirements, the panel's rubric and preparing the defense
- 7.6.2 Capstone C1: a multi-asset futures system, from forecast to paper account
- 7.6.3 Capstone C2: systematic options book, volatility surface and real-time Greeks
- 7.6.4 Capstone C3: stock and ETF portfolio with ML, HRP and Spanish taxation
- 7.6.5 Capstone C4: a research platform with LLMs and alternative data
- 7.6.6 Capstone C5: crypto market making or arbitrage with counterparty control
From the ESMA decision to the CNMV resolution
Lesson 1.2.4 presented the limits on CFDs for retail clients and computed how much movement closes a position in EURUSD. This lesson goes to the sources and to the detail that decides the outcome of an account: which underlying falls in which band, how the 50% close-out is measured, what happens with a price gap and where the figure in the warning comes from. The framework is the EU one as applied in Spain.
The product intervention power came with Regulation (EU) 600/2014 (MiFIR), applicable since January 3, 2018: its Article 40 allows ESMA to temporarily restrict a product throughout the EU and Article 42 allows each national authority to do so in its own country. On May 22, 2018 ESMA adopted two decisions: banning binary options for retail clients from July 2 and restricting CFDs from August 1 (Decision (EU) 2018/796), for three renewable months. According to the CNMV (Comisión Nacional del Mercado de Valores, Spain's securities market regulator), ESMA renewed them three times. To give them stability, each authority adopted equivalent national measures; in Spain, the CNMV Resolution of June 27, 2019, whose CFD chapter came into force on August 1, 2019 and still applies “as long as the CNMV does not consider that there have been changes in market conditions that allow its repeal” (unofficial translation).
Mermaid source
flowchart TB A[MiFIR art. 40 and 42] --> B[ESMA 2018/796] B --> C[CNMV June 2019] C --> D[CNMV July 2023]
The 2019 resolution applies to all marketing, distribution and sale of CFDs to retail clients resident in Spain, whatever the country of the firm and whether or not it has a branch there; if another authority imposes something different, the stricter rule applies. It treats as CFDs, among others, rolling spot forex and spread bets, and it leaves out warrants and turbos. It does not apply to professional clients: that is why lesson 7.4.1 insists on what is lost by asking for that treatment.
The five conditions of Article 4
Article 4 of the resolution allows a CFD to be sold to a retail client only if all of these conditions are met:
| Condition | What it requires | Definition |
|---|---|---|
| a) Initial margin | Charge the client at least the margin in Annex I | Art. 3.c and Annex I |
| b) Margin close-out | Liquidate CFDs when funds plus unrealized net profits fall below half of the total initial margin | Art. 3.e |
| c) Negative balance | The client's liability is limited to the funds in the CFD account | Art. 3.f |
| d) No incentives | No payments or monetary or non-monetary benefits for trading, except information and research tools | Art. 3.b |
| e) Warning | Every communication carries the Annex II warning with the percentage of losing accounts | Annex II |
Annex I sets the margin by type of underlying. The detail is in the lists: there are six “major currencies” (US dollar, euro, yen, pound, Canadian dollar and Swiss franc), and the 5% indices are ten named ones, with their 2019 names (“DAX30”). The IBEX 35 is not among them. A calculator that applies it as written:
import numpy as np
import pandas as pd
PRINCIPALES = {"USD", "EUR", "JPY", "GBP", "CAD", "CHF"}
INDICES_5 = {"FTSE 100", "CAC 40", "DAX30", "DJIA", "S&P 500",
"NASDAQ", "NASDAQ 100", "Nikkei 225", "ASX 200",
"EURO STOXX 50"}
def garantia_inicial(tipo, nombre=""):
"""Fraction of the notional (Annex I of the 2019 Resolution)."""
if tipo == "divisa":
a, b = nombre[:3], nombre[3:]
return 0.0333 if {a, b} <= PRINCIPALES else 0.05
if tipo == "indice":
return 0.05 if nombre in INDICES_5 else 0.10
if tipo == "materia_prima":
return 0.05 if nombre == "oro" else 0.10
if tipo == "cripto":
return 0.50
return 0.20 # stocks and any other underlying
cartera = pd.DataFrame([
("divisa", "EURUSD", 100_000), ("divisa", "EURTRY", 20_000),
("indice", "DAX30", 40_000), ("indice", "IBEX 35", 40_000),
("materia_prima", "oro", 20_000),
("materia_prima", "brent", 20_000),
("accion", "una acción", 10_000), ("cripto", "BTC", 4_000),
], columns=["tipo", "subyacente", "nominal_eur"])
pares = zip(cartera["tipo"], cartera["subyacente"])
cartera["garantia_pct"] = [100 * garantia_inicial(t, s)
for t, s in pares]
cartera["garantia_eur"] = (cartera["nominal_eur"]
* cartera["garantia_pct"] / 100)
print(cartera.to_string(index=False))
total = cartera["garantia_eur"].sum()
nominal = cartera["nominal_eur"].sum()
print(f"total margin {total:,.0f} EUR for {nominal:,.0f} EUR of "
f"notional (average leverage {nominal / total:.1f}:1)") tipo subyacente nominal_eur garantia_pct garantia_eur
divisa EURUSD 100000 3.33 3330.0
divisa EURTRY 20000 5.00 1000.0
indice DAX30 40000 5.00 2000.0
indice IBEX 35 40000 10.00 4000.0
materia_prima oro 20000 5.00 1000.0
materia_prima brent 20000 10.00 2000.0
accion una acción 10000 20.00 2000.0
cripto BTC 4000 50.00 2000.0
total margin 17,330 EUR for 254,000 EUR of notional (average leverage 14.7:1)The data values of the table stay in Spanish, as in the rest of the course: divisa (currency), indice (index),
materia_prima (commodity), accion (stock), oro (gold). The same notional in the DAX30 and in the IBEX 35 costs
twice the margin in the second, and the EURTRY pair, with a currency that is not on the list, goes to 5%. The
average leverage of the portfolio, which mixes bands, is none of those in the annex: that is what happens in a real
account.
What maximum leverage means with data
ESMA did not pick the figures by eye. In its decision it explains that it calibrated the margin of each underlying according to its volatility, simulating with about ten years of daily prices the probability that a client loses 50% of their initial investment over an appropriate holding period, with the aim of making that probability consistent across underlyings. The same exercise can be done with the course data. The series imitate real markets; the band assigned to each is that of the market it imitates, and this is an assumption of the lesson:
| Series (data) | Imitates | Annex I band | Margin |
|---|---|---|---|
QEVUSD (fx3_diario) | EURUSD | Two major currencies | 3.33% |
USDQMP (fx3_diario) | USDMXN | Other currency | 5% |
RVE (futuros3_indices_contado) | EURO STOXX 50 | Major index | 5% |
MEA (futuros2_continuos) | Gold | Gold | 5% |
RVH (futuros3_indices_contado) | IBEX 35 | Other index | 10% |
ENA (futuros2_continuos) | Light crude | Other commodity | 10% |
120 stocks (universo2_ajustados) | Stocks | Stocks | 20% |
XBQ on boreal (cripto3_diario) | Bitcoin | Cryptocurrency | 50% |
The experiment: the whole account balance as margin (the maximum leverage allowed), one position opened every session, long or short, held for 20 sessions. It is closed out if at any daily close the loss reaches half of the margin, that is, an adverse move of half of the annex percentage:
from numpy.lib.stride_tricks import sliding_window_view
fx = pd.read_parquet("fx3_diario.parquet")
ind = pd.read_csv("futuros3_indices_contado.csv", parse_dates=["fecha"])
fut = pd.read_parquet("futuros2_continuos.parquet")
acc = pd.read_parquet("universo2_ajustados.parquet")
cri = pd.read_parquet("cripto3_diario.parquet")
def serie(df, col_id, valor, col_precio):
s = df[df[col_id] == valor].set_index("fecha")[col_precio]
return s.sort_index().dropna()
series = {
"QEVUSD": (serie(fx, "par", "QEVUSD", "spot"), 0.0333),
"USDQMP": (serie(fx, "par", "USDQMP", "spot"), 0.05),
"RVE": (serie(ind, "indice", "RVE", "contado"), 0.05),
"MEA": (serie(fut, "mercado", "MEA", "cierre_ajustado"), 0.05),
"RVH": (serie(ind, "indice", "RVH", "contado"), 0.10),
"ENA": (serie(fut, "mercado", "ENA", "cierre_ajustado"), 0.10),
"XBQ": (serie(cri[cri["exchange"] == "boreal"], "activo", "XBQ",
"cierre_spot"), 0.50),
}
def prob_cierre(precios, garantia, h=20):
"""Fraction of h-session windows with a close-out (long/short mean)."""
v = sliding_window_view(np.asarray(precios, float), h + 1)
r = v[:, 1:] / v[:, :1] - 1
largo = (r <= -0.5 * garantia).any(axis=1).mean()
corto = (r >= 0.5 * garantia).any(axis=1).mean()
return (largo + corto) / 2
res = {k: prob_cierre(s, g) for k, (s, g) in series.items()}
por_accion = [prob_cierre(g["cierre_ajustado"], 0.20)
for _, g in acc.sort_values("fecha").groupby("ticker")
if len(g) > 21]
res["stocks"] = float(np.mean(por_accion))
prob = pd.Series(res).sort_values(ascending=False)
(100 * prob).round(1)RVE 52.7
ENA 51.6
MEA 49.8
QEVUSD 39.8
USDQMP 36.7
RVH 30.0
stocks 19.3
XBQ 7.4
dtype: float64The figure at the top sorts the result. At maximum leverage with the whole balance committed, a CFD is closed out by the 50% rule in a large share of the four-week windows, and the share is not the same across underlyings. The single 5% band for major indices, gold and secondary currencies treats series with different volatilities alike, and the same happens between the IBEX 35 and crude oil at 10%. The cryptocurrency, with the 50% margin, is the one closed out least often: the band is conservative for its volatility. The figures depend on the synthetic data; what can be generalized is the method and the order of magnitude.
The way to reduce that probability is decided not by the rule but by the client: not committing the whole balance. The same account with less effective leverage on the major pair:
qev = series["QEVUSD"][0]
for apal in (30, 20, 10, 5, 2):
# with effective leverage L, the close-out comes with a fall
# of 50% of the balance: a move of 0.5 / L
p = prob_cierre(qev, 1 / apal)
print(f"{apal:>2}:1 move that closes out {50 / apal:5.2f} % "
f"prob. in 20 sessions {100 * p:5.1f} %")30:1 move that closes out 1.67 % prob. in 20 sessions 39.8 %
20:1 move that closes out 2.50 % prob. in 20 sessions 23.0 %
10:1 move that closes out 5.00 % prob. in 20 sessions 4.3 %
5:1 move that closes out 10.00 % prob. in 20 sessions 0.4 %
2:1 move that closes out 25.00 % prob. in 20 sessions 0.0 %The simplification is honest in one sense: with the minimum margin and the whole balance committed, margin and balance coincide, and the close-out comes with the loss of half of the balance. With less leverage, the provider would not close out under the 50% rule (the balance is more than enough), but losing 50% of the balance is still the threshold that matters to the client.
The 50% close-out: per account, not per position
Article 3.e defines the protection as the liquidation of one or more CFDs “when the sum of funds in the CFD trading account and the unrealized net profits of all open CFDs connected to that account falls to less than half of the total initial margin provided for all those open CFDs” (unofficial translation of the CNMV resolution). It is a rule per account. ESMA explains in its decision that the public consultation proposed a rule per position and that it changed it: a rule per account allows the gains of one position to offset the losses of another, and a provider that closes out per position also complies, because it is stricter.
The difference matters as soon as there are two positions that hedge each other. A long-short pair: a long CFD on RVE (major index, 5%) and a short one on RVH (10%), with the same notional, and the account holding exactly the margin of both. The two series have a daily correlation of 0.73:
p = ind.pivot(index="fecha", columns="indice", values="contado")
par = p[["RVE", "RVH"]].to_numpy()
def ventana(i, regla, h=20):
nominal, signo = 1.0, np.array([1, -1]) # long RVE, short RVH
garantia = nominal * np.array([0.05, 0.10])
fondos = garantia.sum()
abierta = np.array([True, True])
cerrada_pnl = np.zeros(2)
cerro = False
for t in range(1, h + 1):
vivo = signo * nominal * (par[i + t] / par[i] - 1)
pnl = np.where(abierta, vivo, cerrada_pnl)
if regla == "position":
corta = abierta & (pnl < -0.5 * garantia)
cerrada_pnl[corta], abierta[corta] = pnl[corta], False
cerro |= corta.any()
if abierta.any() and (fondos + pnl.sum()
< 0.5 * garantia[abierta].sum()):
cerrada_pnl[abierta], abierta[:] = pnl[abierta], False
cerro = True
return cerro, pnl.sum() / fondos
for regla in ("account", "position"):
r = [ventana(i, regla) for i in range(len(par) - 20)]
cerradas = np.mean([c for c, _ in r])
final = np.array([x for _, x in r])
print(f"{regla:9} close-outs {100 * cerradas:5.1f} % mean "
f"result {100 * final.mean():5.1f} % 5th percentile "
f"{100 * np.percentile(final, 5):6.1f} %")account close-outs 6.6 % mean result 0.9 % 5th percentile -51.2 %
position close-outs 71.8 % mean result 2.0 % 5th percentile -58.7 %With the close-out per position, one leg is liquidated in most windows: the 5% leg withstands a 2.5% adverse move before being closed, and in a hedged pair each leg moves much more than the whole. The worst part is not the frequency, it is what is left: one leg open without its hedge, an exposure the client had not chosen. That is the argument ESMA takes from the public consultation. The rule per account looks at what the client can lose, the net, and barely acts. In an account with a single position, as ESMA says, the two rules are the same.
The CNMV adds a good practice in the preamble of the 2019 resolution: warn the client before the 50%, so they can post more margin or close on their own. And the 2023 resolution specifies that the close-out “must not take place before that threshold is reached and the client has been informed” (unofficial translation).
Mermaid source
stateDiagram-v2 [*] --> Normal Normal --> Warning: funds below threshold Warning --> Normal: adds funds or closes Warning --> CloseOut: below 50% CloseOut --> Normal: balance left CloseOut --> Protected: negative balance Protected --> [*]
Negative balance protection
The 50% close-out leaves the other half of the margin as a cushion to execute the close-out. That cushion is useless if the price gaps between two observations: a weekend, a central bank decision, a gap at the open. The currency data contain one like that. On Friday, October 2, 2015 QEVUSD closed at 1.58226 and on Monday the 5th, at 1.45688:
q = series["QEVUSD"][0]
salto = q.pct_change().abs().idxmax()
antes, despues = q.shift(1)[salto], q[salto]
mov = despues / antes - 1
fondos = 10_000 # EUR in the CFD account
nominal = fondos / 0.0333 # the whole balance as margin
saldo = fondos + nominal * mov # long CFD
print(f"{salto.date()}: {antes:.5f} -> {despues:.5f} "
f"({100 * mov:.2f} %)")
print(f"notional {nominal:,.0f}; balance after the gap {saldo:,.0f} EUR")
print(f"client's loss with protection: {fondos:,.0f} EUR; "
f"borne by the provider: {-min(saldo, 0):,.0f} EUR")2015-10-05: 1.58226 -> 1.45688 (-7.92 %)
notional 300,300; balance after the gap -13,796 EUR
client's loss with protection: 10,000 EUR; borne by the provider: 13,796 EURFor simplicity the account is in euros and the notional is expressed in euros. A 7.9% fall at 30:1 leverage is a loss of 238% of the margin: by the time the provider can close out, there is no balance left. Negative balance protection (Article 3.f) limits the client's liability, for all the CFDs in that account, to the funds deposited in it. How often this happens in the experiment of the previous section can be counted: the first close-out signal arrives with the loss already above 100% of the margin.
def saldo_negativo(precios, garantia, h=20):
v = sliding_window_view(np.asarray(precios, float), h + 1)
r = v[:, 1:] / v[:, :1] - 1
out = 0
for x in (r, -r): # long and short
toca = x <= -0.5 * garantia
hay = toca.any(axis=1)
primero = toca.argmax(axis=1)
perdida = -x[np.arange(len(x)), primero] / garantia
out += int((hay & (perdida > 1)).sum())
return out
pd.Series({k: saldo_negativo(s, g) for k, (s, g) in series.items()})QEVUSD 88
USDQMP 4
RVE 167
MEA 116
RVH 16
ENA 232
XBQ 0
dtype: int64These are windows (long and short) whose first close-out signal arrives with the loss already above the margin: 232 in crude oil, 167 in the major index, 88 in the major pair and none in the cryptocurrency, whose 50% margin leaves a cushion of a 25% move. Gaps are concentrated on a few dates and affect every window that spans them, which is why the counts are large in some series and small in others. With intraday data and continuous monitoring there would be fewer cases, not none: the gap between two prices exists at any frequency.
The risk warning and its percentage
Every communication from a CFD provider to retail clients carries a warning in a fixed format (Annex II). On a website or a durable medium (unofficial translation of the Spanish text):
CFDs are complex instruments and come with a high risk of losing money rapidly due to leverage. [provider's percentage] % of retail investor accounts lose money when trading CFDs with this provider. You should consider whether you understand how CFDs work and whether you can afford to take the high risk of losing your money.
The percentage is not free. Section A.6 defines it: every three months, over the previous 12 months, the proportion of retail CFD accounts whose net realized and unrealized result on CFDs was negative, with all costs (charges, fees, commissions) and without the accounts that had no open CFD, without the result of other products and without deposits or withdrawals. A provider with no open CFDs in the period uses the standard warning: “Between 74% and 89% of retail investors lose money when trading CFDs” (unofficial translation), the range from the supervisors' studies that the resolution itself cites.
A validator on 5,000 synthetic accounts, compared with two tempting and wrong calculations:
rng = np.random.default_rng(2019)
n = 5_000
cuentas = pd.DataFrame({
"con_cfd_abierto": rng.random(n) < 0.85,
"realizado": rng.normal(-150, 900, n).round(2),
"no_realizado": rng.normal(0, 200, n).round(2),
"costes": rng.gamma(2.0, 180, n).round(2),
"otros_productos": rng.normal(300, 1500, n).round(2),
"ingresos": rng.gamma(1.5, 2000, n).round(2),
"retiradas": rng.gamma(1.2, 900, n).round(2),
})
cuentas.loc[~cuentas["con_cfd_abierto"],
["realizado", "no_realizado", "costes"]] = 0.0
def pct_pierden(c):
"""Annex II, section A.6 of the 2019 Resolution."""
c = c[c["con_cfd_abierto"]]
neto = c["realizado"] + c["no_realizado"] - c["costes"]
return 100 * (neto < 0).mean()
c = cuentas
sin_costes = c[c["con_cfd_abierto"]]
mal_1 = 100 * ((sin_costes["realizado"] + sin_costes["no_realizado"])
< 0).mean()
saldo = (c["realizado"] + c["no_realizado"] - c["costes"]
+ c["otros_productos"] + c["ingresos"] - c["retiradas"])
mal_2 = 100 * (saldo < 0).mean()
print(f"Annex II A.6: {pct_pierden(c):5.1f} %")
print(f"without costs: {mal_1:5.1f} %")
print(f"change in balance, all accounts: {mal_2:5.1f} %")Annex II A.6: 70.3 %
without costs: 56.0 %
change in balance, all accounts: 29.7 %Both errors lower the figure. Forgetting costs flips the sign of accounts that make a small profit before commissions and financing. Using the change in balance of all accounts mixes in deposits, other products and accounts without CFDs, and turns into “winners” accounts that only received a transfer. The annex's method exists so that the figure is comparable across providers.
What the CNMV added in 2023 and what none of this covers
The CNMV Resolution of July 11, 2023, applicable since August 3, 2023, does two things. For CFDs it bans marketing communications aimed at retail clients in Spain, including those that redirect to a provider's website or form and public offers of free or token-price courses, seminars or demo accounts; sponsorship and brand advertising with that effect; and practices such as paying clients for bringing in clients, rewarding the sales network for client acquisitions or client losses, call centers that promote these products and deposits by credit card. And for other leveraged instruments (those whose maximum risk is not known at subscription or can exceed the initial outlay, such as futures or written options) it requires an initial margin and the 50% close-out for retail clients. The margin is the lower of two amounts: the one in the 2019 Annex I according to the underlying, or the one required by the trading venue; if the underlying is a crypto-asset that is not a MiFID financial instrument, the annex amount with no reduction.
esp = pd.read_csv("futuros2_especificaciones.csv")
ultimo = fut[fut["fecha"] == fut["fecha"].max()].set_index("mercado")
esp = esp.set_index("mercado").loc[["IDA", "MEA", "ENA", "DIB", "BOC"]]
esp["nominal"] = ultimo["cierre"] * esp["multiplicador"]
esp["centro_pct"] = 100 * esp["margen_inicial"] / esp["nominal"]
# assumptions: IDA as a major index; DIB, a non-major currency;
# a bond future is an "other underlying"
esp["anexo_pct"] = [5.0, 5.0, 10.0, 5.0, 20.0]
esp["exigible_pct"] = esp[["centro_pct", "anexo_pct"]].min(axis=1)
esp[["nombre", "nominal", "centro_pct", "anexo_pct",
"exigible_pct"]].round(2) nombre nominal centro_pct anexo_pct exigible_pct
mercado
IDA Índice Aldebarán 500 389500.0 7.01 5.0 5.00
MEA Oro 41300.0 5.81 5.0 5.00
ENA Crudo ligero 42670.0 12.89 10.0 10.00
DIB Divisa Kestra/USD 60390.0 3.31 5.0 3.31
BOC Bono a 10 años 95937.5 3.86 20.0 3.86In three of the five level 2 futures (index, gold and crude oil) the annex figure is lower than the market margin and
is the one required; in the currency and the bond the market margin applies, lower than the annex's 5% and 20%. The
columns are centro_pct (trading venue margin), anexo_pct (Annex I) and exigible_pct (the one required). The
resolution sets the minimum the provider must ask of the retail client. Its clearest practical effect is the 50%
close-out, which a market's margin does not impose on the end client.
What none of these measures covers: professional clients; retail clients who trade with unauthorized firms (lesson 4.4.1); and market risk itself. They limit how much can be lost through leverage, not whether the strategy makes money.
Exercises
- Repeat the experiment at the top with windows of 5 and 60 sessions. How does the ranking of the underlyings change? What does it tell you about the “appropriate holding period” ESMA used?
Solution
tabla = pd.DataFrame({
h: {k: 100 * prob_cierre(s, g, h=h)
for k, (s, g) in series.items()}
for h in (5, 20, 60)
}).round(1)
tabla.columns = [f"{h} sessions" for h in tabla.columns]
tabla.sort_values("20 sessions", ascending=False) 5 sessions 20 sessions 60 sessions
RVE 22.3 52.7 70.0
ENA 21.0 51.6 70.7
MEA 18.7 49.8 69.3
QEVUSD 10.8 39.8 62.5
USDQMP 8.1 36.7 59.8
RVH 6.1 30.0 54.9
XBQ 0.3 7.4 36.2All probabilities rise with the horizon, because a longer path has more chances to touch the threshold, but not in the same proportion: those already closed out often in 5 sessions (RVE, ENA, MEA, around 20%) approach a ceiling of 70% at 60 sessions, and the cryptocurrency goes from almost never (0.3%) to just over a third (36.2%). The ranking barely changes, but the distances do. That is why a calibration “consistent across underlyings” depends on the chosen horizon, and a margin that looks ample for a week is not for a quarter.
- Modify
ventanaso that the account holds twice the funds of the required margin. How many close-outs are there now under each rule?
Solution
def ventana_holgada(i, regla, h=20, colchon=2.0):
nominal, signo = 1.0, np.array([1, -1])
garantia = nominal * np.array([0.05, 0.10])
fondos = colchon * garantia.sum()
abierta = np.array([True, True])
cerrada_pnl, cerro = np.zeros(2), False
for t in range(1, h + 1):
vivo = signo * nominal * (par[i + t] / par[i] - 1)
pnl = np.where(abierta, vivo, cerrada_pnl)
if regla == "position":
corta = abierta & (pnl < -0.5 * garantia)
cerrada_pnl[corta], abierta[corta] = pnl[corta], False
cerro |= corta.any()
if abierta.any() and (fondos + pnl.sum()
< 0.5 * garantia[abierta].sum()):
cerrada_pnl[abierta], abierta[:] = pnl[abierta], False
cerro = True
return cerro
for regla in ("account", "position"):
c = np.mean([ventana_holgada(i, regla)
for i in range(len(par) - 20)])
print(f"{regla:9} close-outs {100 * c:5.1f} %")account close-outs 0.0 %
position close-outs 71.8 %With twice the funds, the close-out per account disappears (0.0%): the account has to lose one and a half times the margin before reaching the threshold. The close-out per position does not change at all, because it looks at each position against its own margin and does not see the account's funds. Adding more balance protects against the close-out only if the rule is per account, which is the minimum the rule requires; it is worth knowing which one your provider applies.
- A provider advertises on a social network: “Trade the IBEX with 20:1 leverage and get a 100 EUR bonus”. Point out which parts of the 2019 and 2023 resolutions that ad breaches if it is aimed at retail clients in Spain.
Solution
Three. The IBEX 35 is not on the list of 5% indices: its minimum margin is 10%, 10:1 leverage (Annex I), so 20:1 breaches Article 4.a. The bonus is a monetary benefit tied to trading CFDs, banned by Article 4.d. And since the 2023 resolution any CFD marketing communication aimed at retail clients in Spain is banned, including those on social networks; even if it were not, the ad would need the Annex II risk warning with the provider's percentage.
Each answer is folded under its question
Self-assessment
A retail client resident in Spain has 10,000 EUR in their CFD account and opens a CFD on the IBEX 35. What is the maximum notional?
- A200,000 EUR: indices have 20:1 leverage
- B100,000 EUR: the IBEX 35 is not on the list of major indices, so the margin is 10% (10:1)
- C300,000 EUR: 30:1
- D50,000 EUR: 5:1, like stocks
Show answer
Answer B. 100,000 EUR: the IBEX 35 is not on the list of major indices, so the margin is 10% (10:1)
Annex I gives 5% only to ten named indices (FTSE 100, CAC 40, DAX30, DJIA, S&P 500, NASDAQ, NASDAQ 100, Nikkei 225, ASX 200 and EURO STOXX 50). All other equity indices go to 10%.
An account holds a long CFD on one index and a short one on another, correlated index. When must the provider close positions under the CNMV resolution?
- AWhen the sum of the account's funds and the unrealized net profits of all its CFDs falls below half of the total initial margin
- BWhen either of the two loses half of its margin
- CAt the end of every session, if there are losses
- DNever: the client decides
Show answer
Answer A. When the sum of the account's funds and the unrealized net profits of all its CFDs falls below half of the total initial margin
The close-out protection is measured per account. ESMA explains in its decision that a close-out per position also complies (it is stricter), but the required minimum is per account. In the lesson, with the long-short pair, the per-position close-out triggers in 72% of the 20-session windows and the per-account one in 7%.
The example account has 10,000 EUR and a long CFD of about 300,000 EUR notional on the major pair (the whole balance as margin) when the price falls 7.9% between two closes. What does negative balance protection cover?
- ANothing: the client owes the provider the difference
- BIt returns half of the loss to the client
- CIt only applies if the client requests it in writing
- DIt limits the client's loss to the funds in their CFD account: the balance is left at zero and the provider bears the rest
Show answer
Answer D. It limits the client's loss to the funds in their CFD account: the balance is left at zero and the provider bears the rest
Negative balance protection limits the retail client's aggregate liability for all CFDs in the account to the funds in that account (Article 3.f). In the lesson, the gap leaves the account at −13,796 EUR; with the protection, the client loses 10,000 and the provider bears the rest.
To compute the risk warning's percentage of losing accounts, which accounts and which amounts are used?
- AAll open accounts, with the change in balance, including deposits and withdrawals
- BOnly the accounts closed during the year
- CAccounts with at least one CFD open in the 12 months, with the net realized and unrealized result of their CFDs, costs included and without deposits, withdrawals or other products; it is recalculated every three months
- DA fixed figure of 74% to 89%
Show answer
Answer C. Accounts with at least one CFD open in the 12 months, with the net realized and unrealized result of their CFDs, costs included and without deposits, withdrawals or other products; it is recalculated every three months
It is the method of section A.6 of Annex II. The 74% to 89% range is the standard warning, for a provider that has had no open CFDs in the last calculation period.
What did the CNMV resolution of July 11, 2023 add?
- AIt banned CFD advertising aimed at retail clients in Spain and extended the initial margin and the 50% close-out to other leveraged instruments, such as futures and options
- BIt raised the maximum leverage of currency CFDs
- CIt removed negative balance protection
- DIt repealed the 2019 resolution
Show answer
Answer A. It banned CFD advertising aimed at retail clients in Spain and extended the initial margin and the 50% close-out to other leveraged instruments, such as futures and options
The first part bans marketing communications, sponsorship and practices such as paying to acquire clients or accepting deposits by credit card; the second applies the minimum margin and the 50% close-out to other instruments whose maximum risk is not known or can exceed the initial outlay.
Key points
- ESMA restricted CFDs for retail clients with Decision (EU) 2018/796 (from August 1, 2018, renewed three times); in Spain the CNMV Resolution of June 27, 2019 has applied the same rules since August 1, 2019, with no end date.
- Minimum initial margin: 3.33% on pairs of two major currencies; 5% on ten major indices, gold and other pairs; 10% on other commodities and indices; 20% on stocks and everything else; 50% on cryptocurrencies.
- The 50% close-out is measured per account: funds plus unrealized net profits against half of the total initial margin. At maximum leverage with the whole balance committed, in the course data it triggers in 7% (cryptocurrency) to 53% (major index) of the 20-session windows.
- Negative balance protection limits the loss to the funds in the CFD account; a gap between two closes can take the balance below zero before the close-out acts.
- The warning carries the percentage of the provider's retail accounts that lose money, calculated every three months over 12 months with costs and without deposits or withdrawals; since 2023 the CNMV also bans CFD advertising to retail clients.
Resources
Research
Documentation
- CNMV Resolution of June 27, 2019 on binary options and CFDs (BOE-A-2019-9737), in the BOE (Spain's official gazette)
- CNMV Resolution of July 11, 2023 on CFDs and other leveraged products (BOE-A-2023-16394), in the BOE
- ESMA Decision (EU) 2018/796 temporarily restricting CFDs for retail clients, in the BOE (in Spanish)
- Regulation (EU) 600/2014 (MiFIR), Articles 40 to 42: product intervention, in the BOE (in Spanish)