How AllInvestView Prices Bonds: Inside the Engine

Cashflows, central-bank yield curves, and implied-spread calibration at the trade date — the engine behind your daily bond prices.

14 min read

1. How we price a bond every day

Every night the engine walks each active bond through five steps: generate the cashflow schedule from your coupon and dates, solve YTM from your purchase price, look up the matching central-bank benchmark yield at the trade-date tenor, calibrate the implied spread, and discount tomorrow's cashflows at the current benchmark plus that stored spread to produce a theoretical price.

The two formulas that drive everything

implied_spread = YTM_at_purchase - benchmark(tenor, trade_date)
theoretical_today = PV( cashflows discounted at benchmark(tenor, today) + implied_spread )

Worked example: a 5-year corporate at 102.50

1
You buy: a 4.5% coupon corporate bond at Clean price 102.50, trade date today.
2
YTM solver: adds accrued, solves for yield. Output: 4.05%.
3
Curve lookup: USD Treasury 5Y on trade date is 3.65%.
4
Spread calibration: 4.05% - 3.65% = 0.40%, stored as implied_spread = 40 bps.
5
Tomorrow's reprice: USD Treasury 5Y moved to 3.78%. Theoretical = PV of cashflows discounted at 3.78% + 0.40% = 4.18%. Output: ~101.95.
+40 bps
implied spread, calibrated once at trade date

Under the hood: cashflows and the YTM solver

Cashflow generation walks from issue_date to maturity_date applying the frequency and day-count convention. Each coupon period accrues at coupon_rate / frequency on the face value, weighted by the day-count rule. The final period repays principal. Stub periods live at one end (Upfront for most US corporates, Backend for some European issuers). Zero-coupon bonds get a single terminal cashflow. Perpetuals are handled as a separate class rather than being integrated to infinity.

The YTM solver uses Newton-Raphson as the primary method, falling back to brentq (bracket-and-bisect) when Newton stalls or returns a yield outside an economic acceptance band of roughly minus 50% to plus 50%. Distressed and deeply premium bonds that would defeat a single-method solver still resolve through the bracket-and-bisect path.

Clean and Dirty round-trip symmetry

For a Clean-quoted bond, the YTM solver adds accrued interest before solving; for a Dirty-quoted bond it uses the input price directly. The reprice path mirrors the symmetry, subtracting accrued for Clean and leaving it in for Dirty. Either way, calibrating against the input price and immediately repricing against the same curve returns the input price.

2. Yield curves and the shifted-curve mechanism

Stored as (curve, tenor_months, date, yield_value) and interpolated on lookup. Sources by currency:

CurrencySourceTenors storedCadence
USDU.S. Treasury Daily Yield Curve13 pillars: 1/2/3/4/6 month + 1/2/3/5/7/10/20/30 yearDaily
EURECB AAA par curve + 7 country shifts3M-30Y AAA daily; per-country 10Y dailyDaily
GBPBank of England gilt yields5Y, 10Y, 20YDaily
CADBank of CanadaOvernight CORRA, 1M/2M/3M/6M T-bills, 1Y/2Y/3Y/5Y/7Y/10Y T-bonds, long bondDaily
AUDRBA F2 (primary) plus OECD STES (fallback)RBA: 2Y/3Y/5Y/10Y; OECD fallback: 1M cash, 3M interbank, 10Y govtDaily / monthly

For curve fundamentals see the Yield Curve Calculator.

The shifted-curve mechanism for EU sovereigns

The ECB publishes the AAA par curve at full tenor but only the 10Y point per country. Italian, Spanish, French, Portuguese, Irish, Greek, and Belgian government bonds trade at persistent positive premiums to AAA, so pricing them off pure AAA would systematically undervalue. The shifted curve anchors at the 10-year point:

Country-shifted curve

country_curve(tenor, t) = ECB_AAA(tenor, t) + (country_10Y(t) - ECB_AAA_10Y(t))
The shape comes from the AAA curve; the level comes from the country's own 10Y. Shifted curves are stored for IT, ES, FR, PT, IE, GR, BE. Bunds route directly to AAA, which tracks the Bund curve.

All seven country 10Y points come from a single batched HTTP call to the ECB statistical data warehouse, keyed by ISO country code. When a date is missing for a country, the shifted-curve lookup falls back to plain AAA at the requested tenor rather than refusing to price.

Sovereign detection is a four-layer hybrid: ISIN prefix fast-path when issuer is empty, generic sovereign tokens ("republic of", "treasury", "kingdom of"), quasi-sovereign tokens (KfW, EIB, German Pfandbriefe) that route sovereign-like, and per-country tokens that disambiguate within EUR. The token list is intentionally conservative: a misclassified corporate routed to a sovereign curve would understate spread.

AUD: govt-only primary with documented basis risk on the fallback

