Lesson 7.4.3 · 55 min

PRIIPs, the KID and US ETFs

A European retail investor can buy Apple shares at their broker but not the US ETF that tracks the S&P 500. The reason is a three-page document. This lesson reads that document with code, checks its figures, computes its risk indicator and compares the cost of the alternatives with the assumptions in plain sight.

Fig. — 20-year cost of investing EUR 10,000 against the index without costs, under the lesson's assumptions (fees, currency and 15 % withholding on dividends)
Level 7 lessons
  1. 7.1 · Software engineering for trading

    1. 7.1.1 Project structure, configuration and quality: from notebook to repository
    2. 7.1.2 Performance: measure, profile and compile only what is needed
    3. 7.1.3 Patterns: events, message queues and hexagonal architecture
  2. 7.2 · Infrastructure and deployment

    1. 7.2.1 Docker and docker-compose: reproducible images with uv
    2. 7.2.2 VPS, cloud and latency; CI/CD with GitHub Actions
    3. 7.2.3 Orchestration and monitoring: task graphs, structured logs, metrics, alerts and heartbeats
    4. 7.2.4 Security and continuity: 2FA, IP allowlists, backups and failure procedures
  3. 7.3 · MLOps for trading models

    1. 7.3.1 Tracking experiments, models and data: MLflow, DVC and a run reproduced end to end
    2. 7.3.2 Scheduled retraining, automatic validation and champion/challenger
    3. 7.3.3 Live model monitoring and automatic shutdown
    4. 7.3.4 Model serving: ONNX, CPU or GPU inference and the cost of LLMs in production
  4. 7.4 · Regulation, ethics and taxation

    1. 7.4.1 MiFID II: clients, suitability and algorithmic trading
    2. 7.4.2 ESMA and CFDs: leverage, close-out and negative balance
    3. 7.4.3 PRIIPs, the KID and US ETFs
    4. 7.4.4 MiCA after the transitional period: checking a provider in the registers
    5. 7.4.5 Market abuse: spoofing, layering and the bot that imitates them by accident
    6. 7.4.6 Trading taxes in Spain
    7. 7.4.7 Ethics: personal data, artificial intelligence and selling signals
  5. 7.5 · Quant career

    1. 7.5.1 Quant roles: six jobs around the same system
    2. 7.5.2 Where to work: what each firm does and what the registers say
    3. 7.5.3 Public portfolio and interviews: show judgment, not returns
    4. 7.5.4 Certifications, training and prop firms: what each one certifies and what a challenge measures
  6. 7.6 · Final capstone

    1. 7.6.1 Capstone: common requirements, the panel's rubric and preparing the defense
    2. 7.6.2 Capstone C1: a multi-asset futures system, from forecast to paper account
    3. 7.6.3 Capstone C2: systematic options book, volatility surface and real-time Greeks
    4. 7.6.4 Capstone C3: stock and ETF portfolio with ML, HRP and Spanish taxation
    5. 7.6.5 Capstone C4: a research platform with LLMs and alternative data
    6. 7.6.6 Capstone C5: crypto market making or arbitrage with counterparty control

What a PRIIP is and why a share is not one

Lesson 1.2.2 explained the practical rule: a US-domiciled ETF does not usually have a key information document (KID), and without one a European broker cannot sell it to a retail client. This lesson goes to the definition, the document and the figures. The framework is the EU one, as it applies to an investor in Spain.

Regulation (EU) 1286/2014 applies to packaged retail investment products (PRIPs) and to insurance-based investment products; together they are the PRIIPs. Article 4(1) defines the first as an investment “where, regardless of the legal form of the investment, the amount repayable to the retail investor is subject to fluctuations because of exposure to reference values or to the performance of one or more assets which are not directly purchased by the retail investor”. Three cases:

ProductPRIIP?Why
Share in a US companyNoThe investor buys the asset directly
US ETF on the S&P 500YesRepayment depends on shares the fund buys, not the investor
Listed option on that ETFYesIts value depends on a reference asset

Article 5 requires the manufacturer (the fund manager, the issuer) to draw up the KID and publish it before making the product available to retail investors; Article 13 requires whoever sells or advises on it to provide it in good time before the retail investor is bound. A US manager that does not market its fund in the EU has no obligation to produce a KID, and the broker cannot produce it on its behalf. The result is the block the investor sees on the order screen. UCITS funds were exempt (Article 32) until December 31, 2022, the date to which Regulation (EU) 2021/2259 extended the exemption; since 2023 they also use the PRIIPs KID.

