ores.trading.bond_issue
Table of Contents
- 1. Flags
- 2. Columns
- 2.1. issue_id
- 2.2. security_id
- 2.3. issuer
- 2.4. face_value
- 2.5. issue_date
- 2.6. settlement_days
- 2.7. calendar
- 2.8. credit_curve_id
- 2.9. reference_curve_id
- 2.10. income_curve_id
- 2.11. credit_group
- 2.12. volatility_curve_id
- 2.13. price_quote_method
- 2.14. price_quote_base_value
- 2.15. sub_type
- 2.16. price_type
- 2.17. payer
- 2.18. credit_risk
- 3. SQL
- 4. Insert trigger
- 5. Delete cascade
- 6. C++
- 7. See also
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
- ores.trading — component group overview.