ores.trading.bond_issue

Table of Contents

One row per bond issue (ISIN), the stable row every instrument of the family references. The columns map from bondReferenceDatum (referencedata.xsd lines 97-113): security_id, issuer, the three curve identifiers, the six fields beside them, issue date, settlement days and calendar. Only IssuerId is required by that schema; every other element is optional, so every other column is nullable and an absent element is stored as NULL rather than as an empty string or a zero.

The bond's coupon terms are not here. ORE states them on legData alone – bondReferenceDatum carries no coupon rate, coupon frequency, day counter or currency – and the security's legs are bond_issue_leg and its children, so the leg holds them once and this row is not a second copy.

face_value is the issue's per-unit value and repeats the first leg's notional. It stays because a row set that holds an issue and no legs still has to export a leg, and it is what that leg's notional is built from.

Two columns come from the trade's own copy of the datum and not from bondReferenceDatum: payer and credit_risk are bondData's top-level members (instruments.xsd lines 404 and 406), which the reference datum does not state. They live here because bondData is the trade's copy of the issue's terms and every other member of it is already mapped to this row, so leaving the two out would drop them from the round trip.

1. Flags

2. Columns

2.1. issue_id

UUID uniquely identifying this bond issue.

Surrogate key of the issue row. Instrument rows and the issue's own child rows reference it; the row is stable while instruments open against it are amended.

2.2. security_id

ISIN or other security identifier of the issue.

Unique among the current rows of a tenant (the partial unique index below). The deduplication key of the migration: one issue row per ISIN, shared by every trade of it.

std::string("US9128283M42")

2.3. issuer

Issuer of the bond.

std::string("US Treasury")

2.4. face_value

Face value per unit of the bond.

ores::utility::decimal::decimal::from_string("1000").value()

2.5. issue_date

Issue date of the bond (ISO 8601 date string).

std::chrono::year_month_day{std::chrono::year{2024}/1/15}

2.6. settlement_days

Settlement days of the bond, a market convention of the issue.

2

2.7. calendar

Calendar the issue's dates are adjusted against, when the document states one at the bond level rather than on a leg.

2.8. credit_curve_id

Credit curve the document names for the issue.

2.9. reference_curve_id

Reference curve the issue is discounted on, as the oresmd URI of the market series that curve is. ORE names a curve its own way, and one index has more than one spelling (refdata holds EUR-ESTR while the market's own forwarding names EUR-ESTER), so the row keeps our name and the export translates it to ORE's. The URI is the series' natural key, the same string in every environment; the series' id is a surrogate, and a row that kept one would name nothing in the next environment the data is loaded into.

A generated population writes the curve its book's currency is discounted on, which the entity declares per currency on the trade generation config: which index a bond discounts on is a fact about the trade. A value naming no curve series of the tenant and party is refused at write time, by the validation below. The series is scoped to the party because one curve id is defined once per entity and each entity holds its own series.

2.10. income_curve_id

Income curve the document names for the issue.

2.11. credit_group

Credit group the document names for the issue.

2.12. volatility_curve_id

Volatility curve the document names for the issue.

2.13. price_quote_method

Price quote method the document states for the issue.

2.14. price_quote_base_value

Price quote base value the document states for the issue.

The column is decimal because the base value is money. The schema spells it as text and the mapper parses those digits.

2.15. sub_type

Bond sub-type the document states for the issue.

2.16. price_type

The price type the document states.

Soft FK to ores_trading_price_types_tbl: the values are the closed ORE bondPriceType set (Clean, Dirty). PR 4 tightens the soft reference into a real foreign key.

2.17. payer

The payer the document states for the bond itself, when it states one.

bondData carries a top-level Payer beside each leg's own, and the two are separate elements: this column is the datum's, and ores.trading.bond_issue_leg.payer is the leg's. bondReferenceDatum, which the issue otherwise models, states neither.

2.18. credit_risk

The credit-risk flag the document states for the issue, when it states one.

bondData's CreditRisk is ORE's loose bool, whose thirteen spellings include the empty element the schema writes for true, so the column holds the spelling as text the way end_of_month does. bondReferenceDatum states no such element.

3. SQL

3.1. Flags

3.2. Checks

Each check holds only for a value the document stated. An absent value is NULL, and a NULL comparison passes, so an issue that states no face value is admitted while a stated non-positive one is not. The empty-string checks went with the columns that needed them: absence is now NULL, not an empty string.

expression
"face_value" > 0
"price_type" is null or "price_type" in ('Clean', 'Dirty')

3.3. Indexes

The index serves the lookup an import makes, and it is not unique: one security id may carry more than one issue, because ORE's own example corpus states one SecurityId for trades whose terms differ. An import keeps the issue whose terms the trade agrees with and mints another when it agrees with none, so the uniqueness the migration relied on is the importer's to hold, not the table's.

name columns unique current_only where_extra
security tenant_id, security_id false true  

4. Insert trigger

4.1. Validations

The reference curve crosses a component: the series it names belongs to market data, so the function that knows the catalogue lives there and the trading insert calls it.

column validation_function
reference_curve_id ores_marketdata_validate_curve_series_fn

5. Delete cascade

The rows a bond issue owns. Each is keyed by the issue, so the delete rule closes them when the issue goes. The issue goes only when its last instrument does (bond_instrument's :cascade_orphan: on issue_id), so a shared issue and its legs are not taken from an instrument still holding them.

5.1. bond_issue_legs

5.2. bond_issue_leg_amounts

5.3. bond_issue_leg_rates

5.4. bond_issue_leg_amortizations

5.5. bond_issue_leg_schedules

5.6. bond_issue_leg_schedule_dates

5.7. bond_issue_call_dates

5.8. bond_issue_conversion_targets

6. C++

6.1. Flags

6.2. Repository

6.3. Domain includes

#include <optional>
#include <string>
#include <boost/uuid/uuid.hpp>
#include "ores.utility/decimal/decimal.hpp"

6.4. Conventions

6.5. Table display

column header
security_id ISIN
issuer Issuer
modified_by Modified By
version Version

6.6. Custom repository methods

7. See also

Emacs 29.3 (Org mode 9.6.15)