noyesUCITS ETFoptionsnoneIndex exposureRetail?US ETFProduct with KID?UCITS, other currencyRisk 7, type KIDIndividual stocks
Mermaid source
flowchart TB
  Q[Index exposure] --> M{Retail?}
  M -- no --> E[US ETF]
  M -- yes --> K{Product with KID?}
  K -- UCITS ETF --> U[UCITS, other currency]
  K -- options --> O[Risk 7, type KID]
  K -- none --> A[Individual stocks]

Inside the KID: fixed sections

Article 8 of the regulation sets the title (“Key Information Document”), an explanatory statement that begins “This document provides you with key information about this investment product. It is not marketing material.” and the sections, in this order: product and manufacturer; “What is this product?”; “What are the risks and what could I get in return?”, with a summary risk indicator and performance scenarios; “What happens if [the name of the PRIIP manufacturer] is unable to pay out?”; “What are the costs?”; “How long should I hold it and can I take money out early?”; “How can I complain?” and “Other relevant information”. At most three sides of A4 paper (Article 6(4)).

Delegated Regulation (EU) 2017/653 sets out the method for risk, scenarios and costs. The Commission amended it in 2021 regarding the methodology and presentation of the scenarios, the presentation of costs and past performance (recital 4 of Regulation 2021/2259 says so). The format seen today, and that of the course's synthetic KIDs, is the amended one.

The fixed format is what makes it possible to read with code. The level 6 data include the KIDs of five UCITS ETFs from a fictitious manager, the same ones lesson 6.3.2 splits into chunks for a RAG. They are written in Spanish, like the rest of the course corpus: the title is “Documento de datos fundamentales” and the sections carry the Spanish headings of the regulation (“¿Qué es este producto?”, “¿Cuáles son los costes?”…).

IN [01]python
import re

import numpy as np
import pandas as pd

docs = pd.read_parquet("rag6_documentos.parquet")
kids = docs[docs["tipo"] == "kid"].set_index("id_doc")
print(kids[["entidad", "fecha"]].to_string())
print(kids.loc["R10", "texto"][:300])
OUT [01]The five level 6 KIDs
                                            entidad       fecha
id_doc
R10       Sintético Renta Variable Global UCITS ETF  2025-03-01
R12     Sintético Bonos Gobierno Euro 3-7 UCITS ETF  2025-03-01
R14         Sintético Mercados Emergentes UCITS ETF  2025-03-01
R16            Sintético Dividendo Europa UCITS ETF  2025-03-01
R18          Sintético Tecnología EE. UU. UCITS ETF  2025-03-01
# Documento de datos fundamentales — Sintético Renta Variable Global UCITS ETF

*Documento sintético para un curso de formación: empresa, cifras y personas inventadas.*

## Finalidad

Este documento le proporciona información fundamental sobre este producto de inversión. No se trata de material come

Reading and validating a KID with code

An extractor by sections and tables. The tables are Markdown, so splitting on | is enough; the numbers come in the Spanish format, with a period for thousands and a decimal comma. The patterns the extractor looks for are the Spanish texts of the documents: “riesgo: 4 en una escala de 1 a 7” (risk: 4 on a scale of 1 to 7), the scenario table (“Escenario”), the cost breakdown (“Composición”) and the total costs table (“Inversión de 10 000 EUR”):

IN [02]python
def numero(txt):
    t = txt.replace("EUR", "").replace("%", "").replace(".", "")
    return float(t.replace(",", ".").strip())

def tabla(texto, cabecera):
    bloque = texto.split(cabecera, 1)[1].split("\n\n", 1)[0]
    filas = [f.strip().strip("|").split("|")
             for f in bloque.strip().splitlines()[2:]]
    return [[c.strip() for c in f] for f in filas]

