Case 922

The safe bond lost a sixth when rates rose

the_safe_bond_lost_a_sixth_when_rates_rose.eml - A saver buys a ten-year government bond as the safe part of the portfolio, the issuer will certainly pay every coupon and the principal, and the statement a year later shows the bond down sixteen percent. What a bond's price answers to is computed below.

ok: true — round-trip fixpoint reached (python1 == python2)updated 2026-09-19

EML

eml
# Self-authored for the EML case corpus (no external origin). A saver buys a
# ten-year government bond as the safe part of the portfolio, the issuer will
# certainly pay every coupon and the principal, and the statement a year later
# shows the bond down sixteen percent. What a bond's price answers to is
# computed below.
#
# The choice is careful. The issuer is genuinely risk-free; every coupon is paid
# on time; the bond will return its full principal at maturity; and the intent is
# exactly 'the part of the portfolio that does not lose value'.
#
# A bond's price is what its fixed coupons are worth against the rates now on
# offer, and rates rose from two percent to four, so a bond paying two percent
# for nine more years is worth sixteen percent less to anyone buying it today -
# nothing about the issuer changed.

10000 => face_value
2 => coupon_percent
4 => market_rate_now_percent
9 => years_remaining
8380 => market_price_now

int(face_value * coupon_percent / 100) => coupon_per_year
face_value - market_price_now => loss_if_sold_now
int(loss_if_sold_now * 10000 / face_value) => loss_per_myriad
int(loss_if_sold_now / coupon_per_year) => years_of_coupons_to_recover_the_loss
coupon_per_year * years_remaining + face_value => total_the_bond_will_pay_if_held

"face value                      : " + str(face_value) ^0
"coupon                          : " + str(coupon_percent) + " percent, " + str(coupon_per_year) + " a year" ^0
"issuer default risk             : none" ^0
"" ^0
"market rate now                 : " + str(market_rate_now_percent) + " percent" ^0
"market price now                : " + str(market_price_now) ^0
"loss if sold now                : " + str(loss_if_sold_now) + ", " + str(loss_per_myriad) + " per ten thousand" ^0
"years of coupons to recover it  : " + str(years_of_coupons_to_recover_the_loss) ^0
"total paid if held to maturity  : " + str(total_the_bond_will_pay_if_held) ^0
"" ^0

# ---- what the choice verified ----

"the safe asset" ^0
"  issuer : genuinely risk-free" ^0
"  coupons : every one paid on time" ^0
"  principal : returned in full at maturity" ^0
"  intent : the part of the portfolio that does not lose" ^0
"    value" ^0
"  missed payments : 0" ^0
"  verdict : THE ISSUER WILL PAY EVERYTHING IT OWES" ^0
"" ^0
"  choosing an issuer that certainly pays is the part done" ^0
"  right here, and it is why " + str(total_the_bond_will_pay_if_held) + " will arrive if the bond" ^0
"  is held" ^0
"" ^0

# ---- what a bond's price answers to ----

"price and rates" ^0
"  what the bond pays : " + str(coupon_per_year) + " a year for " + str(years_remaining) + " more years, then " + str(face_value) ^0
"  what a new bond pays today : " + str(market_rate_now_percent) + " percent" ^0
"  so a buyer of this bond : gets half the going coupon, and" ^0
"    pays less for it - " + str(market_price_now) ^0
"  what changed : the alternative, not the bond" ^0
"  what safe meant : the issuer pays; what it did not mean :" ^0
"    the price holds" ^0
"" ^0

# ---- what the saver got ----

"the statement" ^0
"  value shown : " + str(market_price_now) + ", down " + str(loss_per_myriad) + " per ten thousand" ^0
"  is the issuer in trouble : no" ^0
"  is any coupon at risk : no" ^0
"  did the safe asset lose value : yes, to anyone selling," ^0
"    because safety was about default and the loss is" ^0
"    about rates" ^0
"" ^0

# ---- null control ----

# The same saver holding to maturity (or holding shorter bonds whose price
# answers less to rate moves), so the rate move is not realised.
1620 => nc_loss_per_myriad_if_sold_now
0 => nc_loss_per_myriad_if_held_to_maturity
1 => nc_full_principal_and_coupons_received_if_held

