ores.marketdata.fx_forward_publish
Table of Contents
The detail row of one marketdata.fx_forward_publish approval request: the FX
forward set the request authorises, where each of its numbers came from, and the
record of the act once the set is published.
A forward set is derived data, so it belongs to a party, as a funding curve does.
The subject is the party, the pair and the as-of instant. The set is computed
when the request is raised, so the person who decides reads the numbers they
approve, and the apply publishes exactly those numbers. The tenors are the
fx_forward_publish_point rows of the publish, and the spot observations it read
are its fx_forward_publish_spot rows: one for a USD pair, two for a cross.
The provenance is on this row: the publish of each funding curve the set discounts with, the version of the pair's convention, the calendars its dates roll on, and the method that combined them. Each names its own record, so a reader follows a number back to the market and to the curves. A curve publish is named and not copied, so the withdrawal of a curve shows on every set built from it without a write here. The apply does not check the curves again: the decider approved those numbers, and a curve withdrawn after the raise shows on the set as withdrawn rather than stopping it.
published_at and published_by are the publication record, empty while the
request waits and written in one act when the approved set is published.
request_id is the natural key, so a request authorises one publish.
1. Flags
2. Columns
2.1. id
Surrogate UUID identifying this row.
2.2. request_id
The approval request this record is the subject of.
ctx.generate_uuid()
2.3. party_id
The party the set belongs to. Two parties that publish the same pair at the same instant publish two sets, each from its own curves.
ctx.generate_uuid()
2.4. pair_code
The currency pair, in the form of its convention, such as EUR/USD.
std::string("EUR/USD")
2.5. as_of
The instant the set reads the market at: the latest spot at or before it, and the funding curves published at or before it.
ctx.past_timepoint()
2.6. spot_date
The spot date the forwards are measured from, rolled on the pair's calendars.
std::chrono::year_month_day{std::chrono::year{2026}, std::chrono::month{11}, std::chrono::day{11}}
2.7. spot_rate
The spot rate of the pair the set used. For a cross it is derived from the two USD legs its spot rows name.
1.1
2.8. base_curve_publish_id
The curve_publish of the base currency's funding curve the set discounts with.
ctx.generate_uuid()
2.9. quote_curve_publish_id
The curve_publish of the quote currency's funding curve the set discounts with.
ctx.generate_uuid()
2.10. convention_version
The version of the pair's currency_pair_convention the set read its spot lag, roll and pip factor from.
1
2.11. calendar_codes
The calendars the dates roll on, comma separated, in the order the convention names them.
std::string("TARGET,US")
2.12. method_code
How the set combined its inputs. covered_interest_parity is F = S x DF_base / DF_quote, each discount factor measured from the spot date.
std::string("covered_interest_parity")
2.13. published_by
The username of the account that applied the request, or empty while it waits.
std::string("")
2.14. published_at
When the set was published, or null while the request waits.
std::nullopt
3. SQL
3.1. Flags
The record is tenant-scoped, as an IR curve publish is: the decider of a publish is a tenant function, so the subject names its party instead of hiding behind it.
3.2. Checks
| expression |
|---|
| ("published_at" is null) = ("published_by" = '') |
| "as_of" > '1970-01-01 00:00:00+00'::timestamp with time zone |
| "spot_rate" > 0 |
| "pair_code" <> '' |
3.3. Indexes
| name | columns | unique | current_only |
|---|---|---|---|
| fx_forward_publishes_party_pair | tenant_id, party_id, pair_code, as_of desc | false | true |
4. Foreign keys
4.1. request_id
The request the record is the subject of. Its own id is the one the publish call names, so a record that names a request the store does not hold authorises nothing.
#include "ores.iam.api/generators/account_generator.hpp" #include "ores.iam.core/repository/account_repository.hpp" #include "ores.inbox.api/generators/approval_request_generator.hpp" #include "ores.inbox.core/repository/approval_kind_repository.hpp" #include "ores.inbox.core/repository/approval_request_repository.hpp" #include "ores.inbox.core/repository/approval_request_state_repository.hpp" #include "ores.utility/uuid/tenant_id.hpp"
{
auto asker = ores::iam::generators::generate_synthetic_account(ctx);
asker.account_type = "service";
asker.change_reason_code = "system.test";
ores::iam::repository::account_repository asker_repo;
asker_repo.write(party_ctx, asker);
auto request = ores::inbox::generators::generate_synthetic_approval_request(ctx);
request.change_reason_code = "system.test";
request.requested_by = asker.id;
const auto system_ctx =
party_ctx.with_tenant(ores::utility::uuid::tenant_id::system(), h.db_user());
const auto kinds =
ores::inbox::repository::approval_kind_repository{}.read_latest(system_ctx);
REQUIRE_FALSE(kinds.empty());
request.kind_code = kinds.front().code;
const auto states =
ores::inbox::repository::approval_request_state_repository{}.read_latest(system_ctx);
REQUIRE_FALSE(states.empty());
request.state_code = states.front().code;
ores::inbox::repository::approval_request_repository request_repo;
request_repo.write(party_ctx, request);
v.request_id = request.id;
}
4.2. party_id
5. C++
5.1. Flags
5.2. Repository
5.2.1. read_latest_by_request
Reads the record of one request, if the store holds one. The gate asks here.
std::optional<domain::fx_forward_publish> read_latest_by_request(context ctx, const std::string& request_id);
#include <optional> #include <string>
std::optional<domain::fx_forward_publish> fx_forward_publish_repository::read_latest_by_request(context ctx, const std::string& request_id) { static constexpr auto max = db_timestamp::max(); const auto tid = ctx.tenant_id().to_string(); const auto query = query_builder::read<std::vector<fx_forward_publish_entity>> | query_builder::where("tenant_id"_c == tid && "request_id"_c == request_id && "valid_to"_c == max); auto rows = query_builder::execute_read_query<fx_forward_publish_entity, domain::fx_forward_publish>( ctx, query, [](const auto& entities) { return fx_forward_publish_mapper::map(entities); }, lg(), "Reading the FX forward publish of a request."); if (rows.empty()) return std::nullopt; return rows.front(); }
5.2.2. read_published_for_pair
Every published set of one party and pair, newest as-of first. A reader at an as-of takes the first one at or before it.
std::vector<domain::fx_forward_publish> read_published_for_pair(context ctx, const boost::uuids::uuid& party_id, const std::string& pair_code);
#include <algorithm> #include <string> #include <vector> #include <boost/uuid/uuid_io.hpp>
std::vector<domain::fx_forward_publish> fx_forward_publish_repository::read_published_for_pair(context ctx, const boost::uuids::uuid& party_id, const std::string& pair_code) { static constexpr auto max = db_timestamp::max(); const auto tid = ctx.tenant_id().to_string(); const auto pid = boost::uuids::to_string(party_id); const auto query = query_builder::read<std::vector<fx_forward_publish_entity>> | query_builder::where("tenant_id"_c == tid && "party_id"_c == pid && "pair_code"_c == pair_code && "valid_to"_c == max); auto rows = query_builder::execute_read_query<fx_forward_publish_entity, domain::fx_forward_publish>( ctx, query, [](const auto& entities) { return fx_forward_publish_mapper::map(entities); }, lg(), "Reading the published FX forward sets of a pair."); std::erase_if(rows, [](const auto& r) { return !r.published_at.has_value(); }); // Newest as-of first; between two sets of one as-of, the one published last. std::ranges::sort(rows, [](const auto& a, const auto& b) { if (a.as_of != b.as_of) return a.as_of > b.as_of; return *a.published_at > *b.published_at; }); return rows; }
5.3. Domain includes
#include <chrono> #include <optional> #include <string> #include <boost/uuid/uuid.hpp>
5.4. Entity includes
#include <optional> #include <string>
5.5. Conventions
5.6. Table display
| column | header |
|---|---|
| pair_code | Pair |
| as_of | As Of |
| published_by | Published By |
| published_at | Published At |
6. See also
- ores.marketdata.curve_publish – the IR curve publish this record follows, and whose publishes it names.