def leer_kid(texto):
    k = {"isin": re.search(r"ISIN (\w{12})", texto).group(1)}
    m = re.search(r"riesgo: (\d) en una escala de 1 a 7\. Periodo de "
                  r"mantenimiento recomendado: (\d+) años", texto)
    k["sri"], k["rhp"] = int(m.group(1)), int(m.group(2))
    for f in tabla(texto, "| Escenario"):
        k[f"esc_{f[0].lower()}_1a"] = numero(f[1])
        k[f"esc_{f[0].lower()}_rhp"] = numero(f[3])
        k[f"rent_{f[0].lower()}_rhp"] = numero(f[4])
    comp = dict((f[0], f[1]) for f in tabla(texto, "| Composición"))
    k["gestion"] = numero(comp["Comisiones de gestión y otros "
                               "costes administrativos"])
    k["operacion"] = numero(comp["Costes de operación"])
    k["entrada_salida"] = (numero(comp["Costes de entrada"])
                           + numero(comp["Costes de salida"]))
    tot = dict((f[0], f[1:]) for f in tabla(texto, "| Inversión de"))
    k["coste_1a"] = numero(tot["Costes totales"][0])
    k["coste_rhp"] = numero(tot["Costes totales"][1])
    k["incidencia"] = numero(tot["Incidencia anual de los costes"][0])
    return k

kid = pd.DataFrame({i: leer_kid(t) for i, t in kids["texto"].items()}).T
kid[["isin", "sri", "rhp", "gestion", "operacion", "incidencia",
     "coste_1a", "coste_rhp"]]
OUT [02]KID extractor
             isin sri rhp gestion operacion incidencia coste_1a coste_rhp
R10  ZZ3353919667   4   5     0.2      0.06       0.26     26.0     139.0
R12  ZZ6549778970   2   5    0.12      0.05       0.17     17.0      89.0
R14  ZZ2516219569   5   5    0.35       0.1       0.45     45.0     239.0
R16  ZZ8471203886   4   5     0.3      0.02       0.32     32.0     170.0
R18  ZZ6812181936   5   5    0.25      0.07       0.32     32.0     168.0

The columns are the summary risk indicator (sri), the recommended holding period in years (rhp), the management and transaction costs (gestion, operacion), the annual cost impact in % (incidencia) and the total costs in euros at 1 year and at the end of the holding period (coste_1a, coste_rhp).

Extracting is not enough: a KID can be badly made, badly translated or out of date, and a system fed by them (a comparison tool, a RAG like the one in lesson 6.3.3) inherits their errors. The checks that can be done without outside information:

  • ISIN. Twelve characters: two country letters, nine alphanumerics and a check digit computed with the Luhn algorithm on the digits, after converting each letter into a number (A = 10 … Z = 35).
  • Scenarios. The average annual return has to match the 5-year amount; and the order has to be stress < unfavorable < moderate < favorable.
  • Costs. The breakdown has to add up to the annual impact, and the total costs of the first year have to be the impact on 10,000 EUR: the prescribed text of the cost presentation assumes that in the first year the investor gets back what they invested (0%) and, for the other periods, the moderate scenario (Q&A of the Joint Committee of the European Supervisory Authorities on the KID).
IN [03]python
def isin_valido(isin):
    digitos = "".join(str(int(c, 36)) for c in isin[:-1])
    suma = 0
    for i, d in enumerate(reversed(digitos)):
        n = int(d) * (2 if i % 2 == 0 else 1)
        suma += n // 10 + n % 10
    return (10 - suma % 10) % 10 == int(isin[-1])

def validar(k, tol=0.15):
    avisos = []
    if not isin_valido(k["isin"]):
        avisos.append("ISIN: check digit")
    esc = ["tensión", "desfavorable", "moderado", "favorable"]
    finales = [k[f"esc_{e}_rhp"] for e in esc]
    if finales != sorted(finales):
        avisos.append("scenarios out of order")
    for e in esc:
        final = k[f"esc_{e}_rhp"] / 10_000
        anual = 100 * (final ** (1 / k["rhp"]) - 1)
        if abs(anual - k[f"rent_{e}_rhp"]) > tol:
            avisos.append(f"return {e}: {anual:.2f} %")
    suma = k["gestion"] + k["operacion"] + k["entrada_salida"]
    if abs(suma - k["incidencia"]) > 0.005:
        avisos.append("breakdown does not add up to the annual impact")
    if abs(k["coste_1a"] - 100 * k["incidencia"]) > 1:
        avisos.append("first-year cost is not the annual impact")
    r = 1 + k["rent_moderado_rhp"] / 100
    esperado = 100 * k["incidencia"] * sum(r ** t
                                           for t in range(k["rhp"]))
    desvio = k["coste_rhp"] / esperado - 1
    if abs(desvio) > 0.03:
        avisos.append(f"cost at {k['rhp']} years {100 * desvio:+.1f} % "
                      f"vs. the moderate scenario")
    return avisos or ["no warnings"]

