Lesson 1.2.7 · 60 min

Fixed income and interest rates; CFDs and leveraged products

The interest rate is the price of money and it shows up in every other lesson: in the carry of futures, the forex rollover or options parity. This lesson studies it in its own market, the bonds and yield curve of a fictitious country, and ends with CFDs, the most common leveraged product among retail traders in Europe.

Fig. — Valdoria sovereign curve on three dates: steep with the policy rate near zero (June 2021), inverted after the rate hikes (June 2023) and nearly flat at the end of 2025
07/07
Module
1.2 · Asset classes
Duration
60 min
Updated
Level 1 lessons
  1. 1.1 · How markets work

    1. 1.1.1 Market participants and trading venues
    2. 1.1.2 Sessions, auctions, holidays and calendars
    3. 1.1.3 Order book: bid, ask, spread and depth
    4. 1.1.4 Order types
    5. 1.1.5 Costs, settlement, leverage and margin
  2. 1.2 · Asset classes

    1. 1.2.1 Stocks: splits, dividends and corporate actions
    2. 1.2.2 ETFs: replication, tracking error, leveraged ETFs and UCITS
    3. 1.2.3 Futures: specifications, margin, roll and contango
    4. 1.2.4 Forex: pairs, pips, lots, rollover and CFDs
    5. 1.2.5 Options: calls, puts, intrinsic value and time value
    6. 1.2.6 Crypto: spot, perpetuals, funding and custody
    7. 1.2.7 Fixed income and interest rates; CFDs and leveraged products
  3. 1.3 · Market data sources

    1. 1.3.1 Types of market data: EOD, bars, ticks, order book and reference
    2. 1.3.2 Free market data sources
    3. 1.3.3 Retail and prosumer market data APIs
    4. 1.3.4 Professional market data providers
    5. 1.3.5 Crypto and on-chain data
    6. 1.3.6 Brokers as market data sources
    7. 1.3.7 Market data licensing and terms of use
    8. 1.3.8 How to choose a market data provider
  4. 1.4 · Financial data engineering

    1. 1.4.1 Downloading over REST and websockets: pagination, rate limits and retries
    2. 1.4.2 Data cleaning: missing values, bad ticks, gaps and time zones
    3. 1.4.3 Adjusting for splits and dividends: adjusted and unadjusted prices
    4. 1.4.4 Universes without survivorship bias: delistings, mergers and symbol changes
    5. 1.4.5 Building bars: time, tick, volume, dollar and imbalance
    6. 1.4.6 Continuous futures series: roll rules, difference adjustment and ratio adjustment
    7. 1.4.7 Storage: CSV, Parquet, partitioning, DuckDB, TimescaleDB and ArcticDB
    8. 1.4.8 Reproducible pipeline: download, validation, incremental updates and quality tests
  5. 1.5 · Fundamental and macro data

    1. 1.5.1 Financial statements, ratios, XBRL and SEC EDGAR
    2. 1.5.2 Macro data, economic calendars, estimates and transcripts
  6. 1.6 · Financial exploratory analysis

    1. 1.6.1 Returns, volatility, rolling correlations and drawdown
    2. 1.6.2 Stylized facts: fat tails, clustering, autocorrelation and leverage
    3. 1.6.3 Seasonality: day of the week, month, turn of the month and intraday sessions
  7. 1.7 · Programmed technical analysis

    1. 1.7.1 Technical indicators in Python
    2. 1.7.2 Your own implementation versus TA-Lib: validating results
    3. 1.7.3 Candlestick patterns and support and resistance
    4. 1.7.4 Multi-timeframe analysis without look-ahead

The price of money

The interest rate shows up, in one form or another, in every market in this module: in the theoretical price of a future (lesson 1.2.3), in the rollover of a forex position (1.2.4), in options put-call parity (1.2.5) and in the financing of any leveraged position (1.1.5). Its own market is fixed income: the bonds that governments and companies issue to borrow. A stock trading system does not need to trade bonds, but it does need to understand what moves rates, because they move the value of everything else.

