HEDGEFUND.md

Models / Macro / rates_ladder

Rates ladder

What would this bond ladder earn over the horizon on these yields, what does a parallel shift do to it, and what shift takes the return to zero?

Prices a ladder of fixed coupon bonds from the yields sent: dirty and clean price, Macaulay and modified duration, convexity, DV01, a shock table of full repricing against the duration and convexity estimate, carry and roll-down over a horizon, and the parallel shift that takes the horizon return to zero. Yields come from the caller. It is arithmetic on those numbers, not a view on rates.

The paste-ready promptmodel.md

On these numbers, the ladder is worth 4983423.61 with a DV01 of 1909.3. Over 0.5 years its hypothetical return is 2.42% with roll-down and no shift, and a parallel rise of 72.04 bps at the horizon takes that to zero.

Hypothetical, and on made-up numbers until you replace them. Nobody traded this, and nothing here is on offer.

Readings

The numbers, with their units.

Dirty value

4,983,424

Clean 4974673.61, accrued 8750.

Modified duration

3.8313years

Value-weighted. Macaulay 3.93.

DV01

1,909.3

Value change for 1 bp, on dirty value.

Convexity

23.97

Value-weighted.

Coupon carry over the horizon

2.107%of dirty value

Roll-down over the horizon

0.2404%of dirty value

From the curve sent, with each bond's gap to the curve held.

Hypothetical horizon return

2.4215%

Over 0.5 years, not annualized. Includes pull to par of 0.07%.

Shift that takes it to zero

72.04bps

What flips it

The value of one input where the outcome changes, with the others held.

  1. parallel_shift_bps

    72.04

    A parallel yield move of this size at the horizon takes the ladder's 0.5-year return to zero, found by repricing every flow. Past it, toward higher yields, the return is negative.

What this leaves out

What the formula leaves out, by name.

  • Reinvestment of coupons and of any principal paid back inside the horizon.
  • Moves that aren't parallel, other than the one roll-down path.
  • Default, calls, amortization, inflation links and floating coupons.
  • Day counts, settlement lags and holiday calendars.
  • Repo or other financing of the ladder, bid-ask, fees and taxes.
What it took as given (9)

What it took as given to get here.

  • Time is in plain years, and flows are counted back from maturity. A fraction of a period at the front is a stub.
  • The stub is discounted with a fractional exponent, and accrued interest is straight-line across the coupon period.
  • DV01, duration and convexity are on the dirty price. Convexity includes the 1 / f term that goes with periodic compounding.
  • Each bond's yield shifts by the same amount in a shock. Book totals add the bonds, so book duration and convexity are value-weighted.
  • Coupon carry is the coupon earned over the horizon on an accrual basis: coupons paid plus the change in accrued.
  • Pull to par is the rest of the horizon return at unchanged yield.
  • Roll-down moves each bond's yield by the curve's change from maturity to shortened maturity, by straight-line interpolation, flat past the ends. The bond's own gap to the curve stays the same.
  • Cash paid inside the horizon sits idle, with no reinvestment. Horizon returns aren't annualized.
  • The shift that flips the horizon return is applied at the horizon date, on top of roll-down, and found by repricing every flow.
Cash paid by yearAmount
00.5M1M12345678910Year
The data
Book change by shock: full reprice and estimateChange in value
  • Full reprice
  • Duration and convexity
-200K0200K-100-50050100150200Shock, bps-359,231
The data

Bonds, prices per 100 of face

namedirty_per_100accrued_per_100clean_per_100macaulay_yearsmodified_yearsconvexitydv01
Bond 1.25y100.390.87599.511.22431.20092.051120.55
Bond 2.5y99.76099.762.40372.35546.8329234.99
Bond 3.75y98.97098.973.49933.462113.38342.63
Bond 5y10001004.58754.3924.47439
Bond 10y99.22099.227.98017.781773.44772.13
Book99.670.17599.493.93223.831323.971,909.3

Parallel shocks to the book: full reprice against the estimate

shock_bpsfull_changeestimate_changegapduration_only_changefull_change_pct
-100197,073196,903169.87190,9303.9546
-5096,979.296,958.2320.9795,464.981.946
50-93,992.19-93,971.73-20.46-95,464.98-1.8861
100-185,119-184,957-161.72-190,930-3.7147
200-359,231-357,968-1,263.24-381,860-7.2085

Over the horizon of 0.5 years, money amounts

namecoupon_carrypull_to_parroll_downtotalreturn_pctyield_move_bps
Bond 1.25y17,5001,905.731,098.1220,503.852.0425-15
Bond 2.5y20,000451.761,901.5622,353.312.2406-10
Bond 3.75y20,0001,284.592,254.8923,539.482.3785-7.5
Bond 5y22,500-247.583,004.6825,257.12.5257-7.5
Bond 10y25,000302.173,719.4429,021.622.9249-5
Book105,0003,696.6611,978.69120,6752.4215n/a