for i, k in kid.iterrows():
    print(i, k["isin"], "|", "; ".join(validar(k)))
OUT [03]KID validator
R10 ZZ3353919667 | no warnings
R12 ZZ6549778970 | no warnings
R14 ZZ2516219569 | cost at 5 years -3.3 % vs. the moderate scenario
R16 ZZ8471203886 | cost at 5 years -3.5 % vs. the moderate scenario
R18 ZZ6812181936 | cost at 5 years -4.4 % vs. the moderate scenario

The scenario names (tensión, desfavorable, moderado, favorable: stress, unfavorable, moderate, favorable) are the keys that come out of the Spanish table. All five ISINs have the correct check digit; the ZZ prefix, on the other hand, does not correspond to any country: it is the mark the course data use so that nobody confuses these funds with real ones, and a production validator would check it against the list of country codes. Scenarios and cost breakdown add up. The warning is about the 5-year costs: in all five documents they are 5.3 times those of the first year, whereas with the growth of the moderate scenario of the equity funds (4.7% or 4.8% a year) the sum of five years of impact on a growing balance gives 5.5. In the three of R14, R16 and R18 the deviation exceeds 3%; that of R10 stays just below, and in the bond fund (R12), with a moderate scenario of 1.9%, the factor of 5.3 almost matches what is expected. The check is approximate (the regulation details how costs accumulate within each year), but a fixed factor for products with different returns is a question for the manager.

There is a second check that only shows when comparing documents with each other:

IN [04]python
cols = [c for c in kid.columns if c.startswith("esc_")]
firma = kid[cols].astype(float).round(0).apply(tuple, axis=1)
for _, grupo in kid.groupby(firma):
    if len(grupo) > 1:
        print("same scenarios:", ", ".join(
            kids.loc[grupo.index, "entidad"]))
OUT [04]Identical scenarios in different funds
same scenarios: Sintético Mercados Emergentes UCITS ETF, Sintético Tecnología EE. UU. UCITS ETF
same scenarios: Sintético Renta Variable Global UCITS ETF, Sintético Dividendo Europa UCITS ETF

A global equity fund and a European dividend fund with the same scenarios down to the euro is not impossible, but it is very unlikely if each is computed with its own history. In these synthetic data the scenarios depend only on the risk indicator; in a real KID, the same coincidence would be a sign of a copied template and a reason not to take the figures as that fund's own.

The summary risk indicator, from volatility

Annex II of Delegated Regulation 2017/653 measures market risk with the VaR-equivalent volatility (VEV): the annualized volatility that corresponds to the value at risk at 97.5% over the recommended holding period. For category 2 PRIIPs (unleveraged exposure, or with a constant multiple, to assets with a sufficient price history, such as an ETF), the VaR is computed with the moments of the distribution of returns over the last five years: volatility, skewness and excess kurtosis (a Cornish-Fisher expansion). The VEV is converted into a class with a table:

Market risk class1234567
VEV< 0.5%0.5-5%5-12%12-20%20-30%30-80%> 80%

If returns were normal, the VEV would be the annualized volatility; with fat tails or negative skewness it is higher. The cell's approximation uses only the volatility of the last five years and therefore underestimates the risk of series with tails: it is useful to understand the table, not to compute a KID. The series come from the course data:

IN [05]python
etf = pd.read_csv("etf_indice_diario.csv", parse_dates=["fecha"])
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")
cri = pd.read_parquet("cripto3_diario.parquet")

def s(df, filtro, col):
    return df[filtro].set_index("fecha")[col].sort_index()

series = {
    "BOA (future, 2-year bond)": s(fut, fut["mercado"] == "BOA",
                                   "cierre_ajustado"),
    "BOB (future, 5-year bond)": s(fut, fut["mercado"] == "BOB",
                                   "cierre_ajustado"),
    "QEVUSD (currency)": s(fx, fx["par"] == "QEVUSD", "spot"),
    "Level 1 ETF (NAV)": etf.set_index("fecha")["etf_vl"],
    "RVH (index)": s(ind, ind["indice"] == "RVH", "contado"),
    "Level 1 2x ETF": etf.set_index("fecha")["etf_2x_precio"],
    "XBQ (crypto)": s(cri, (cri["exchange"] == "boreal")
                      & (cri["activo"] == "XBQ"), "cierre_spot"),
}
LIMITES = [0.5, 5, 12, 20, 30, 80]

