ores.trading.structure

Table of Contents

The immutable identity of a deal assembled from several trades. It holds what never changes for the deal's life: the party, the counterparty, the kind of binding, the template it was shaped by, and its parent when it is itself a leg of a larger deal.

It is the anchor of the composition ladder. The legs are not owned children: a trade points at the structure that holds it, so the same trade can be unlinked from one deal and linked to another without being rewritten. The economics live on the legs, and the structure's internal version is read from them rather than stored beside them.

A structure nests one level at most, because a deal inside a deal inside a deal has no confirmation to hang on. The insert trigger enforces it.

1. Flags

2. Columns

2.1. id

The structure id: the firm's own identifier of the deal.

ctx.generate_uuid()

2.2. party_id

The firm's legal entity that is party to the deal. Every leg shares it, and the pin on the leg is what keeps the sharing true.

ctx.generate_uuid()

2.3. counterparty_id

The counterparty the deal is struck with. Every leg shares it.

ctx.generate_uuid()

2.4. kind

The rung of the composition ladder the deal sits on, which is what decides whether it confirms as one document or trade by trade.

std::string("Strategy")

2.5. template_code

The template that shaped the deal, when one did. A package has none, because it binds its legs to nothing and no template describes it.

std::string("Straddle")

2.6. parent_structure_id

The structure this one is a leg of, when the deal nests. Null for a deal the customer sees on its own.

ctx.generate_uuid()

3. SQL

3.1. Flags

3.2. Indexes

The two indexes answer a lookup by party or by counterparty.

name columns unique current_only where_extra

3.3. Extra drops

drop function if exists ores_trading_validate_structure_fn;

4. Insert trigger

-- Structures nest one level at most. A structure that has a parent is a
-- leg of a larger deal, and a leg carries no legs of its own: the
-- confirmation hangs on the deal the customer sees, and there is no
-- second deal above it to confirm.
if NEW.parent_structure_id is not null and exists (
    select 1 from ores_trading_structures_tbl
    where tenant_id = NEW.tenant_id
      and id = NEW.parent_structure_id
      and parent_structure_id is not null
) then
    raise exception 'Invalid parent_structure_id: %. The parent is itself a leg, and structures nest one level at most.',
        NEW.parent_structure_id
        using errcode = '23514';
end if;

-- A structure is not its own parent.
if NEW.parent_structure_id = NEW.id then
    raise exception 'Invalid parent_structure_id: %. A structure cannot be its own parent.',
        NEW.parent_structure_id
        using errcode = '23514';
end if;

5. Foreign keys

5.1. kind

The kind catalogue is system reference data.

5.2. template_code

The template catalogue is system reference data. A package rests on no template, so the column is nullable.

5.3. parent_structure_id

A database foreign key: the parent is immutable, so the key can be enforced rather than checked.

6. C++

6.1. Flags

6.2. Repository

6.3. Domain includes

#include <string>
#include <boost/uuid/uuid.hpp>

6.4. Conventions

6.5. Table display

column header
id Structure Id
kind Kind
template_code Template
parent_structure_id Parent
party_id Party

6.6. Custom repository methods

6.7. Naming a structure

A structure is grouped before anybody can book a leg into it, so the grouping is where it needs a name: every write gives a structure that has no internal reference one. The service names it after the repository writes the row.

#include "ores.trading.api/domain/structure_identifier.hpp"
#include "ores.trading.core/repository/structure_identifier_repository.hpp"
/**
 * @brief The prefix a deal reference carries for a kind of structure.
 *
 * The desk reads a reference and knows what it is looking at, so the prefix is
 * the kind's and not a house-wide one. An unknown kind takes the structure
 * prefix rather than no prefix at all: a reference is what makes a deal
 * addressable, and a missing one is worse than an approximate one.
 */
std::string reference_prefix(const std::string& kind) {
    if (kind == "Package")
        return "PKG";
    if (kind == "Strategy")
        return "STR";
    if (kind == "Typed")
        return "TYP";
    if (kind == "Dynamic")
        return "DYN";
    return "STR";
}

/**
 * @brief Names a structure that has no reference yet.
 *
 * A structure is grouped before anybody can book a leg into it, so the grouping
 * is where it needs a name. The value is derived from the structure's own id,
 * which is unique already, so two structures cannot collide and no counter has
 * to be kept.
 *
 * This runs on every write and not only on a creation. The structure and its
 * identifier are two statements, so a run cut between them would otherwise
 * leave a deal that no later write ever names again.
 */
void name_structure(const ores::database::context& ctx, const domain::structure& value) {
    repository::structure_identifier_repository identifiers;
    const auto named =
        identifiers.read_latest(ctx, boost::uuids::to_string(value.id), std::string("Internal"));
    if (!named.empty())
        return;

    domain::structure_identifier identifier;
    identifier.tenant_id = value.tenant_id;
    identifier.structure_id = value.id;
    identifier.id_type = "Internal";
    identifier.id_value =
        reference_prefix(value.kind) + "-" + boost::uuids::to_string(value.id).substr(0, 8);
    identifier.modified_by = value.modified_by;
    identifier.performed_by = value.performed_by;
    identifier.change_reason_code = value.change_reason_code;
    identifier.change_commentary = value.change_commentary;
    identifier.recorded_at = value.recorded_at;

    // The claim is the identifier's own: a structure's claim speaks about the
    // structure, and a version on it would mean nothing here.
    identifiers.write(
        ctx, identifier, {ores::utility::domain::precondition_kind::must_not_exist, std::nullopt});
}
name_structure(ctx_, value);
for (const auto& written_value : batch)
    name_structure(ctx_, written_value);

7. See also

Emacs 29.3 (Org mode 9.6.15)