RBA Table F2 (four government tenors, daily) is primary. When F2 is unreachable, the engine falls back to OECD STES, which publishes three Australian series of mixed character:

  • 1-month proxy: RBA cash rate target (monetary policy rate)
  • 3-month proxy: BBSW interbank rate (bank credit, not government)
  • 10-year: government bond yield

Basis risk on the AUD fallback

The 1-month and 3-month points are not government bond yields. Mixing them with the 10Y govt point introduces a small basis at the short end: typically 5-30 basis points in calm regimes, materially wider in funding stress. The source is stamped on every stored row, so fallback-priced AUD bonds can be identified after the fact. For the broader framing of where basis risk hits a bond portfolio, see Basis Risk for Bond Investors.

Storage and self-healing

Each (curve, tenor, date) row is unique; re-runs do not duplicate. When the bond report needs a curve for a date that is not cached, the lookup calls the registered fetcher and writes the data in line, so a stale curve self-heals on the next read.

Bad data is rejected at the fetch boundary: yields outside [-2%, +25%] are dropped, and upstream schema changes abort the batch rather than write rows under a wrong schema.

3. The implied spread: what it captures

The spread number we calibrate is an implied I-spread: a single-point benchmark match between your bond's YTM at purchase and the matching central-bank curve point on that date. Bond Spread Calculator covers how I-spread compares to Z-spread and OAS.

Freezing it at trade date separates two risks:

  • Rate risk: how the benchmark curve moves day to day. Captured automatically by the nightly reprice.
  • Credit risk: the premium you locked in for taking on the issuer's specific creditworthiness. Captured in the stored spread.

The engine measures your credit premium at the moment of purchase, not today's market credit premium. The two diverge as the issuer's situation evolves: downgrades, distress, sector repricing. Edit Spread lets you re-anchor explicitly, or back-solve from a current market price.

The stored spread persists, with three documented exceptions:

  • You override it via Edit Spread. The override is flagged so subsequent re-anchoring migrations skip your bond.
  • An operator runs a country-curve migration that re-anchors non-user-overridden EUR sovereign bonds onto the country-shifted curve. The prior spread is snapshotted for audit.
  • The stored value drifts to an unreasonable range on the next reprice. The engine recalibrates against the current curve and writes the corrected value, self-healing a previously poisoned spread.

4. Daily repricing

A scheduled job runs nightly, iterating active bonds (type = Bond, maturity in the future, valid metadata). For each user it pre-warms the set of curves needed by that user's bonds (including the AAA parent for any country-shifted curve), then walks the bonds one at a time. Each call lazy-fetches the curve if stale, reprices the bond, and saves the result so downstream caches refresh.

For multi-lot positions (same ISIN held across several trade lots), one lot is designated the anchor. The anchor's reprice runs through the full pipeline; the resulting theoretical price propagates to the other lots in bulk.

If a curve source has a transient outage, the bond's theoretical price blanks for the night with a tooltip explaining the source is temporarily unavailable, and the engine retries automatically on the next run. YTM and duration continue to display from the bond's own cashflows in the meantime — the rate-sensitivity numbers stay on the page even when the rate environment hasn't refreshed yet.

5. What you control

Edit Spread

The Edit Spread modal on every bond row lets you set the implied spread directly in basis points or paste a target market price so the engine back-solves the spread for you. The override is flagged so subsequent re-anchoring migrations skip your bond and your value persists.

One caveat for currencies with single-tenor curves: if the bond's remaining tenor falls outside the safe window (AUD: 24-180 months), the by-price back-solve will decline because the resulting spread would be calibrated against a flat-extrapolated benchmark.

Price priority in your bond table

The Price column for each row picks the freshest credible source in this order:

  1. Broker market price: live price reported by your synced broker, when fresher than 7 days.
  2. Market price: for bonds we cover in our market data, the latest daily quote when fresher than 7 days. Covers users without a broker sync.
  3. Theoretical price: our nightly-computed value, when calibration succeeded.
  4. Purchase price: your original input, always available as a floor.

YTM and duration are computed against whichever price is current. Each number is labelled with its source. Daily change is suppressed when a non-theoretical price is in use to avoid phantom moves from the source switch.

Freshness honesty on the market quote

The freshness date we use to gate the market quote is the date our data feed refreshed successfully, not the date of the underlying trade. For an illiquid bond that did not trade today, the feed can still carry the latest available quote and stamp it with today's date. Liquid bonds reflect today's market; illiquid bonds may carry a quote from earlier in the week with a current freshness stamp.

Manual reprice

The Reprice button forces a curve refresh and per-bond recalculation without waiting for the nightly. Useful after editing a coupon or maturity date, or after a curve source has recovered from an outage.