Central bankPolicy rateExpectationsYield curveValue of cash flowsFutures carryFinancing
Mermaid source
flowchart TB
  BC[Central bank] --> TO[Policy rate]
  TO --> EX[Expectations]
  EX --> CU[Yield curve]
  CU --> DE[Value of cash flows]
  CU --> CA[Futures carry]
  CU --> FI[Financing]

The central bank sets the policy rate, the very short-term rate. Rates at longer tenors depend on what the market expects that policy rate to do in the future, plus a term premium that compensates for the risk of lending long. Those rates are the ones used to discount future cash flows (which is why stock valuations rise and fall), to compute the carry of futures and to charge financing on margin positions.

Inside a bond

A fixed-coupon bond pays periodic interest (the coupon, as a percentage of face value) and repays the face value at maturity. Its price is the present value of those cash flows, discounted at the yield to maturity yy, the single rate that equates price and cash flows. With annual coupons CC, face value 100 and nn years:

P=∑t=1nC(1+y)t+100(1+y)nP = \sum_{t=1}^{n} \frac{C}{(1 + y)^t} + \frac{100}{(1 + y)^n}

The example is a 10-year bond of Valdoria, the fictitious country in the level's data, with a 3% annual coupon:

IN [01]python
import numpy as np
import pandas as pd
from scipy.optimize import brentq

def flujos_bono(cupon, anos, nominal=100.0):
    """Annual cash flows: coupons and, in the last year, face value."""
    t = np.arange(1, anos + 1)
    f = np.full(anos, cupon * nominal)
    f[-1] += nominal
    return t, f

def precio_bono(y, cupon, anos):
    t, f = flujos_bono(cupon, anos)
    return float((f / (1 + y) ** t).sum())

t, f = flujos_bono(0.03, 10)
print("cash flows:", f)
for y in (0.02, 0.03, 0.04):
    precio = precio_bono(y, 0.03, 10)
    print(f"yield {y:.0%}: price {precio:.3f}")
OUT [01]Cash flows and price of a bond
cash flows: [  3.   3.   3.   3.   3.   3.   3.   3.   3. 103.]
yield 2%: price 108.983
yield 3%: price 100.000
yield 4%: price 91.889

If the market yield matches the coupon, the bond trades at par (100). If market rates are higher than its coupon, nobody buys it at 100: its price falls until buying it yields the same as a new bond (it trades below par). If they are lower, it rises (above par). Price and yield always move in opposite directions.

In the market the price is observed, and the yield is inferred by solving the equation the other way around. It has no closed-form solution, but it does have a single root, which is found numerically:

IN [02]python
def rentabilidad(precio, cupon, anos):
    return brentq(lambda y: precio_bono(y, cupon, anos) - precio,
                  -0.05, 0.5)

curva = pd.read_csv("curva_tipos_diaria.csv", parse_dates=["fecha"],
                    index_col="fecha")
y10 = curva.loc["2025-12-31", "10a"] / 100
p_hoy = precio_bono(y10, 0.03, 10)
print(f"Valdoria 10-year on 31-12-2025: {y10:.3%}")
print(f"Price of the 3% bond: {p_hoy:.3f}")
print(f"Yield inferred from that price: "
      f"{rentabilidad(p_hoy, 0.03, 10):.3%}")
OUT [02]Yield from the price
Valdoria 10-year on 31-12-2025: 3.547%
Price of the 3% bond: 95.462
Yield inferred from that price: 3.547%

With the Valdoria 10-year at 3.547% at the end of 2025, the 3% bond trades at 95.462: below par, because its coupon is lower than what the market pays. Starting from the price, the same yield is recovered. Here the bond is fictitious and is valued with the curve's yield; with real bonds you also have to take into account accrued interest (the interest accumulated since the last coupon, which the buyer pays on top of the “clean” price) and each market's day count convention.

Duration, DV01 and convexity

For a trader, the important question is how much the price changes if rates move. The first-order answer is the modified duration DmodD_{mod}:

ΔPP≈−Dmod Δy+12 Conv (Δy)2\frac{\Delta P}{P} \approx -D_{mod}\,\Delta y + \tfrac{1}{2}\,\text{Conv}\,(\Delta y)^2