def clase_mrm(vev_pct):
    return 1 + sum(vev_pct >= x for x in LIMITES)

filas = []
for nombre, p in series.items():
    p = p[p.index > p.index.max() - pd.DateOffset(years=5)]
    r = np.log(p).diff().dropna()
    anual = 365 if "crypto" in nombre else 252
    vol = 100 * r.std() * np.sqrt(anual)
    filas.append((nombre, round(vol, 2), clase_mrm(vol),
                  round(r.skew(), 2), round(r.kurt(), 1)))
mrm = pd.DataFrame(filas, columns=["serie", "vol_pct", "clase",
                                   "asimetria", "exceso_curtosis"])
mrm
OUT [05]Approximate market risk class
                       serie  vol_pct  clase  asimetria  exceso_curtosis
0  BOA (future, 2-year bond)     1.90      2      -0.35              1.5
1  BOB (future, 5-year bond)     4.82      2      -0.31              1.3
2          QEVUSD (currency)     8.22      3      -0.19              0.8
3          Level 1 ETF (NAV)    20.51      5       0.28              7.0
4                RVH (index)    21.52      5      -0.03              0.8
5             Level 1 2x ETF    40.98      6       0.11              7.0
6               XBQ (crypto)    57.86      6      -0.12              2.3
Fig. — Five-year annualised volatility of seven course series on the market risk classes of Delegated Regulation 2017/653 (normal approximation)

Two lessons come out of the table (clase is the class; asimetria, the skewness; exceso_curtosis, the excess kurtosis). The first: the level 1 ETF sits half a point from the boundary between 4 and 5. A small change in the five-year volatility moves the number the investor sees, which is why the regulation requires the manufacturer to monitor the data behind the indicator. The second: the series with high excess kurtosis, such as the level 1 ETF and its 2x version (7.0), would have a VEV above their volatility with the full calculation; for nearly normal series, such as the RVH index or the currency, the approximation comes closer.

The summary indicator combines the market class with a credit risk class (of the issuer or of whoever has to pay). The table in Part 3 of Annex II, as is:

IN [06]python
IRR = {  # rows: credit class 1-6; columns: market class 1-7
    1: [1, 2, 3, 4, 5, 6, 7],
    2: [1, 2, 3, 4, 5, 6, 7],
    3: [3, 3, 3, 4, 5, 6, 7],
    4: [5, 5, 5, 5, 5, 6, 7],
    5: [5, 5, 5, 5, 5, 6, 7],
    6: [6, 6, 6, 6, 6, 6, 7],
}

def indicador(clase_mercado, clase_credito):
    return IRR[clase_credito][clase_mercado - 1]

for m, c in [(2, 1), (2, 4), (5, 3), (7, 1)]:
    print(f"market {m}, credit {c} -> indicator {indicador(m, c)}")
OUT [06]From market and credit risk to the summary indicator
market 2, credit 1 -> indicator 2
market 2, credit 4 -> indicator 5
market 5, credit 3 -> indicator 5
market 7, credit 1 -> indicator 7

A UCITS fund, with its assets segregated at the depositary, usually has low credit risk and its indicator is its market class. A structured product from a weak issuer can have a market risk of 2 and an indicator of 5. And derivatives are another story: point 4 of Annex II includes in category 1 the PRIIPs in which more than the amount invested can be lost and the derivatives in points 4 to 10 of Section C of Annex I of MiFID II, and point 8 assigns them market class 7. A listed option, a future or a CFD carries indicator 7, whatever the volatility of the underlying.

Performance scenarios: what they say and what they do not

Since the 2021 amendment, the unfavorable, moderate and favorable scenarios of a category 2 PRIIP come from the history of the product or of its benchmark: according to the Joint Committee Q&A, that history has to cover at least 10 years and 5 more than the recommended holding period, it is split into subintervals of the length of that period and the results are sorted to pick each scenario. The stress scenario is computed separately. To see where those figures come from, an illustration with the series of a level 3 index (it is not the exact method of Annex IV, which has more steps):