Hypothetical, computed from the numbers sent and any stated default, with hindsight. Nobody traded it, and costs and liquidity are only as assumed. Not a forecast, a recommendation, an offer, or a record of real trading. Don't use it to market an investment.

formula Flows at t_k = maturity - k / f. Dirty = sum CF_k / (1 + y / f)^(f t_k). Accrued = coupon per period * (1 - f * first t). Macaulay = sum t PV / dirty. Modified = Macaulay / (1 + y / f). Convexity = sum t (t + 1 / f) PV / dirty / (1 + y / f)^2. DV01 = modified * dirty * 0.0001. Estimate = dirty (-modified s + 0.5 convexity s^2). Horizon value = sum over flows after H of CF / (1 + y / f)^(f (t - H)).

inputs_hash 5357458cea2f79e7

Paste it into your agent

No connection needed. This prompt carries the method, the conventions and what this site's engine gives on the made-up numbers, so your agent can check its own work before it touches real ones. Every prompt, with its hash, is listed at /prompts.json. A copy that stays fixed for this version, for a stack to point at: /v/1.0/models/rates_ladder.md.

prompt.md
# Rates ladder: a prompt from hedgefund.mdPaste this into your AI agent. It needs no connection to hedgefund.md. An agent that can run code should write and run it, and shouldn't work a long series by hand.**Question.** What would this bond ladder earn over the horizon on these yields, what does a parallel shift do to it, and what shift takes the return to zero?## MethodFlows at t_k = maturity - k / f. Dirty = sum CF_k / (1 + y / f)^(f t_k). Accrued = coupon per period * (1 - f * first t). Macaulay = sum t PV / dirty. Modified = Macaulay / (1 + y / f). Convexity = sum t (t + 1 / f) PV / dirty / (1 + y / f)^2. DV01 = modified * dirty * 0.0001. Estimate = dirty (-modified s + 0.5 convexity s^2). Horizon value = sum over flows after H of CF / (1 + y / f)^(f (t - H)).## Conventions- Time is in plain years, and flows are counted back from maturity. A fraction of a period at the front is a stub.- The stub is discounted with a fractional exponent, and accrued interest is straight-line across the coupon period.- DV01, duration and convexity are on the dirty price. Convexity includes the 1 / f term that goes with periodic compounding.- Each bond's yield shifts by the same amount in a shock. Book totals add the bonds, so book duration and convexity are value-weighted.- Coupon carry is the coupon earned over the horizon on an accrual basis: coupons paid plus the change in accrued.- Pull to par is the rest of the horizon return at unchanged yield.- Roll-down moves each bond's yield by the curve's change from maturity to shortened maturity, by straight-line interpolation, flat past the ends. The bond's own gap to the curve stays the same.- Cash paid inside the horizon sits idle, with no reinvestment. Horizon returns aren't annualized.- The shift that flips the horizon return is applied at the horizon date, on top of roll-down, and found by repricing every flow.## Step 1: check your method on these made-up numbersThe numbers and names below are made up. They aren't market levels, typical values or anyone's real figures.```json{  "bonds": [    {      "name": "Bond 1.25y",      "face": 1000000,      "coupon_pct": 3.5,      "maturity_years": 1.25,      "yield_pct": 3.9,      "freq": 2    },    {      "name": "Bond 2.5y",      "face": 1000000,      "coupon_pct": 4,      "maturity_years": 2.5,      "yield_pct": 4.1,      "freq": 2    },    {      "name": "Bond 3.75y",      "face": 1000000,      "coupon_pct": 4,      "maturity_years": 3.75,      "yield_pct": 4.3,      "freq": 4    },    {      "name": "Bond 5y",      "face": 1000000,      "coupon_pct": 4.5,      "maturity_years": 5,      "yield_pct": 4.5,      "freq": 1    },    {      "name": "Bond 10y",      "face": 1000000,      "coupon_pct": 5,      "maturity_years": 10,      "yield_pct": 5.1,      "freq": 2    }  ],  "shocks_bps": [-100, -50, 50, 100, 200],  "horizon_years": 0.5,  "curve": [    { "years": 0.5, "yield_pct": 3.6 },    { "years": 1, "yield_pct": 3.8 },    { "years": 2, "yield_pct": 4 },    { "years": 3, "yield_pct": 4.2 },    { "years": 5, "yield_pct": 4.5 },    { "years": 10, "yield_pct": 5 }  ]}```Work them out with the method above. Yours should match these within 0.5%.- Dirty value: 4983423.6- Modified duration: 3.8313 years- DV01: 1909.2996- Convexity: 23.9715- Coupon carry over the horizon: 2.107 % of dirty value- Roll-down over the horizon: 0.2404 % of dirty value- Hypothetical horizon return: 2.4215 %- Shift that takes it to zero: 72.0433 bpsWhere the outcome flips, with the other inputs held:- parallel_shift_bps at 72.0433: A parallel yield move of this size at the horizon takes the ladder's 0.5-year return to zero, found by repricing every flow. Past it, toward higher yields, the return is negative.If yours differ, stop and tell the person which ones and by how much. Don't go on to real numbers until they match, or until the person has seen the difference. These values come from one engine and can be wrong too.## Step 2: run it on the person's numbersReplace every input with the person's own. Ask for any number you don't have, and don't invent one.## Step 3: reportGive one sentence beginning "On these numbers,", then the values, then where the outcome flips. Always add what this leaves out:- Reinvestment of coupons and of any principal paid back inside the horizon.- Moves that aren't parallel, other than the one roll-down path.- Default, calls, amortization, inflation links and floating coupons.- Day counts, settlement lags and holiday calendars.- Repo or other financing of the ladder, bid-ask, fees and taxes.## LimitsResults are hypothetical: arithmetic on the numbers given, prepared with hindsight. Nobody achieved them, and costs and liquidity are only as assumed. They aren't a forecast, a recommendation, an offer or a record of real trading. Don't say what to buy, sell or hold, and don't use them to market an investment. Whether a person may hold or trade an instrument is a legal question for counsel.Provided as is, at your own risk, by hedgefund.md, which is not a fund and isn't anyone's adviser. Version 1.0. Source: https://hedgefund.md/models/rates_ladder/prompt.md. Terms: https://hedgefund.md/terms