(Macaulay) duration is the average time of the cash flows, weighted by their present value; modified duration divides it by 1+y1 + y. DV01 is the price change for one basis point (0.01%) of yield, in money, and convexity corrects for the curvature of the relation, which duration treats as if it were a straight line:

IN [03]python
def sensibilidades(y, cupon, anos):
    t, f = flujos_bono(cupon, anos)
    vp = f / (1 + y) ** t
    p = vp.sum()
    macaulay = (t * vp).sum() / p
    d_mod = macaulay / (1 + y)
    conv = (t * (t + 1) * vp).sum() / (p * (1 + y) ** 2)
    return p, macaulay, d_mod, conv

p, mac, dmod, conv = sensibilidades(y10, 0.03, 10)
print(f"Macaulay duration: {mac:.2f} years")
print(f"Modified duration: {dmod:.2f}")
print(f"Convexity:         {conv:.1f}")
print(f"DV01 per 1 M of face value: {dmod * p / 100 * 1e6 * 1e-4:,.0f}")
OUT [03]Duration, DV01 and convexity of the bond
Macaulay duration: 8.75 years
Modified duration: 8.45
Convexity:         85.7
DV01 per 1 M of face value: 807

The 10-year bond has a Macaulay duration of almost nine years: the coupons bring part of the money forward and pull the average time below maturity. With a modified duration of 8.45, each basis point rise in yield takes 0.085% off the price, 807 units per million of face value. For small moves duration is enough; for large ones, convexity matters:

IN [04]python
filas = []
for dy in (-0.02, -0.01, -0.001, 0.001, 0.01, 0.02):
    exacto = precio_bono(y10 + dy, 0.03, 10) / p - 1
    solo_dur = -dmod * dy
    con_conv = solo_dur + 0.5 * conv * dy ** 2
    filas.append({"cambio_pb": round(dy * 1e4),
                  "exacto_%": 100 * exacto,
                  "duracion_%": 100 * solo_dur,
                  "dur_conv_%": 100 * con_conv})
pd.DataFrame(filas).set_index("cambio_pb").round(3)
OUT [04]Approximation versus exact price
           exacto_%  duracion_%  dur_conv_%
cambio_pb
-200         18.756      16.904      18.618
-100          8.897       8.452       8.881
-10           0.850       0.845       0.849
 10          -0.841      -0.845      -0.841
 100         -8.039      -8.452      -8.023
 200        -15.312     -16.904     -15.190

With 10 basis points, duration alone is off by less than a hundredth of a percentage point. With 200, by more than a point and a half (−16.904% against −15.312% for a rise), and always in the same direction: the real price rises more than duration says when rates fall and falls less when they rise. That asymmetry, convexity, is a favorable property for the bondholder, and the figure draws it: the curve of price against yield always lies above the tangent line.

Fig. — Price of a fictitious 10-year bond with a 3% annual coupon by yield, and the tangent line given by duration at the 3.547% Valdoria 10-year yield at the end of 2025

The Valdoria yield curve

Each tenor has its yield. Joined together, they form the yield curve. The data are Valdoria's daily sovereign curve between 2019 and 2025 at five tenors: 3 months, 2, 5, 10 and 30 years. The curve comes from expectations about Valdoria's policy rate (macro_vintages.csv) plus a term premium, the same structure attributed to real curves.

IN [05]python
print(curva.shape)
fechas = ["2019-06-03", "2021-06-01", "2023-06-01", "2025-12-31"]
curva.loc[fechas]
OUT [05]The daily curve
(1760, 5)
               3m     2a     5a    10a    30a
fecha
2019-06-03  2.322  1.425  2.100  2.659  2.972
2021-06-01  0.156  1.524  2.371  2.484  2.858
2023-06-01  4.992  4.305  3.450  3.363  3.337
2025-12-31  3.403  3.243  3.254  3.547  3.576

Four snapshots with four shapes. In June 2019, a positive slope from 2 years on, although with the 3-month above the 2-year: the market was already pricing in some cut to the policy rate. In June 2021, with the policy rate close to zero after the 2020 crisis, the short end is pinned at zero and the curve is very steep. In June 2023, after the rate hikes, the curve is inverted: the 3-month yields almost 5% and the 30-year, 3.3%. At the end of 2025, with cuts already under way, the curve is almost flat again with a positive slope. The figure at the top draws the 2021 and 2023 curves next to the end-of-2025 one.

