ores.trading.trade_operations

Table of Contents

A trade is an immutable anchor with a booking and a state, each in its own table. Booking a trade writes all three, and a trade with an anchor but no booking or state is not a trade anyone can read. So booking is one operation rather than three entity writes: the three rows are written in one transaction, and a failure in any of them writes none.

The anchor is written once. A second booking of the same trade id is answered with a conflict, because the trade it names already exists, rather than surfacing as a database key violation.

The handler stays hand-written beside this model, because an operation model generates no service handler.

1. Includes

#include <map>
#include <optional>
#include <string>
#include <vector>
#include "ores.trading.api/domain/bond_issue.hpp"
#include "ores.trading.api/domain/bond_issue_call_date.hpp"
#include "ores.trading.api/domain/bond_issue_conversion_target.hpp"
#include "ores.trading.api/domain/bond_issue_leg.hpp"
#include "ores.trading.api/domain/bond_issue_leg_amortization.hpp"
#include "ores.trading.api/domain/bond_issue_leg_amount.hpp"
#include "ores.trading.api/domain/bond_issue_leg_rate.hpp"
#include "ores.trading.api/domain/bond_issue_leg_schedule.hpp"
#include "ores.trading.api/domain/bond_issue_leg_schedule_date.hpp"
#include "ores.trading.api/domain/instrument_batch.hpp"
#include "ores.trading.api/domain/structure.hpp"
#include "ores.trading.api/domain/structure_member.hpp"
#include "ores.trading.api/domain/trade.hpp"
#include "ores.trading.api/domain/trade_envelope_data.hpp"
#include "ores.trading.api/domain/trade_booking.hpp"
#include "ores.trading.api/domain/trade_identifier.hpp"
#include "ores.utility/domain/protocol.hpp"

2. Messages

2.1. book_trade_request

/**
 * @brief Books a trade: its anchor, its booking, its first state, its
 * identifiers and its instrument.
 *
 * The rows are written in one transaction. The booking's trade id,
 * party and counterparty are taken from the anchor, so the caller states
 * them once.
 */

2.1.1. anchor

/**
 * @brief The trade's immutable facts.
 */

2.1.2. booking

/**
 * @brief Where the trade is booked. Its trade id, party and counterparty
 * are replaced by the anchor's.
 */

2.1.3. activity_type_code

/**
 * @brief The activity that books the trade, which names the transition
 * that starts its state: new_booking for a live trade, draft_capture for a
 * draft.
 */

2.1.4. draft_reason_code

/**
 * @brief Why the trade is a draft, when the activity books one. Empty for a
 * booking that goes live, because a concluded deal waits on nothing.
 */

2.1.5. identifiers

/**
 * @brief The trade's identifiers. The service states the trade id and the
 * activity id on each one, so the caller states the scheme and the value.
 */

2.1.6. instruments

/**
 * @brief The trade's instrument, as one array for each instrument table. The
 * service states the trade id, the trade type and the activity id on each
 * row. A row for a kind with no writer yet refuses the booking by name.
 */

2.2. book_trade_response

/**
 * @brief The outcome of booking a trade.
 */

2.2.1. result

/**
 * @brief Outcome of the operation: conflict with code already_exists when
 * the trade id is already booked.
 */

2.2.2. activity_id

/**
 * @brief The activity that booked the trade; absent when the booking was
 * refused.
 */

2.3. execute_trade_request

/**
 * @brief Takes a draft trade live: the activity that executes it, and the
 * state that activity moves it to.
 *
 * The activity, the state and the authorisation request join one
 * transaction, so an actual trade is never live without a request.
 */

2.3.1. trade_id

/**
 * @brief The draft to execute.
 */

2.3.2. expected_version

/**
 * @brief The version the caller read. A draft that moved since is refused
 * rather than executed on terms nobody read.
 */

2.3.3. occurred_at

/**
 * @brief When the deal executed; the clock when absent.
 */

2.3.4. change_reason_code

/**
 * @brief Why the draft was executed.
 */

2.3.5. change_commentary

/**
 * @brief The note that goes with the reason.
 */

2.4. execute_trade_response

/**
 * @brief The outcome of executing a draft.
 */

2.4.1. result

/**
 * @brief Outcome of the operation: conflict when the trade is not a draft or
 * has moved since the caller read it, not found when no such trade exists.
 */

2.4.2. activity_id

/**
 * @brief The activity that executed the trade; absent when it was refused.
 */

2.5. complete_structure_request

/**
 * @brief Completes a structure: its anchor, its legs, and the execution of
 * every leg, in one transaction.
 *
 * The legs are drafts when the request arrives. A completion that is refused
 * leaves every one of them a draft and writes no member, which is why the
 * structure, the members and the executions are one unit of work rather than
 * a sequence a caller drives.
 */

2.5.1. structure

/**
 * @brief The structure to write. The service names it, so the caller states
 * the party, the kind and the template, and no reference.
 */

2.5.2. legs

/**
 * @brief The legs the structure holds, in the order they are given. The
 * service states the structure id and the sequence number on each one.
 */

2.5.3. leg_count

/**
 * @brief How many legs the caller means to complete. A request whose list is
 * not this long is refused, so a truncated list never completes a structure
 * that is missing a leg.
 */

2.5.4. change_reason_code

/**
 * @brief Why the structure is being completed.
 */

2.5.5. change_commentary

/**
 * @brief The note that goes with the reason.
 */