6. What we don't model

  • Callable and putable bonds: priced as if straight to maturity. No option-adjusted spread, no short-rate model (Hull-White, Black-Karasinski) to value the embedded option. The theoretical price will systematically overvalue callable bonds when they are trading near or above the call price.
  • Convertible bonds: not modeled. The equity-option leg requires Black-Scholes or a tree model; not yet supported.
  • Floating-rate notes (FRNs): treated as fixed-rate at the current coupon. Forward-curve projection of future coupon resets is not implemented.
  • Real-time credit spread feeds: not implemented. The implied spread is what you calibrated at purchase, not today's market spread.
  • Borrowed-shape curves for low-coverage currencies: CHF, JPY, NZD, NOK, SEK, DKK, MXN and similar currencies are deferred pending user demand. Bonds in those currencies show YTM and duration from cashflows but no live curve-based theoretical price.
  • SGD: no usable public curve. Singapore is not in OECD STES and MAS does not publish a comparable daily feed. Holders see YTM and duration from cashflows; the Spread cell stays blank with a tooltip naming the currency.

The callable case

If you hold a US corporate that is callable in 2 years and trades at 105, our theoretical will use the stated maturity (say 10 years) and overstate value relative to a yield-to-worst calculation a desk would run. Edit Spread by market price is the workaround until OAS support is added.

7. Reference: full inputs and outputs schema

Inputs (per bond)

FieldUsed by
isinIssuer / sovereign detection, curve routing
issuer, nameSovereign token matching, label rendering
coupon_rateCashflow schedule
issue_date, maturity_dateTenor, accrual periods
frequency (Annual, Semi, Quarterly)Coupon period length
rate_convention (30/360, ACT/365, ACT/ACT)Day-count weighting
stub_period (Upfront, Backend)Stub coupon placement
quotation (Clean, Dirty)YTM solver input handling
face_value, lot_sizeCashflow notional scaling, position value
currencyCurve routing
price (purchase), trade_dateYTM at purchase, spread calibration

Outputs (per bond, recomputed nightly)

FieldHow
ytmNewton-Raphson with brentq fallback over the cashflows
duration, convexityModified duration and dollar convexity from the same cashflows
current_yield, accrued_interestCoupon over price; accrual since last coupon
implied_spread (bps)YTM at trade-date minus benchmark yield at the matching tenor
theoretical_pricePresent value of cashflows discounted at (today's benchmark + stored spread)
benchmark_curveThe curve identifier (e.g. USD_UST, EUR_IT)

Scale note: the YTM solver works in price-as-percent-of-face, so face values of 100 (typical sovereign), 1,000 (typical US corporate), or 1.0 (a wrapped-fund unit) all produce the same per-100 theoretical. lot_size applies downstream at the position-value layer, not inside the solver.

8. Frequently asked questions

How does AllInvestView price bonds every day?
A nightly job fetches central-bank yield curves, applies each bond's stored implied spread to the current curve, and recomputes a theoretical price. Every active bond on the platform is repriced and your dashboard reflects the new value on the next visit.
What yield curve sources power the engine?
U.S. Treasury (Daily Yield Curve, 13 pillars from 1M to 30Y), ECB AAA par curve (3M-30Y), Bank of England gilt yields (5Y/10Y/20Y), Bank of Canada (overnight CORRA through long bond), and RBA F2 for Australian government bonds with an OECD STES fallback. Seven country-shifted variants cover IT, ES, FR, PT, IE, GR, BE sovereigns; German Bunds use ECB AAA directly.
What is the implied spread and why is it frozen at the trade date?
Implied spread is YTM at purchase minus benchmark yield at the matching tenor. Freezing it separates your locked-in credit premium from daily rate moves and avoids depending on a live credit-spread feed. It falls out of frozen only if you override it via Edit Spread, an operator runs a country-curve migration on EUR sovereigns, or the stored value drifts to an unreasonable range and the engine self-heals on the next reprice.
Do you handle callable, putable, or convertible bonds?
Not yet. Callable and putable bonds are priced as if straight to maturity, with no option-adjusted spread. Convertibles and floating-rate notes are not modeled. The limitations are documented here rather than hidden behind a number that looks confident.
Can I override the spread or theoretical price for my bond?
Yes. The Edit Spread modal on any bond row lets you set the implied spread directly in basis points or paste a target market price so we back-solve the spread. The override is flagged so subsequent re-anchoring migrations skip your bond. In the display column we automatically prefer your synced-broker quote when fresher than 7 days, then the market quote from our market data coverage, otherwise the theoretical. Daily change is suppressed when a non-theoretical price is in use to avoid stale-versus-fresh mismatches.
What happens if a central-bank curve feed goes down?
YTM and duration keep displaying from the bond's own cashflows. The theoretical price blanks with a tooltip explaining the source is temporarily unavailable, and the bond auto-retries on the next nightly run without operator intervention. For AUD specifically, an OECD STES fallback kicks in when RBA F2 is unreachable, with documented basis risk on the short end.

See the engine on your own bonds

Import your fixed-income positions and watch the daily theoretical price, YTM, spread, and duration update against live central-bank yield curves.

Start Free View Bond Report