The slope and the inversion

The shape of the curve is summed up by its slope, usually the difference between the 10-year and the 2-year (the 2s10s), in basis points. Positive, the curve is normal; negative, inverted. An inverted curve says the market expects future cuts to the policy rate: high short-term rates today and lower ones tomorrow. That is why many analysts follow it as a leading signal of a slowdown; but, if the relation exists, it is statistical, with long and variable lags, and it does not work as a clock.

IN [06]python
pendiente = 100 * (curva["10a"] - curva["2a"])  # basis points
invertida = pendiente < 0
print(f"Sessions with an inverted curve: {invertida.sum()} "
      f"of {len(curva)}")
tramos = (invertida != invertida.shift()).cumsum()
periodos = (pendiente[invertida].groupby(tramos[invertida])
            .agg(inicio=lambda s: s.index[0].date(),
                 fin=lambda s: s.index[-1].date(),
                 sesiones="size", minimo="min"))
periodos.reset_index(drop=True).round(1)
OUT [06]The 2s10s and the inversion periods
Sessions with an inverted curve: 671 of 1760
       inicio         fin  sesiones  minimo
0  2022-06-06  2025-01-13       654   -98.6
1  2025-01-16  2025-01-27         7    -6.9
2  2025-01-31  2025-02-06         5    -6.2
3  2025-02-10  2025-02-11         2    -2.8
4  2025-02-14  2025-02-14         1    -0.1
5  2025-02-21  2025-02-24         2    -3.3
Fig. — Valdoria curve 2s10s slope (10-year minus 2-year), last value of each week, 2019–2025. Shaded, the inverted-curve period

The Valdoria curve inverts in June 2022, when the central bank raises rates quickly, hits its low of almost −100 basis points at the end of 2022 and stays inverted for 654 consecutive sessions, until January 13, 2025; after that the slope oscillates around zero, with five short inverted stretches (from one to seven sessions) until February 24. In total, 671 sessions. The slope turns positive again when the central bank starts cutting rates and the 2-year falls ahead of the 10-year.

The short end of the curve follows the policy rate very closely, because nobody lends for three months at a rate very different from what the central bank pays for overnight money:

IN [07]python
macro = pd.read_csv("macro_vintages.csv",
                    parse_dates=["fecha_publicacion"])
oficial = (macro[macro["serie"] == "tipo_oficial"]
           .set_index("fecha_publicacion")["valor"])
fin_mes = curva["3m"].resample("ME").last()
fin_mes.index = fin_mes.index.normalize()
comp = pd.DataFrame({"oficial": oficial.resample("ME").last(),
                     "curva_3m": fin_mes}).dropna()
print(f"Monthly correlation: {comp.corr().iloc[0, 1]:.3f}")
comp.loc["2022-03":"2022-09"].round(3)
OUT [07]The 3-month versus the policy rate
Monthly correlation: 0.987
            oficial  curva_3m
2022-03-31     0.35     0.908
2022-04-30     0.35     1.311
2022-05-31     0.85     1.908
2022-06-30     1.60     2.269
2022-07-31     2.35     2.790
2022-08-31     2.35     3.242
2022-09-30     3.10     3.725

The 3-month runs ahead of the policy rate: it rises before each hike, because the market prices it in. It is the small version of what the whole curve does, and the reason rate data are a leading indicator of central bank decisions (lesson 1.5.2).

Interest rate futures

Rates are also traded with futures, and they are among the most liquid contracts in the world. There are two families:

  • Short-term interest rate futures: they settle against the interest rate for a period (three months, for example). By convention they are quoted as 100 minus the rate: a price of 96.25 implies a rate of 3.75%. That way, as with a bond, the price falls when the market expects higher rates. The strip of expiries of these futures is a curve of policy rate expectations.
  • Bond futures: they refer to a notional bond and settle by delivering real bonds from a list. Eurex's Euro-Bund, for example, has a face value of 100,000 EUR on a notional German bond with a 6% coupon and a remaining life of between 8.5 and 10.5 years, with a tick of 0.01% (10 EUR)1Note 1 · Eurex, fixed income futures factsheet (link in the resources): contract value, notional coupon, remaining life of the underlying and minimum price change of the Euro-Bund.. Its price moves with the German 10-year yield according to the duration of the cheapest-to-deliver bond.