IN [07]python
rva = s(ind, ind["indice"] == "RVA", "contado").resample("ME").last()
finales = 10_000 * (rva.shift(-60) / rva).dropna()
print(f"{len(rva)} months ({rva.index.min():%Y-%m} to "
      f"{rva.index.max():%Y-%m}); {len(finales)} 5-year windows")
print(finales.quantile([0, 0.1, 0.5, 0.9, 1]).round(0).to_string())
OUT [07]Results of every 5-year window (illustration)
192 months (2010-01 to 2025-12); 132 5-year windows
0.0    11197.0
0.1    13047.0
0.5    17419.0
0.9    21629.0
1.0    37766.0

With 16 years of monthly history there is room for 132 five-year windows, with results between 11,197 and 37,766 EUR and the median at 17,419. Almost all of them overlap: they are not 132 independent observations, they are three five-year periods seen from different starting points. A KID's scenarios summarize the past of that product with a rule common to all products so that they are comparable; they are not forecasts, and the document itself says so (the course's synthetic KIDs: “Los escenarios son ilustrativos y se basan en la evolución pasada”, the scenarios are illustrative and based on past performance).

Alternatives for a retail investor and what they cost

AlternativeWhat it doesWhat you gainWhat you lose
UCITS ETF on the same indexEU-domiciled fund with a KIDCan be bought as a retail investor; UCITS protectionAnother ticker, sometimes another currency and another exchange; the withholding on US dividends stays inside the fund (lesson 7.4.6)
Listed options on the US ETFDerivative with a KID for the contract typeLeveraged or hedged exposureRisk indicator 7, mandatory appropriateness test (lesson 7.4.1), time decay and margin
The index stocks one by oneDirect purchase: they are not PRIIPsNo KID and no management feeMany orders, commissions and currency conversion for each one; imperfect replication
Becoming a professional clientOutside the scope of PRIIPsAccess to the US ETFAnnex II requirements and giving up protections (lesson 7.4.1)

On options, the Joint Committee Q&A (section IX, from 2017) accepts, for futures and options traded on a regulated market, one KID per group of contracts with the same relevant characteristics (type of derivative, underlying, exercise style), for example one for buying calls on stocks, not one per series. That is why a broker can offer a retail investor options on an ETF it could not sell them.

The cost comparison between the UCITS ETF and the US one is where forums get it most wrong: they compare the management fee and forget the rest. A calculator with all the assumptions in plain sight. The UCITS fee is that of the synthetic KID of the US technology fund (0.32% annual impact); everything else is an assumption of the lesson, not data for any product:

IN [08]python
H = dict(
    inversion=10_000, anos=20,
    precio=0.055, dividendo=0.015,    # gross return of the index
    coste_ucits=kid.loc["R18", "incidencia"] / 100,
    coste_eeuu=0.0010,                # assumption
    retencion=0.15,                   # assumption: at source, US
    divisa=0.002,                     # assumption: each conversion
)

def valor_final(ucits, retencion_recuperable=False, h=H):
    v = h["inversion"] * (1 - (0 if ucits else h["divisa"]))
    coste = h["coste_ucits"] if ucits else h["coste_eeuu"]
    for _ in range(h["anos"]):
        div = v * h["dividendo"]
        ret = 0 if retencion_recuperable else div * h["retencion"]
        conv = 0 if ucits else (div - ret) * h["divisa"]
        v = v * (1 + h["precio"]) + div - ret - conv
        v *= 1 - coste
    return v * (1 - (0 if ucits else h["divisa"]))

bruto = H["inversion"] * (1 + H["precio"] + H["dividendo"]) ** H["anos"]
casos = {
    "UCITS accumulating (tax withheld in fund)": valor_final(True),
    "US, withholding not recoverable": valor_final(False),
    "US, withholding recovered in Spain": valor_final(False, True),
}
for k, v in casos.items():
    print(f"{k:42} {v:9,.0f} EUR  cost {bruto - v:7,.0f}")
OUT [08]20-year cost: UCITS ETF vs. US ETF (assumptions)
UCITS accumulating (tax withheld in fund)     34,798 EUR  cost   3,899
US, withholding not recoverable               36,204 EUR  cost   2,493
US, withholding recovered in Spain            37,757 EUR  cost     939