"null control - hold to maturity, or hold shorter" ^0
"  loss if sold now : " + str(nc_loss_per_myriad_if_sold_now) + " per ten thousand" ^0
"  loss if held to maturity : " + str(nc_loss_per_myriad_if_held_to_maturity) ^0
"  full principal and coupons received if held : " + str(nc_full_principal_and_coupons_received_if_held) ^0
"  no coupon and no issuer changed; the rate move stopped" ^0
"  being turned into a sale" ^0
"" ^0

# ---- the rule ----

"what a risk-free issuer guarantees" ^0
"  every coupon and the principal will be paid : exactly," ^0
"    the issuer's own credit" ^0
"  the bond's price will not fall : not addressed; the price" ^0
"    is the fixed coupons against today's rates, and rates" ^0
"    doubled, so the bond is worth " + str(market_price_now) + " to a buyer now - " + str(loss_per_myriad) + " per" ^0
"    ten thousand below face, " + str(years_of_coupons_to_recover_the_loss) + " years of coupons" ^0
"" ^0

"safe names who will pay, and price names what someone else will pay; a" ^0
"promise that is certain can still be worth less than it was when a better" ^0
"promise appears beside it, and the statement prices the comparison" ^0
"" ^0

"The issuer will pay every coupon and the full " + str(face_value) + " - the bond is safe from" ^0
"default. But rates rose from " + str(coupon_percent) + " to " + str(market_rate_now_percent) + " percent, so its fixed " + str(coupon_per_year) + " a year is worth" ^0
"" + str(market_price_now) + " to a buyer today, " + str(loss_per_myriad) + " per ten thousand below face and " + str(years_of_coupons_to_recover_the_loss) + " years of coupons to" ^0
"recover, until safe is read as default risk and not as price." ^0

Python (deterministic transpilation)

python
face_value = 10000
coupon_percent = 2
market_rate_now_percent = 4
years_remaining = 9
market_price_now = 8380
coupon_per_year = int(face_value * coupon_percent / 100)
loss_if_sold_now = face_value - market_price_now
loss_per_myriad = int(loss_if_sold_now * 10000 / face_value)
years_of_coupons_to_recover_the_loss = int(loss_if_sold_now / coupon_per_year)
total_the_bond_will_pay_if_held = coupon_per_year * years_remaining + face_value
print("face value                      : " + str(face_value))
print("coupon                          : " + str(coupon_percent) + " percent, " + str(coupon_per_year) + " a year")
print("issuer default risk             : none")
print("")
print("market rate now                 : " + str(market_rate_now_percent) + " percent")
print("market price now                : " + str(market_price_now))
print("loss if sold now                : " + str(loss_if_sold_now) + ", " + str(loss_per_myriad) + " per ten thousand")
print("years of coupons to recover it  : " + str(years_of_coupons_to_recover_the_loss))
print("total paid if held to maturity  : " + str(total_the_bond_will_pay_if_held))
print("")
print("the safe asset")
print("  issuer : genuinely risk-free")
print("  coupons : every one paid on time")
print("  principal : returned in full at maturity")
print("  intent : the part of the portfolio that does not lose")
print("    value")
print("  missed payments : 0")
print("  verdict : THE ISSUER WILL PAY EVERYTHING IT OWES")
print("")
print("  choosing an issuer that certainly pays is the part done")
print("  right here, and it is why " + str(total_the_bond_will_pay_if_held) + " will arrive if the bond")
print("  is held")
print("")
print("price and rates")
print("  what the bond pays : " + str(coupon_per_year) + " a year for " + str(years_remaining) + " more years, then " + str(face_value))
print("  what a new bond pays today : " + str(market_rate_now_percent) + " percent")
print("  so a buyer of this bond : gets half the going coupon, and")
print("    pays less for it - " + str(market_price_now))
print("  what changed : the alternative, not the bond")
print("  what safe meant : the issuer pays; what it did not mean :")
print("    the price holds")
print("")
print("the statement")
print("  value shown : " + str(market_price_now) + ", down " + str(loss_per_myriad) + " per ten thousand")
print("  is the issuer in trouble : no")
print("  is any coupon at risk : no")
print("  did the safe asset lose value : yes, to anyone selling,")
print("    because safety was about default and the loss is")
print("    about rates")
print("")
nc_loss_per_myriad_if_sold_now = 1620
nc_loss_per_myriad_if_held_to_maturity = 0
nc_full_principal_and_coupons_received_if_held = 1
print("null control - hold to maturity, or hold shorter")
print("  loss if sold now : " + str(nc_loss_per_myriad_if_sold_now) + " per ten thousand")
print("  loss if held to maturity : " + str(nc_loss_per_myriad_if_held_to_maturity))
print("  full principal and coupons received if held : " + str(nc_full_principal_and_coupons_received_if_held))
print("  no coupon and no issuer changed; the rate move stopped")
print("  being turned into a sale")
print("")
print("what a risk-free issuer guarantees")
print("  every coupon and the principal will be paid : exactly,")
print("    the issuer's own credit")
print("  the bond's price will not fall : not addressed; the price")
print("    is the fixed coupons against today's rates, and rates")
print("    doubled, so the bond is worth " + str(market_price_now) + " to a buyer now - " + str(loss_per_myriad) + " per")
print("    ten thousand below face, " + str(years_of_coupons_to_recover_the_loss) + " years of coupons")
print("")
print("safe names who will pay, and price names what someone else will pay; a")
print("promise that is certain can still be worth less than it was when a better")
print("promise appears beside it, and the statement prices the comparison")
print("")
print("The issuer will pay every coupon and the full " + str(face_value) + " - the bond is safe from")
print("default. But rates rose from " + str(coupon_percent) + " to " + str(market_rate_now_percent) + " percent, so its fixed " + str(coupon_per_year) + " a year is worth")
print("" + str(market_price_now) + " to a buyer today, " + str(loss_per_myriad) + " per ten thousand below face and " + str(years_of_coupons_to_recover_the_loss) + " years of coupons to")
print("recover, until safe is read as default risk and not as price.")