IN [08]python
# short-term future: 100 - rate, fictitious 1 M, 3-month contract
precio_stir = 100 - curva.loc["2025-12-31", "3m"]
print(f"Short-term future implied by the 3-month: {precio_stir:.3f}")
print(f"Basis point value: {1e6 * 1e-4 * 0.25:.0f} per contract")

# bond future: 6% notional, 10 years, 100,000 face value
p6, _, dmod6, _ = sensibilidades(y10, 0.06, 10)
print(f"6% notional bond: price {p6:.2f}, D_mod {dmod6:.2f}")
dv01_6 = dmod6 * p6 / 100 * 1e5 * 1e-4
print(f"DV01 of 100,000 face value: {dv01_6:.0f}")
OUT [08]What moves per basis point
Short-term future implied by the 3-month: 96.597
Basis point value: 25 per contract
6% notional bond: price 120.35, D_mod 7.75
DV01 of 100,000 face value: 93

A short-term contract of one million and three months moves 25 units per basis point: 1,000,000 × 0.0001 × 0.25. A 6% 10-year notional bond, with a yield of 3.547%, trades well above par, at 120.35, with a modified duration of 7.75, lower than that of the 3% bond (high coupons bring the cash flows forward); 100,000 of face value moves about 93 units per basis point. With those numbers you can compute how many contracts hedge a bond portfolio or how much rate risk a position carries. (The price of a real bond future also depends on the cheapest-to-deliver bond and its conversion factor; here the order of magnitude is enough.)

CFDs and leveraged products for retail clients

A CFD (contract for difference) is a contract between the client and a provider in which the difference in the price of an underlying (a stock, an index, a currency, a bond, a commodity) between the opening and the closing of the position is exchanged. The client does not buy the underlying: they open a position with the provider, who is their counterparty, and post margin.

marginprice and P&LyesnoRetail clientCFD providerHedges?Real marketOwn book
Mermaid source
flowchart TB
  C[Retail client] -- margin --> P[CFD provider]
  P -- price and P&L --> C
  P --> D{Hedges?}
  D -- yes --> M[Real market]
  D -- no --> L[Own book]

Two consequences. First: the provider can hedge the position in the market or keep it, and in that case it gains what the client loses, a conflict of interest that regulation requires to be managed. Second: CFDs with no expiry charge financing every night on the notional of long positions (and pay or charge something on shorts), with a spread over a reference rate. It is the same idea as perpetuals funding (lesson 1.2.6) or the forex rollover (1.2.4), and on positions held for weeks it weighs heavily.

In 2018 ESMA restricted CFDs for retail clients across the EU because, according to the national authorities' analyses, between 74% and 89% of retail accounts lost money, with average losses per client of 1,600 to 29,000 euros2Note 2 · ESMA, press release of March 27, 2018 (link in the resources).. The measures, product intervention under MiFIR (temporary and renewable every three months), were five:

MeasureWhat it requires
Leverage limits on openingFrom 30:1 to 2:1 depending on the underlying (full table in lesson 1.2.4)
Margin close-outClose positions when margin falls to 50% of the required minimum, per account
Negative balance protectionThe client cannot lose more than what was deposited in the account
IncentivesBonuses and gifts for trading are banned
Risk warningStandardized, with the percentage of the provider's accounts that lose money
IN [09]python
nocional = 10_000  # long CFD on a major index
apal = 20          # ESMA limit for major indices: 20:1
margen = nocional / apal
cierre = 0.5 * margen
print(f"Margin: {margen:.0f}; close-out if losses reach "
      f"{margen - cierre:.0f} ({(margen - cierre) / nocional:.1%} "
      "of the notional)")

# financing: reference rate + 2.5% (assumed spread)
tipo_ref = curva.loc["2025-12-31", "3m"] / 100
anual = nocional * (tipo_ref + 0.025)
print(f"Financing of a long: {anual / 360:.2f} per day, "
      f"{anual:.0f} per year ({anual / margen:.0%} of the margin)")