2.6. complete_structure_response

/**
 * @brief The outcome of completing a structure.
 */

2.6.1. result

/**
 * @brief Outcome of the operation: conflict with code already_exists when the
 * structure is already made, conflict with code not_a_draft when a leg is not
 * a draft, not found when a leg is not booked.
 */

2.6.2. structure_id

/**
 * @brief The structure written; absent when the completion was refused.
 */

2.6.3. structure_version

/**
 * @brief The version the structure is at after the write, so a caller can
 * address the structure it just made.
 */

2.7. put_bond_issue_composite_request

/**
 * @brief Creates a bond issue with its legs, in one transaction.
 *
 * The issue is the security master. It is whole or absent: a refused child
 * write leaves no issue row. The issue is create-only. An issue that already
 * exists is answered with a conflict and the stored issue stays as it is:
 * already_exists when its terms equal the request, content_differs when they
 * do not. Each child row names its issue and leg, and the caller states them
 * once on the row.
 */

2.7.1. issue

/**
 * @brief The security's terms.
 */

2.7.2. legs

/**
 * @brief The issue's legs.
 */

2.7.3. amounts

/**
 * @brief The amounts of the legs: notionals, coupons and the like.
 */

2.7.4. rates

/**
 * @brief The rate terms of the legs.
 */

2.7.5. schedules

/**
 * @brief The schedules of the legs.
 */

2.7.6. schedule_dates

/**
 * @brief The dates of the schedules that state a date list.
 */

2.7.7. amortizations

/**
 * @brief The amortisation terms of the legs.
 */

2.7.8. call_dates

/**
 * @brief The dates on which the issuer may call the issue.
 */

2.7.9. conversion_targets

/**
 * @brief The securities a convertible issue converts into.
 */

2.8. put_bond_issue_composite_response

/**
 * @brief The outcome of creating a bond issue.
 */

2.8.1. result

/**
 * @brief Outcome of the operation: conflict with code already_exists when
 * the same issue is stored, and conflict with code content_differs when an
 * issue with this id or security id is stored with other terms.
 */

2.9. trade_export_item

/**
 * @brief One trade's anchor, its ORE identifier and its envelope, as an
 * export writes it.
 *
 * The trade's instrument is not here. The export carries it in the batch's
 * typed array for the table the trade type routes to, and every element of
 * that array names the trade id this item states, so a reader joins the two
 * without an element tag.
 */

2.9.1. anchor

/**
 * @brief The trade's immutable facts.
 */

2.9.2. ore_id

/**
 * @brief The id the package names the trade by, which is the trade's own UUID.
 */

2.9.3. envelope

/**
 * @brief The ids of the trade's counterparty, netting set and portfolios, and the additional fields: the names and codes of those entities as context, beside any field the trade's source recorded. Absent when the trade has none.
 */

2.10. export_portfolio_request

/**
 * @brief Exports the trades under a taxonomy node.
 *
 * The node is a book, a portfolio or a business unit, resolved to its books on
 * the server; the trades are those booked in them.
 */

2.10.1. node_id

/**
 * @brief The book, portfolio or business unit to export.
 */

2.10.2. offset

/**
 * @brief The first trade to export, in trade id order.
 */

2.10.3. limit

/**
 * @brief The most trades to export.
 */

2.11. export_portfolio_response

/**
 * @brief The exported trades.
 */

2.11.1. success

/**
 * @brief Whether the export ran.
 */

2.11.2. message

/**
 * @brief Why the export failed, when it did.
 */

2.11.3. items

/**
 * @brief The trades, in trade id order.
 */

2.11.4. instruments

/**
 * @brief The trades' instruments, one typed array per instrument entity and
 * per child table, every element keyed by its trade id.
 *
 * An instrument is not a field of the item above: a std::variant cannot cross
 * the wire, because the codec names no alternative, and an encoded payload
 * would be an untyped field. So the tag sits on the container: a reader takes
 * the trade's type from the anchor, routes it with instrument_table_for, and
 * joins the array that table names by the trade id.
 */

2.12. export_trades_to_storage_request

/**
 * @brief Exports the trades booked in a set of books to object storage.
 *
 * The handler serialises the export items to MsgPack, compresses them with
 * gzip and uploads them, so a report run passes a storage key rather than the
 * trades through NATS.
 */

2.12.1. book_ids

/**
 * @brief The books whose trades to export.
 */

2.12.2. storage_bucket

/**
 * @brief The target bucket: the platform bucket, ores.
 */

2.12.3. storage_key

/**
 * @brief The target key, such as reporting/runs/{instance_id}/trades.msgpack.
 */

2.13. export_trades_to_storage_response

/**
 * @brief The outcome of an export to storage.
 */

2.13.1. success

/**
 * @brief Whether the export ran.
 */

2.13.2. message

/**
 * @brief Why the export failed, when it did.
 */

2.13.3. trade_count

/**
 * @brief How many trades were written.
 */

2.13.4. storage_key

/**
 * @brief The key written, echoed from the request.
 */

2.13.5. trade_versions

/**
 * @brief The version of each trade written, keyed by trade id.
 *
 * The blob holds the trades, so a reader of it needs no manifest to read them.
 * This is for the caller that holds a trade id and has to say which version of
 * that trade the export read: a report run writes the errors its engine raises,
 * and an error about a trade names the version the engine was given.
 */

3. See also

Emacs 29.3 (Org mode 9.6.15)