ores.trading.callable_swap_call_date

Table of Contents

One row per date the callable swap's exercise schedule names, keyed to the instrument and the date's ordinal within the schedule.

The ORE schema states the callable swap's exercise dates as an unbounded list of ISO 8601 dates on the option block. The list order is the document's order and the ordinal preserves it, so export re-emits the dates as the document held them.

A date list states no rule, no calendar and no convention: the document writes out every date it means. The columns here are therefore the date's own ordinal and the date itself, and nothing else. A malformed date is refused by the column's type rather than by a convention the readers must share, and a repeated date stays two rows because the ordinal, not the date, is part of the key.

The trade row carries the party. The call date rows are family-owned and ride the trade's scope.

1. Flags

2. Natural keys

3. Columns

3.1. trade_id

The trade whose callable swap schedule states this date.

3.2. trade_activity_id

The activity that wrote this version.

3.3. sequence_number

Ordinal of this date within the schedule's list, counting from one.

The schema declares the list unbounded and a document's order is the order it stated, so the ordinal is what identifies a row and preserves that order.

3.4. call_date

The date on which the call may be exercised.

The ORE document states it as an ISO 8601 date string; the column's type refuses any other spelling.

std::chrono::year_month_day{std::chrono::year{2029}/1/15}

4. Foreign keys

4.1. trade_id

The trade this row belongs to. An instrument is keyed by its trade, so a fact or child row names the trade its document states and the insert trigger checks it there.

#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();
    ores::trading::repository::trade_repository().write(party_ctx, anchor);
    v.trade_id = anchor.id;
}

4.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.trade_activity_id = activity.id;
}

5. SQL

5.1. Flags

5.2. Checks

expression
"sequence_number" > 0

6. C++

6.1. Flags

6.2. Repository

6.3. Domain includes

#include <boost/uuid/uuid.hpp>

6.4. Conventions

6.5. Table display

column header
sequence_number Sequence
call_date Call Date
modified_by Modified By
version Version

6.6. Custom repository methods

The trade read path fetches the call dates of many callable swaps at once when it assembles the export payload, and no generated read covers that: read_latest(context, ids) filters on the child's own key and read_latest_by_trade_id reads one instrument at a time. The batch read below is one statement over the instrument set, which is what the generated stack cannot express.

6.6.1. read_by_instruments_batch

Reads every current call date of the given instruments, ordered by instrument and ordinal, in one statement. An empty input reads nothing.

std::vector<domain::callable_swap_call_date>
read_by_instruments_batch(context ctx, const std::vector<std::string>& trade_ids);
std::vector<domain::callable_swap_call_date>
callable_swap_call_date_repository::read_by_instruments_batch(
    context ctx, const std::vector<std::string>& trade_ids) {
    if (trade_ids.empty())
        return {};
    static constexpr auto max = db_timestamp::max();
    const auto tid = ctx.tenant_id().to_string();
    const auto query = query_builder::read<std::vector<callable_swap_call_date_entity>> |
                       query_builder::where("tenant_id"_c == tid && "trade_id"_c.in(trade_ids) &&
                             "valid_to"_c == max) |
                       query_builder::order_by("trade_id"_c, "sequence_number"_c);
    return query_builder::execute_read_query<callable_swap_call_date_entity, domain::callable_swap_call_date>(
        ctx,
        query,
        [](const auto& entities) { return callable_swap_call_date_mapper::map(entities); },
        lg(),
        "Reading callable swap call dates for multiple instruments.");
}

7. See also

Emacs 29.3 (Org mode 9.6.15)