OUT [09]Margin, 50% close-out and financing of a CFD
Margin: 500; close-out if losses reach 250 (2.5% of the notional)
Financing of a long: 1.64 per day, 590 per year (118% of the margin)

With the maximum leverage for a major index, an adverse move of 2.5% is enough for the provider to close the position. And financing, with a spread of 2.5 points over the short-term rate (an assumption: each provider publishes its own), costs 590 a year: 118% of the margin tied up. That is why the CFD is a tool for positions held for days, not months, and why a backtest with CFDs that does not include daily financing overstates the result. A future on the same index carries the cost of money inside its price (the basis from lesson 1.2.3), without an added spread.

There are other leveraged products for retail clients: exchange-listed warrants and turbos (with a barrier that, when touched, cancels the product), leveraged and inverse ETFs (lesson 1.2.2) and options (1.2.5). Their risk is not in the product's name but in its effective leverage and in how the capital is lost: all at once when a barrier is touched, little by little through financing or through the decay of the daily rebalancing.

Typical mistakes with rate data

  • Price and yield. A series of yields is not a series of prices: if it rises, the bond loses. For the result of a bond position you have to convert to price (with duration or by revaluing the bond) and add the coupons.
  • Units. Rates in percent (3.547), as a decimal (0.03547) or in basis points (354.7). Half the mistakes in a fixed income calculation are a factor of 100.
  • Constant maturity curves. The “10-year” of a curve is a fixed tenor recomputed every day with different bonds; it is not a bond you can hold in a portfolio.
  • Conventions. Annual or semiannual coupons, day count basis (Act/360, Act/365, 30/360) and accrued interest change the figures. Before comparing two sources, you need to know which convention each one uses.

Exercises

  1. Compute the price, modified duration and DV01 per million of a 2-year bond with a 3% coupon using the Valdoria 2-year yield of December 31, 2025. Compare its DV01 with that of the 10-year bond: how many millions of face value of the 2-year carry the same rate risk as one million of the 10-year?
Solution
IN [10]python
y2 = curva.loc["2025-12-31", "2a"] / 100
p2, _, dmod2, _ = sensibilidades(y2, 0.03, 2)
dv01_2 = dmod2 * p2 / 100 * 1e6 * 1e-4
dv01_10 = dmod * p / 100 * 1e6 * 1e-4
print(f"2-year: price {p2:.3f}, D_mod {dmod2:.2f}, "
      f"DV01 {dv01_2:.0f} per million")
print(f"2-year face value equivalent to 1 M of the 10-year: "
      f"{dv01_10 / dv01_2:.2f} M")
OUT [10]2-year bond and DV01 hedge
2-year: price 99.537, D_mod 1.91, DV01 190 per million
2-year face value equivalent to 1 M of the 10-year: 4.25 M

The 2-year bond has a duration of less than two years and a DV01 of about 190 units per million, against 810 for the 10-year: you need a little over four million of the 2-year to have the same risk per basis point. It is the calculation behind a slope trade (buying the 10-year and selling the 2-year, or the other way around) that is neutral to a parallel shift of the curve.

  1. Compute the average 2s10s of each year and the number of sessions with an inverted curve in each year. In which year is the inversion deepest on average?
Solution
IN [11]python
por_ano = pd.DataFrame({
    "pendiente_media_pb": pendiente.groupby(pendiente.index.year)
                                    .mean(),
    "sesiones_invertida": invertida.groupby(invertida.index.year)
                                     .sum(),
})
por_ano.round(1)
OUT [11]Slope by year
       pendiente_media_pb  sesiones_invertida
fecha
2019                141.4                   0
2020                151.1                   0
2021                 92.2                   0
2022                -23.0                 145
2023                -75.9                 250
2024                -28.2                 252
2025                 14.4                  24

The deepest inversion on average is 2023's, −75.9 basis points, with all 250 sessions of the year inverted. 2022 has 145 inverted sessions, from June, and the absolute low; 2024, all 252 sessions of the year, although with a smaller average inversion (−28.2). In 2025 only 24 inverted sessions remain and the average slope turns positive again.

  1. A friend wants to hold a long CFD on an index for three months because “it's cheaper than a fund”. What costs and risks would you explain, using the data in this lesson?