The calculator simplifies two things on purpose. It assumes that the withholding on US dividends inside the UCITS fund is the same as that suffered by the direct investor, and it models the US case with dividends reinvested without Spanish tax: the real treatment (double taxation treaties, the deduction in the IRPF, Spain's personal income tax, and when each option is taxed) is in lesson 7.4.6 and changes the result. With these assumptions, the UCITS ETF that a retail investor can buy is the most expensive of the three. But the difference between the two US cases, which only change the withholding assumption (1,553 EUR), is larger than the one separating the UCITS from the US ETF without recovering it (1,406 EUR), which reflects the difference in fees (0.22 points a year) and the currency costs. Until the tax assumption is written down, the comparison means nothing. The figure at the top draws the three cases.

Exercises

  1. Write a function that checks that a KID in text form has the sections of Article 8 in the right order and apply it to the five KIDs. Then remove a section from one and check that it detects it.
Solution
IN [09]python
SECCIONES = [   # the Spanish headings of the course KIDs
    "## Finalidad",
    "## Producto",
    "## ¿Qué es este producto?",
    "## ¿Qué riesgos corro y qué podría obtener a cambio?",
    "## ¿Qué pasa si",
    "## ¿Cuáles son los costes?",
    "## ¿Cuánto tiempo debo mantener la inversión",
    "## ¿Cómo puedo reclamar?",
    "## Otros datos de interés",
]

def secciones_ok(texto):
    pos = [texto.find(s) for s in SECCIONES]
    faltan = [s for s, p in zip(SECCIONES, pos) if p < 0]
    if faltan:
        return "missing: " + "; ".join(faltan)
    return "ok" if pos == sorted(pos) else "wrong order"

print({i: secciones_ok(t) for i, t in kids["texto"].items()})
roto = kids.loc["R12", "texto"].replace("## ¿Cómo puedo reclamar?", "")
secciones_ok(roto)
OUT [09]Article 8 sections, in order
{'R10': 'ok', 'R12': 'ok', 'R14': 'ok', 'R16': 'ok', 'R18': 'ok'}
'missing: ## ¿Cómo puedo reclamar?'

All five follow the structure. The check is useful before indexing documents in a RAG (lesson 6.3.2): a KID missing a section has probably been extracted badly from the PDF, and its answers will be incomplete. The removed section, “¿Cómo puedo reclamar?”, is the Spanish heading “How can I complain?”.

  1. In the calculator, what annual fee would the UCITS ETF need to match the final value of the US ETF with non-recoverable withholding? And with recovered withholding?
Solution
IN [10]python
def equilibrio(objetivo):
    lo, hi = 0.0, 0.02
    for _ in range(60):                   # bisection
        mid = (lo + hi) / 2
        v = valor_final(True, h={**H, "coste_ucits": mid})
        lo, hi = (mid, hi) if v > objetivo else (lo, mid)
    return 100 * mid

for k in list(casos)[1:]:
    print(f"{k:42} {equilibrio(casos[k]):.3f} %")
OUT [10]Break-even fee of the UCITS
US, withholding not recoverable            0.122 %
US, withholding recovered in Spain         0.000 %

Against the US ETF with non-recoverable withholding, the UCITS would break even with an annual impact of 0.122% instead of the 0.32% in its KID. Against the case with recovered withholding it does not break even even with a zero fee (the bisection stops at 0.000%): under this assumption, the withholding inside the fund is a cost the direct investor recovers and the UCITS does not. The answer depends on the tax treatment, not only on the product.

  1. A broker offers you a US ETF if you sign “a professional client form”. Explain what the broker would have to check before accepting it and which document you would stop receiving with each order.
Solution

The broker would have to check that you meet two of the three criteria of Annex II of MiFID II and of Article 113 of Spain's Royal Decree 813/2023 (Real Decreto 813/2023) (on average ten transactions of significant size per quarter, a portfolio of more than 500,000 EUR, one year in a position in the financial sector) and follow the written procedure with a separate statement (lesson 7.4.1). A form without that check is not a valid classification. As a professional, the PRIIPs Regulation does not apply to your purchases: you would stop receiving the KID, and with it the risk indicator, the scenarios and the standardized costs of each product; in addition, the firm can presume your knowledge in the appropriateness assessment.

Each answer is folded under its question

Self-assessment

  1. Why does a European broker sell a retail client shares in a US company but not a US ETF on the same index?

    • ABecause US stocks have a KID and ETFs do not
    • BBecause a share is not a packaged product: what the investor receives does not depend on assets they do not buy directly; an ETF is one and needs a KID that its manager does not produce
    • CBecause US ETFs are banned by ESMA
    • DBecause US ETFs are not quoted in euros
    Show answer

    Answer B. Because a share is not a packaged product: what the investor receives does not depend on assets they do not buy directly; an ETF is one and needs a KID that its manager does not produce

    Article 4(1) of Regulation 1286/2014 defines the packaged product by its exposure to reference values or to assets not directly purchased by the investor. An ETF is one; a share is not. Without a KID, Article 13 prevents selling it to a retail investor.

  2. A KID says: total costs if you exit after 1 year, 32 EUR on 10,000 EUR invested. What return assumption is behind that figure?

    • AThat of the favorable scenario
    • BThat of the moderate scenario
    • CA 0% return in the first year; the moderate scenario for the other periods
    • DThe historical return of the last year
    Show answer

    Answer C. A 0% return in the first year; the moderate scenario for the other periods

    It is the prescribed text of the cost presentation (Joint Committee Q&A on the KID): in the first year the investor is assumed to get back what they invested (0%); for the other periods, the moderate scenario. That is why 32 EUR is exactly 0.32% of 10,000.

  3. A fund's annualized volatility over the last five years is 20.5%. Which market risk class does it get, if its distribution is approximately normal and its credit risk is class 1?

    • A5: the Annex II table puts the 20% to 30% band in class 5, and with credit risk 1 the summary indicator equals the market class
    • B4, because it is close to 20%
    • C6
    • DIt depends on the recommended holding period
    Show answer

    Answer A. 5: the Annex II table puts the 20% to 30% band in class 5, and with credit risk 1 the summary indicator equals the market class

    The class table runs from < 0.5% (1) to > 80% (7), with the boundary between 4 and 5 at 20%. With the credit risk 1 row, the indicator is the market class. A tenth of a point above the boundary changes the number the investor sees, which is why the regulation requires monitoring of the data.

  4. What summary risk indicator does the KID of a listed option bought by a retail investor carry?

    • AWhatever comes out of the underlying's volatility
    • BAlways 1
    • C7: the derivatives in Section C of Annex I of MiFID II are category 1 PRIIPs and their market risk class is 7
    • DThey carry no indicator
    Show answer

    Answer C. 7: the derivatives in Section C of Annex I of MiFID II are category 1 PRIIPs and their market risk class is 7

    Point 4 of Annex II of Delegated Regulation 2017/653 includes in category 1 the PRIIPs in points 4 to 10 of Section C of Annex I of MiFID II (derivatives), and point 8 assigns them class 7. With low credit risk, the indicator is 7.

  5. In the lesson's calculator, what mainly decides whether the UCITS ETF comes out more or less expensive than the US one?

    • AOnly the management fee
    • BThe summary risk indicator
    • CThe KID's moderate scenario
    • DThe assumptions about withholding tax on dividends (where it is applied and whether the investor recovers it) and the currency costs, more than the difference in fees
    Show answer

    Answer D. The assumptions about withholding tax on dividends (where it is applied and whether the investor recovers it) and the currency costs, more than the difference in fees

    With the lesson's assumptions, changing whether the withholding at source is recoverable moves the 20-year cost more than the difference in management fees. The specific tax rules are in lesson 7.4.6.

Key points

  • A PRIIP is an investment whose repayment depends on assets the investor does not buy directly: funds, ETFs, derivatives, structured products. A share or a plain bond is not one.
  • Whoever sells a PRIIP to a retail investor must hand over the KID beforehand (Art. 13); the manufacturer produces it (Art. 5). US ETFs do not usually have one, which is why they are not sold to EU retail investors.
  • The KID has fixed sections and texts; its figures can be extracted and validated: ISIN, annualized returns of the scenarios, the sum of the costs and the total costs with 0% in the first year.
  • The summary risk indicator combines a market risk class (by the VaR-equivalent volatility at 97.5%, from < 0.5% to > 80%) and a credit class; derivatives are always class 7.
  • The alternatives have different costs: the UCITS ETF (KID, and withholding inside the fund), options (a KID per contract type and risk 7) and professional client treatment (no KID or protections); the comparison depends on tax assumptions that have to be written down.

Resources