stdout (executed)

text
face value                      : 10000
coupon                          : 2 percent, 200 a year
issuer default risk             : none

market rate now                 : 4 percent
market price now                : 8380
loss if sold now                : 1620, 1620 per ten thousand
years of coupons to recover it  : 8
total paid if held to maturity  : 11800

the safe asset
  issuer : genuinely risk-free
  coupons : every one paid on time
  principal : returned in full at maturity
  intent : the part of the portfolio that does not lose
    value
  missed payments : 0
  verdict : THE ISSUER WILL PAY EVERYTHING IT OWES

  choosing an issuer that certainly pays is the part done
  right here, and it is why 11800 will arrive if the bond
  is held

price and rates
  what the bond pays : 200 a year for 9 more years, then 10000
  what a new bond pays today : 4 percent
  so a buyer of this bond : gets half the going coupon, and
    pays less for it - 8380
  what changed : the alternative, not the bond
  what safe meant : the issuer pays; what it did not mean :
    the price holds

the statement
  value shown : 8380, down 1620 per ten thousand
  is the issuer in trouble : no
  is any coupon at risk : no
  did the safe asset lose value : yes, to anyone selling,
    because safety was about default and the loss is
    about rates

null control - hold to maturity, or hold shorter
  loss if sold now : 1620 per ten thousand
  loss if held to maturity : 0
  full principal and coupons received if held : 1
  no coupon and no issuer changed; the rate move stopped
  being turned into a sale

what a risk-free issuer guarantees
  every coupon and the principal will be paid : exactly,
    the issuer's own credit
  the bond's price will not fall : not addressed; the price
    is the fixed coupons against today's rates, and rates
    doubled, so the bond is worth 8380 to a buyer now - 1620 per
    ten thousand below face, 8 years of coupons

safe names who will pay, and price names what someone else will pay; a
promise that is certain can still be worth less than it was when a better
promise appears beside it, and the statement prices the comparison

The issuer will pay every coupon and the full 10000 - the bond is safe from
default. But rates rose from 2 to 4 percent, so its fixed 200 a year is worth
8380 to a buyer today, 1620 per ten thousand below face and 8 years of coupons to
recover, until safe is read as default risk and not as price.

Trace event types

eml:run:starteml:assigneml:outputeml:run:done