Call it

The same code answers on this page, over HTTP, over MCP and on your own machine, and the same inputs give the same bytes. No key, and nothing is stored. Send positions by POST or run the library, because a URL can land in a server log. model.md holds all of this for your agent.

POST the inputs to /api/v1/rates_ladder.

terminal
curl -s https://hedgefund.md/api/v1/rates_ladder \  -H 'content-type: application/json' \  -d '{"bonds":[{"name":"Bond 1.25y","face":1000000,"coupon_pct":3.5,"maturity_years":1.25,"yield_pct":3.9,"freq":2},{"name":"Bond 2.5y","face":1000000,"coupon_pct":4,"maturity_years":2.5,"yield_pct":4.1,"freq":2},{"name":"Bond 3.75y","face":1000000,"coupon_pct":4,"maturity_years":3.75,"yield_pct":4.3,"freq":4},{"name":"Bond 5y","face":1000000,"coupon_pct":4.5,"maturity_years":5,"yield_pct":4.5,"freq":1},{"name":"Bond 10y","face":1000000,"coupon_pct":5,"maturity_years":10,"yield_pct":5.1,"freq":2}],"shocks_bps":[-100,-50,50,100,200],"horizon_years":0.5,"curve":[{"years":0.5,"yield_pct":3.6},{"years":1,"yield_pct":3.8},{"years":2,"yield_pct":4},{"years":3,"yield_pct":4.2},{"years":5,"yield_pct":4.5},{"years":10,"yield_pct":5}]}' \  | jq '{summary, flags, flips, not_modeled, inputs_hash}'

Inputs

InputTypeRangeRequiredWhat it is
bondsarray1 to 40 itemsyesThe ladder, up to 40 fixed coupon bonds.
bonds[].namestringyesA label for the bond, such as Bond 5y.
bonds[].facenumber0.01 to 1000000000000yesFace amount held.
bonds[].coupon_pctnumber0 to 100yesAnnual coupon on face, in percent.
bonds[].maturity_yearsnumber0.01 to 50yesYears to maturity. Flows are counted back from it, so a fraction makes a stub.
bonds[].yield_pctnumber-5 to 60yesYield to maturity, compounded freq times a year, in percent.
bonds[].freqwhole number1 to 4yesCoupons a year: 1, 2 or 4.
shocks_bpsarray0 to 15 itemsnoParallel yield shocks to reprice, in basis points. Default -100, -50, 50, 100.
horizon_yearsnumber0.01 to 30yesYears to carry the ladder forward.
curvearray1 to 30 itemsnoOptional curve for roll-down, up to 30 points.
curve[].yearsnumber0.01 to 100yesPoint on the curve, in years.
curve[].yield_pctnumber-5 to 60yesYield at that point, in percent.

Hypothetical, and on made-up numbers until you replace them. Nobody traded this, and nothing here is on offer.

1.0Use at your own risk: hedgefund.md is not a fund, not an offer of any security, token or fund interest, and not advice. Results are hypothetical, may be wrong, and are not a record of real trading. Don't use them to market an investment. See the terms.