Solution

The CFD has no management fee, but it charges financing every night on the entire notional: with a short-term rate of 3.4% and a spread of 2.5 points, around 6% a year of the notional, 1.5% in three months, much more than the annual fee of an index fund. It also pays the spread when opening and closing. With leverage, a small adverse move triggers the 50% margin close-out and locks in the loss, and the provider is the counterparty: if it goes bankrupt, there are no securities in your friend's name. A fund or an ETF (lesson 1.2.2) gives the same exposure without financing or the risk of a forced close-out; if they want leverage, a future carries the cost of money in its price without a spread.

Footnotes

  1. Eurex, fixed income futures factsheet (link in the resources): contract value, notional coupon, remaining life of the underlying and minimum price change of the Euro-Bund. ↩

  2. ESMA, press release of March 27, 2018 (link in the resources). ↩

Each answer is folded under its question

Self-assessment

  1. Market interest rates rise. What happens to the price of an already issued fixed-coupon bond?

    • AIt rises, because it pays more interest
    • BIt does not change, because the coupon is fixed
    • CIt depends only on the issuer
    • DIt falls: its fixed coupons are worth less discounted at a higher rate
    Show answer

    Answer D. It falls: its fixed coupons are worth less discounted at a higher rate

    The price is the present value of the cash flows. With a higher discount rate, each cash flow is worth less today. A new bond would pay a higher coupon; the old one only sells if its price falls until its yield matches.

  2. A bond has a modified duration of 8.5 and trades at 95. If its yield rises 10 basis points, roughly how much does its price change?

    • A−8.5%
    • B−0.085%
    • C−0.85%
    • D+0.85%
    Show answer

    Answer C. −0.85%

    The relative price change is −modified duration × change in yield: −8.5 × 0.001 = −0.85%. In price, about 0.81 points on 95.

  3. What does it mean for the yield curve to be inverted (negative 2s10s)?

    • AThat 2-year bonds yield more than 10-year ones: the market expects policy rates to fall
    • BThat 10-year bonds yield more than 2-year ones
    • CThat the central bank has raised long-term rates
    • DThat inflation is negative
    Show answer

    Answer A. That 2-year bonds yield more than 10-year ones: the market expects policy rates to fall

    Longer-term rates reflect expectations about future short-term rates plus a term premium. If the 2-year is above the 10-year, the market is pricing in future cuts to the policy rate, typically because it expects a slowdown.

  4. A short-term interest rate future trades at 96.25. What interest rate does it imply?

    • A96.25%
    • B3.75%
    • C6.25%
    • D0.9625%
    Show answer

    Answer B. 3.75%

    By convention, these futures are quoted as 100 minus the rate: 100 − 96.25 = 3.75%. If the market expects higher rates, the future's price falls, like a bond's.

  5. According to the national authorities' analyses cited by ESMA in 2018, what percentage of retail CFD accounts lost money?

    • ABetween 10% and 20%
    • BAround 50%
    • CMore than 99%
    • DBetween 74% and 89%
    Show answer

    Answer D. Between 74% and 89%

    In March 2018 ESMA cited that, according to the national authorities' analyses, between 74% and 89% of retail CFD accounts lost money, with average losses per client of 1,600 to 29,000 euros. That is why it limited leverage and required every provider to publish that percentage.

Key points

  • A bond's price is the present value of its coupons and its principal. Yield and price move in opposite directions.
  • Modified duration gives the price's sensitivity to rates (−D × Δy) and DV01, how much is gained or lost per basis point. Convexity corrects the approximation for large moves.
  • The yield curve reflects expectations about the policy rate plus a term premium. In Valdoria it was inverted for 671 sessions, from June 2022 to February 2025.
  • Short-term interest rate futures are quoted as 100 minus the rate; bond futures, on a notional bond (Eurex's Bund, 100,000 EUR with a 6% coupon).
  • A CFD is a contract with the provider as counterparty: it replicates the underlying's price with margin and charges financing every night. ESMA limits its leverage for retail clients and requires close-out at 50% of margin.

Resources