ores.trading.credit_instrument
Table of Contents
- 1. Flags
- 2. Columns
- 3. Foreign keys
- 4. Delete cascade
- 4.1. credit_basket_constituents
- 4.2. swap_legs
- 4.3. swap_leg_amounts
- 4.4. swap_leg_rates
- 4.5. swap_leg_amortizations
- 4.6. swap_leg_indexings
- 4.7. instrument_barriers
- 4.8. instrument_barrier_levels
- 4.9. instrument_strikes
- 4.10. instrument_schedules
- 4.11. instrument_schedule_dates
- 4.12. instrument_options
- 4.13. instrument_option_premiums
- 4.14. instrument_option_exercise_fees
- 4.15. instrument_option_payment_dates
- 4.16. instrument_option_exercise_prices
- 4.17. credit_default_swap_instruments
- 4.18. index_credit_default_swap_instruments
- 4.19. index_credit_default_swap_option_instruments
- 4.20. synthetic_cdo_instruments
- 4.21. credit_linked_swap_instruments
- 4.22. risk_participation_agreement_instruments
- 5. SQL
- 6. C++
- 7. See also
One row per credit trade, the family's own header. It holds what every product in the family states the same way: the trade it belongs to, the trade type code, the party, the activity that wrote the version, the reference entity, the instrument's start and maturity dates and its description. It holds no product economics.
The header is the family's coverage: the trade_type_code check that the
routed-instrument template generates from ores.trading.trade_type_catalogue
lists exactly the six codes the importer writes, and the two codes with no
importer, CreditDefaultSwapOption and CBO, stay out until a mapper writes them.
It is also the family's owner: the delete cascade section below names every
table the family writes, so the delete rule closes the legs, the basket and
the facts with the header and the family does not outlive it.
The products' own fields stay in their fact tables, keyed by the same trade
and joined to this row by the trade id. A fact table carries no party_id and
no trade_type_code: the header is the family's party boundary and its
routing boundary.
The dates are the family's common dates, the one set of names for the start and the maturity of every credit product. A risk participation agreement's protection start and end are those dates.
1. Flags
2. Columns
2.1. trade_type_code
Trade type code (soft FK to ores_trading_trade_types_tbl).
One of the family's codes; the coverage check the routed-instrument template generates from the trade-type catalogue lists all of them.
std::string("CreditDefaultSwap")
2.2. party_id
Party that owns this instrument. The family's party boundary: the fact and child rows carry no party of their own.
Set from session variable app.current_party_id.
2.3. trade_id
The trade this instrument belongs to, and the instrument's own key.
The trade id identifies both the trade and its instrument, so the header carries no identity of its own: this column is the key, and the trade it names gives the instrument its scope. Every fact and child row of the family names the same trade.
2.4. trade_activity_id
The activity that wrote this version.
2.5. reference_entity_id_type
What kind of identifier reference_entity_id states: the legal entity's LEI,
or an identifier the system's own data uses.
A reference is typed rather than guessed, because a credit curve named ACME
in an engine document and an LEI are different things and a column that holds
either without saying which cannot be joined to anything.
The closed set is LEI and Internal. It is a check on this column rather than a catalogue table, because the two kinds of identifier are a property of how a reference is stated and not a list the tenant curates.
std::string("LEI")
2.6. reference_entity_id
The identifier of the reference entity the risk is on, read with
reference_entity_id_type.
Every credit product states one. When the type is LEI the value is the legal entity's LEI and the soft reference below applies; when it is Internal the value is the identifier the source states, such as an engine document's credit curve or issuer id, and nothing is claimed about a legal entity.
Soft FK to the DQ lei_entity dataset when the type is LEI: the entity belongs to that dataset rather than to a trading table, so the reference is recorded rather than copied. A later change tightens it into a real foreign key once a legal entity lives in refdata.
Resolving an internal identifier into an LEI replaces both this value and its type together, so a trade states one identifier and never two.
std::string("ORESLEI0000000000001")
2.7. start_date
The instrument's start date. A risk participation agreement's protection start is this column.
Null when the product states none.
ISO 8601 date string (YYYY-MM-DD).
2.8. maturity_date
The instrument's maturity date. A risk participation agreement's protection end is this column.
Null with start_date, and for the same reason.
2.9. description
Optional free-text description.
3. Foreign keys
3.1. trade_id
The trade that carries this instrument. An instrument is written beside its trade, so a row cannot exist without one.
#include "ores.trading.api/generators/trade_generator.hpp" #include "ores.trading.core/repository/trade_repository.hpp"
{
auto anchor = ores::trading::generators::generate_synthetic_trade(ctx);
anchor.party_id = *party_ctx.party_id();
anchor.trade_type = v.identity.trade_type_code;
ores::trading::repository::trade_repository().write(party_ctx, anchor);
v.identity.trade_id = anchor.id;
}
3.2. trade_activity_id
The activity that wrote this version. A database foreign key: the activity is immutable.
#include "ores.trading.api/generators/trade_activity_generator.hpp" #include "ores.trading.core/repository/trade_activity_repository.hpp"
{
auto activity = ores::trading::generators::generate_synthetic_trade_activity(ctx);
activity.party_id = *party_ctx.party_id();
ores::trading::repository::trade_activity_repository().write(party_ctx, activity);
v.identity.trade_activity_id = activity.id;
}
4. Delete cascade
The rows a credit instrument owns. Each is keyed by the instrument's own trade id, so the delete rule closes them all with one statement per table and the family does not outlive its header.
The legs, the strikes and the schedules are the shared shapes the bond pilot and the rates family built; the credit family writes to them rather than widening them.
4.1. credit_basket_constituents
4.2. swap_legs
4.3. swap_leg_amounts
4.4. swap_leg_rates
4.5. swap_leg_amortizations
4.6. swap_leg_indexings
4.7. instrument_barriers
4.8. instrument_barrier_levels
4.9. instrument_strikes
4.10. instrument_schedules
4.11. instrument_schedule_dates
4.12. instrument_options
4.13. instrument_option_premiums
4.14. instrument_option_exercise_fees
4.15. instrument_option_payment_dates
4.16. instrument_option_exercise_prices
4.17. credit_default_swap_instruments
4.18. index_credit_default_swap_instruments
4.19. index_credit_default_swap_option_instruments
4.20. synthetic_cdo_instruments
4.21. credit_linked_swap_instruments
4.22. risk_participation_agreement_instruments
5. SQL
5.1. Flags
5.2. Checks
| expression |
|---|
| "reference_entity_id" <> '' |
| "reference_entity_id_type" in ('LEI', 'Internal') |
| "reference_entity_id_type" <> 'LEI' or char_length("reference_entity_id") = 20 |
| "maturity_date" is null or "start_date" is null or "maturity_date" >= "start_date" |
5.3. Indexes
| name | columns | unique | current_only | where_extra |
|---|---|---|---|---|
| party | tenant_id, party_id | false | true | |
| trade_type | tenant_id, trade_type_code | false | true |
5.4. Pinned keys
The header copies the anchor's party and trade type, so the insert trigger
checks the copies against the anchor's current row and refuses a row that
disagrees. The anchor is a versioned table, so a database foreign key cannot
name it and the pin is a trigger check, as the trade_id key is. The fact and
child tables carry neither column: they reach both through this row (design
decision D3), so the header is the only row of the family that can disagree.
The insert trigger stamps party_id from the session, and row-level
security hides another party's anchor, so in practice the pin refuses a
disagreeing trade_type_code; the party column is held to the anchor as
well, so a path that bypasses the stamp cannot drift from it.
The anchor's model states that its party and trade type are fixed for the trade's life and that a change is a cancel and rebook. The anchor's write path does not enforce it, so an amendment that changed the trade type would leave the header unchecked. That gap belongs to the trade model, not to this family, and it is open.
| name | columns | table | target_columns | error_message |
|---|---|---|---|---|
| anchor | trade_id, party_id, trade_type_code | ores_trading_trades_tbl | id, party_id, trade_type | Invalid trade_id: %. The party and trade type must be the trade's own. |
The tenant isolation and the party isolation policies are hand-written in
trading_rls_policies_create.sql, as bond_instruments' are: the header
carries party_id, so it needs the restrictive party policy beside the
tenant policy, and the generated :rls_tenant_isolation: form states the
tenant policy alone.
6. C++
The C++ domain class nests the scaffolding columns and the columns marked
:group: identity below into an instrument_identity identity; member
(see the ores.trading.instrument_identity field-group model), the implicit
audit columns fold into an ores::dq::domain::audit_record audit; member
(see the ores.dq.audit_record field-group model), and the dates and the
description stay flat in between. The SQL schema, DB entity and column
lists are unaffected. The entity templates consume these annotations;
domain and repository profiles regenerate correctly.
6.1. Flags
6.2. Repository
6.3. Domain includes
#include <chrono> #include <string> #include <boost/uuid/uuid.hpp>
6.4. Conventions
6.5. Table display
| column | header |
|---|---|
| identity.trade_id | ID |
| identity.trade_type_code | Type |
| reference_entity_id_type | Reference Type |
| reference_entity_id | Reference |
| start_date | Start Date |
| maturity_date | Maturity Date |
| description | Description |
| identity.version | Version |
| audit.recorded_at | Recorded At |
6.6. Custom repository methods
6.7. Write observation
The trade's economic digest observes every write of this component. The observer's specialisation must be visible where the repository writes, so the repository includes it.
#include "ores.trading.core/repository/trade_write_observation.hpp"
7. See also
- ores.trading — component group overview.
- ores.trading.trade_type_catalogue — the routing this header's check is generated from.