ores.trading.trade
Table of Contents
The immutable anchor of a trade. It holds only the facts that are fixed for the trade's life: the firm's legal entity (party), the counterparty, the trade type, and the three closed classifications — counterparty scope, booking nature and entry channel. Everything that changes lives in component tables keyed by the trade, each on its own timeline.
A row is written once and never changed. A change of party or counterparty is a cancel and rebook: a new trade, linked to the old one. Because the row never changes, the component tables reference it with database foreign keys instead of trigger checks against temporal rows.
The anchor is built beside the wide trade table, which it replaces in
the last task of the story; until then it is named trade. It has
no audit tail: the audit record of the act that booked it carries that.
1. Flags
:generate_touch_function:: the trade is a composite parent. A write to
any of its parts bumps the trade's own version in the same transaction,
so the trade's windows partition time into spans in which its parts are
stable, and a read assembles the trade from the timeline with no link
table.
The parts are the trade's own anchors (trade_state, trade_booking,
trade_identifier, trade_party_role, trade_portfolio,
trade_additional_field, structure_member) and the bond rows keyed by
the same trade: bond_instrument and the leg rows under it. Each of
those declares :bump_parent_version: true on its trade key. See the
"Temporal composite entity versioning" architecture doc.
2. Columns
2.1. id
The trade id: the firm's own identifier of the trade.
ctx.generate_uuid()
2.2. party_id
The firm's legal entity that is party to the trade.
ctx.generate_uuid()
2.3. counterparty_id
The party the firm faces. Absent only on an intra-entity trade, which moves risk between two books of one legal entity and faces nobody.
std::nullopt
2.4. trade_type
ORE trade type code (e.g. Swap, FxForward, CapFloor).
std::string("Swap")
2.5. counterparty_scope
Who the firm faces: external, inter_entity or intra_entity.
ores::trading::domain::counterparty_scope::intra_entity
2.6. booking_nature
Whether anything happened to cause the booking: actual, test or
hypothetical.
ores::trading::domain::booking_nature::test
2.7. entry_channel
How the trade reached the firm's books: manual, stp, ecn or
allocation.
ores::trading::domain::entry_channel::manual
2.8. origin
Which system first wrote the trade down: ux, api, ore_import or
synthetic. It is provenance and not economics, so it stays out of the
economic digest: the same trade imported twice is one trade.
ores::trading::domain::origin::api
2.9. origin_reference
The reference the origin implies: the ORE trade id for an import, the generation config id for a synthetic trade, and nothing for a person at a screen.
std::string(faker::string::numeric(10))
2.10. external_version
The version the customer's records match. It moves when the economics the trade holds change, and never for an internal reason: a null amend, an operational authorisation or any other change the customer did not agree to leaves it alone.
It is not the version every entity carries. That one is the audit trail and
moves on every recorded change; this one is the commercial record. See
Trade Versioning.
0
2.11. draft_reason_code
Why a draft is not live, when the trade is a draft: a code from ores.trading.draft_reason. It is null for a trade that went live when it was booked, because a concluded deal waits on nothing.
std::string("structure_incomplete")
2.12. economic_digest
The SHA-256 of the economics the trade holds, folded from its own economic fields and from every component's, in hex. Stored rather than recomputed on read, so a change is one comparison rather than a walk of the whole shape.
A null amend leaves it unchanged, which is what makes the external version rule enforceable at all. A change to a field the customer did not agree to leaves it unchanged too, because the digest covers declared economic fields and nothing else. See Exact Numbers and Economic Change.
std::string("")
3. Foreign keys
3.1. origin
3.2. party_id
The firm's legal entity. A party is temporal, so this stays a trigger check.
3.3. counterparty_id
The counterparty. Temporal, so a trigger check.
3.4. trade_type
The trade type catalogue is system reference data, so the check reads the system tenant.
3.5. counterparty_scope
A database foreign key: the lookup is immutable and has no tenant.
3.6. booking_nature
A database foreign key: the lookup is immutable and has no tenant.
3.7. entry_channel
A database foreign key: the lookup is immutable and has no tenant.
4. SQL
4.1. Flags
4.2. Checks
An external trade faces a counterparty; only an intra-entity trade may have none.
| expression |
|---|
| "counterparty_scope" = 'intra_entity' or "counterparty_id" is not null |
4.3. Indexes
The two unique keys are what a component pins its copied party and
counterparty to: a database pin can only name a key, and the primary key
(tenant_id, id) does not carry either column.
| name | columns | unique | current_only | where_extra |
|---|---|---|---|---|
| party | tenant_id, party_id | false | false | |
| counterparty | tenant_id, counterparty_id | false | false |
5. C++
5.1. Flags
5.2. Repository
5.3. Domain includes
#include <optional> #include <string> #include <boost/uuid/uuid.hpp>
5.4. Conventions
5.5. Table display
| column | header |
|---|---|
| id | Trade Id |
| trade_type | Trade Type |
| counterparty_scope | Counterparty Scope |
| booking_nature | Booking Nature |
| entry_channel | Entry Channel |
6. See also
- ores.trading — component group overview.
- Trade Classification — counterparty scope and booking nature.