Typed operations¶
A plugin reaches the Open Meridian bus through its typed operations and nothing else. Each operation is one step of a workflow that a plugin role may take. The plugin calls a typed method, and its sidecar does the rest:
- It builds the domain message.
- It stamps the fields only the sidecar knows truthfully.
- It checks the grant.
- It sends the message.
A plugin never names a topic.
The operations are generated, not written by hand. One generator reads the interface's matrix and domain protos and emits three things that must agree:
- the plugin-facing gRPC service,
meridian.plugin.v1.PluginOperations; - the sidecar's side of it;
- the Python methods of the role classes,
meridian.roles.<role>.Role.
This page lists every operation in SDK 0.36.0: holdings ingestion and the custodian's activity, the book of record's commands and reads, instrument and venue resolution, the lake's records and reads, the order path, booking, the settlement calendars' reads, and the one-ID model's reads, list_replacements, list_templates and read_template, with reference's offer_template_fields; the analytics component, event groups, bounded lake query and agents' guard; RFQ quotes, execution costs, rates, liveness and latency; listed options and futures, companies and corporate actions, derived series and saved scenarios, the stale-reference actions permitted, and the filings slice and quality states core serves later; and factors and an underlying's expirations, with fixed income's prices and fills. A resolve answers whether its record is provisional. The book refuses an entry missing what it requires, REFUSAL_REASON_INCOMPLETE, naming each missing field (see What the book requires). A command naming an order, a placement, a change request or a locate by its ID is admitted on the role's grant and held by the book to the plugin's write scope (see The order lifecycle).
Three calls every plugin may make are in the Python SDK rather than here: reading the prepared change a page was opened from (ReadPreparedCall), saving a person's own settings (SetOwnSettings), and calling one of the plugin's own acts as the service account its role runs as (CallAsServiceAccount, offered as meridian.runs_as). Where the dashboard makes such an act, its route is reached with a service account's claims and sends what it sends for a person, acting_for the header it received (see Acting for a person); the book records the service account and its owner as the entry's actor.
Summary¶
| Python method | gRPC rpc | Workflow step | Kind | Role | Returns |
|---|---|---|---|---|---|
report_external_accounts |
ReportExternalAccounts |
W2.8 Report the accounts a connection reaches | event | custody |
Published |
report_sync_status |
ReportSyncStatus |
W2.1 Observe the brokerage sync state | event | custody |
Published |
record_holdings_statement |
RecordHoldingsStatement |
W2.2 Open a holdings statement | command | custody |
RecordHoldingsStatementResult |
record_holding |
RecordHolding |
W2.3 Publish each holding | command | custody |
RecordHoldingResult |
list_custodial_positions |
ListCustodialPositions |
W2.7 Read custodial positions | query | operations |
ListCustodialPositionsResult |
list_statements |
ListStatements |
W2.9 Read completed statements | query | operations |
ListStatementsResult |
record_activity |
RecordActivity |
W2.10 Record an account's activity | command | custody |
RecordActivityResult |
list_activities |
ListActivities |
W2.11 List an account's activity | query | operations |
ListActivitiesResult |
re_resolve_activity |
ReResolveActivity |
W2.15 Re-resolve a recorded activity | command | custody |
ReResolveActivityResult |
list_sync_statuses |
ListSyncStatuses |
W2.14 Read an account's sync status | query | operations |
ListSyncStatusesResult |
resolve_identifier |
ResolveIdentifier |
W3.1 Resolve an identifier set | query | custody, data, reporting, connectivity |
ResolveIdentifierResult |
report_missing_instrument |
ReportMissingInstrument |
W3.2 Report that a resolution missed | event | custody, data, connectivity |
Published |
read_accounts_for_linking |
ReadAccountsForLinking |
W6.4 Link a plugin's external account | query | custody |
ReadAccountsForLinkingResult |
link_external_account |
LinkExternalAccount |
W6.4 Link a plugin's external account | command | custody |
LinkExternalAccountResult |
resolve_instrument |
ResolveInstrument |
W3.6 Resolve an instrument for display | query | portfolio, reporting, compliance, oms, operations, data, ems, connectivity |
ResolveInstrumentResult |
record_opening_balance |
RecordOpeningBalance |
W9.1 Record an account's opening balance | command | operations |
RecordOpeningBalanceResult |
record_break |
RecordBreak |
W9.4 Record a break | command | operations |
RecordBreakResult |
record_account_figures |
RecordAccountFigures |
W9.5 Record the account's figures | command | operations |
RecordAccountFiguresResult |
record_encumbrances |
RecordEncumbrances |
W9.15 Record a position's encumbrances | command | operations |
RecordEncumbrancesResult |
handle_break |
HandleBreak |
W9.6 Set a break's cause and handling | command | operations |
HandleBreakResult |
resolve_break |
ResolveBreak |
W9.7 Resolve or close a break | command | operations |
ResolveBreakResult |
close_breaks_as_cleared |
CloseBreaksAsCleared |
W9.7 Resolve or close a break | command | operations |
CloseBreaksAsClearedResult |
list_positions |
ListPositions |
W9.10 Read positions | query | portfolio, reporting, compliance, oms, operations |
ListPositionsResult |
list_breaks |
ListBreaks |
W9.11 Read breaks | query | operations, oms, compliance, portfolio, reporting |
ListBreaksResult |
list_account_figures |
ListAccountFigures |
W9.12 Read the account's figures | query | operations, portfolio, compliance, reporting |
ListAccountFiguresResult |
list_account_attributes |
ListAccountAttributes |
W9.14 Read an account's attributes | query | portfolio, reporting, compliance, oms, operations, ems, connectivity |
ListAccountAttributesResult |
record_prices |
RecordPrices |
W10.4 Record prices and bars in batches | command | data |
RecordPricesResult |
record_bars |
RecordBars |
W10.4 Record prices and bars in batches | command | data |
RecordBarsResult |
record_trades |
RecordTrades |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordTradesResult |
record_quotes |
RecordQuotes |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordQuotesResult |
decline_want |
DeclineWant |
W10.7 Want what a read could not answer | command | data |
DeclineWantResult |
resolve_venue |
ResolveVenue |
W3.14 Resolve a venue | query | data, connectivity, ems |
ResolveVenueResult |
report_missing_venue |
ReportMissingVenue |
W3.15 Report a venue the deployment does not hold | event | data, connectivity |
Published |
list_prices |
ListPrices |
W10.6 Read prices and bars, point in time, by source | query | reporting, portfolio, compliance, signal, operations |
ListPricesResult |
list_bars |
ListBars |
W10.6 Read prices and bars, point in time, by source | query | reporting, portfolio, compliance, signal |
ListBarsResult |
list_trades |
ListTrades |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | signal, ems |
ListTradesResult |
list_quotes |
ListQuotes |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | signal, ems |
ListQuotesResult |
record_outcomes |
RecordOutcomes |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordOutcomesResult |
list_outcomes |
ListOutcomes |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | reporting, portfolio, compliance, signal, operations |
ListOutcomesResult |
list_datasets |
ListDatasets |
W10.9 Read the datasets | query | reporting, portfolio, compliance, signal, ems |
ListDatasetsResult |
list_source_priorities |
ListSourcePriorities |
W10.2 Order the sources a default read takes | query | reporting, portfolio, compliance, signal, ems, oms, operations, servicing |
ListSourcePrioritiesResult |
propose_order |
ProposeOrder |
W11.1 Propose an order | command | portfolio, oms, ems |
ProposeOrderResult |
record_order |
RecordOrder |
W11.2 Record an order the book did not create | command | oms |
RecordOrderResult |
request_order_change |
RequestOrderChange |
W11.3 Ask for a change to an order | command | portfolio, oms, ems |
RequestOrderChangeResult |
record_check |
RecordCheck |
W11.4 Record a check | command | compliance |
RecordCheckResult |
decide_approval |
DecideApproval |
W11.5 Require, give or override approval, or reject an order | command | compliance, oms |
DecideApprovalResult |
release_order |
ReleaseOrder |
W11.6 Release an order | command | oms |
ReleaseOrderResult |
set_working_condition |
SetWorkingCondition |
W11.7 Claim, hold or pause an order | command | ems, oms |
SetWorkingConditionResult |
create_placement |
CreatePlacement |
W11.8 Create a placement | command | ems |
CreatePlacementResult |
request_placement_change |
RequestPlacementChange |
W11.9 Ask for a change to a placement | command | ems, oms, connectivity |
RequestPlacementChangeResult |
report_placement |
ReportPlacement |
W11.10 Report a placement's progress | command | connectivity |
ReportPlacementResult |
report_execution |
ReportExecution |
W11.11 Report an execution | command | connectivity, ems, oms |
ReportExecutionResult |
report_charge |
ReportCharge |
W11.12 Report a charge | command | connectivity |
ReportChargeResult |
acknowledge_flag |
AcknowledgeFlag |
W11.14 Acknowledge a flag | command | oms, operations |
AcknowledgeFlagResult |
list_trading_instructions |
ListTradingInstructions |
W11.16 Hear and read the trading instructions in force | query | oms, ems, connectivity, portfolio, compliance |
ListTradingInstructionsResult |
list_orders |
ListOrders |
W11.17 Read orders, and an order's history | query | oms, ems, compliance, portfolio, operations, reporting, connectivity |
ListOrdersResult |
read_order_history |
ReadOrderHistory |
W11.17 Read orders, and an order's history | query | compliance, reporting, operations, oms |
ReadOrderHistoryResult |
record_locate |
RecordLocate |
W11.18 Record a locate and the prime's answer | command | connectivity |
RecordLocateResult |
list_locates |
ListLocates |
W11.18 Record a locate and the prime's answer | query | compliance, oms, portfolio |
ListLocatesResult |
record_locate_use |
RecordLocateUse |
W11.19 Reserve, give back or consume a locate | command | compliance, oms |
RecordLocateUseResult |
report_venue_catalogue |
ReportVenueCatalogue |
W11.20 Publish the venue's catalogue | event | connectivity |
Published |
read_venue_catalogue |
ReadVenueCatalogue |
W11.20 Publish the venue's catalogue | query | ems, oms |
ReadVenueCatalogueResult |
map_venue_account |
MapVenueAccount |
W11.22 Map an account to a venue account code | command | ems |
MapVenueAccountResult |
accept_execution |
AcceptExecution |
W11.23 Accept an unmatched execution to an order | command | ems |
AcceptExecutionResult |
dont_know_execution |
DontKnowExecution |
W11.24 Answer an unmatched execution DK | command | ems |
DontKnowExecutionResult |
report_value_date_roll |
ReportValueDateRoll |
W11.25 Report a value-date roll | command | connectivity |
ReportValueDateRollResult |
set_allocation_instruction |
SetAllocationInstruction |
W11.26 Set an order's allocation instruction | command | portfolio, operations, oms |
SetAllocationInstructionResult |
book_order |
BookOrder |
W11.27 Book an order's executions to its accounts | command | oms |
BookOrderResult |
hand_off_booking |
HandOffBooking |
W11.28 Hand off or close a booking | command | oms |
HandOffBookingResult |
correct_booking |
CorrectBooking |
W11.29 Correct a booking | command | oms, operations |
CorrectBookingResult |
list_bookings |
ListBookings |
W11.31 Read bookings | query | oms, operations, compliance, portfolio, reporting |
ListBookingsResult |
report_give_up |
ReportGiveUp |
W11.32 Report a give-up's answer | command | connectivity, confirmation |
ReportGiveUpResult |
record_sleeve_cross |
RecordSleeveCross |
W11.33 Record a sleeve cross | command | oms |
RecordSleeveCrossResult |
raise_alert |
RaiseAlert |
W11.34 Raise, acknowledge and clear an alert | command | compliance |
RaiseAlertResult |
acknowledge_alert |
AcknowledgeAlert |
W11.34 Raise, acknowledge and clear an alert | command | compliance |
AcknowledgeAlertResult |
list_alerts |
ListAlerts |
W11.35 Hear and read alerts | query | compliance, reporting, oms, operations |
ListAlertsResult |
read_local_record_orders |
ReadLocalRecordOrders |
W11.37 Read whether an order may name a local record | query | oms, ems, portfolio, compliance (connectivity's read dropped in chart 0.1.306) |
ReadLocalRecordOrdersResult |
list_replacements |
ListReplacements |
W3.22 Catch up on replacements | query | every role | ListReplacementsResult |
list_templates |
ListTemplates |
W3.24 Read the template catalogue | query | every role | ListTemplatesResult |
read_template |
ReadTemplate |
W3.24 Read the template catalogue | query | every role | ReadTemplateResult |
offer_template_fields |
OfferTemplateFields |
W3.23 Offer a template's fields | command | reference |
OfferTemplateFieldsResult |
read_calendar |
ReadCalendar |
W3.19 Read a calendar | query | every role | ReadCalendarResult |
compute_date |
ComputeDate |
W3.20 Work out a date | query | every role | ComputeDateResult |
report_event_group |
ReportEventGroup |
W3.29 Report an event group | command | data |
ReportEventGroupResult |
list_event_groups |
ListEventGroups |
W3.30 Read event groups, and hear each change | query | every role but pricing |
ListEventGroupsResult |
query_lake |
QueryLake |
W10.10 Query the lake within bounds | query | compliance, data, ems, operations, portfolio, reporting, signal |
QueryLakeResult |
read_agent_orders_demo_only |
ReadAgentOrdersDemoOnly |
W11.39 Read whether agents' orders are kept to demo connections | query | compliance, ems, oms, portfolio |
ReadAgentOrdersDemoOnlyResult |
run_job |
RunJob |
W12.1 Run a job | query | compliance, portfolio, reporting, signal |
RunJobResult |
list_measure_definitions |
ListMeasureDefinitions |
W12.1 Run a job | query | compliance, portfolio, reporting, signal |
ListMeasureDefinitionsResult |
list_price_batches |
ListPriceBatches |
W12.3 Price a batch | query | pricing |
ListPriceBatchesResult |
answer_price_batch |
AnswerPriceBatch |
W12.3 Price a batch | command | pricing |
AnswerPriceBatchResult |
list_finished_jobs |
ListFinishedJobs |
W12.4 Finish a job later, and read its answer | query | compliance, portfolio, reporting, signal |
ListFinishedJobsResult |
read_job_answer |
ReadJobAnswer |
W12.4 Finish a job later, and read its answer | query | compliance, portfolio, reporting, signal |
ReadJobAnswerResult |
record_rates |
RecordRates |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordRatesResult |
list_rates |
ListRates |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | compliance, portfolio, reporting, signal |
ListRatesResult |
record_liveness |
RecordLiveness |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordLivenessResult |
report_latency |
ReportLatency |
W4.16 Report a session's latency and a hop's data age | command | connectivity, data, ems (served) |
ReportLatencyResult |
report_placement_quote |
ReportPlacementQuote |
W11.40 Record a quote received on an RFQ placement | command | connectivity |
ReportPlacementQuoteResult |
pick_placement_quote |
PickPlacementQuote |
W11.41 Pick a quote received on an RFQ placement | command | ems |
PickPlacementQuoteResult |
list_execution_costs |
ListExecutionCosts |
W10.11 Record and read execution costs | query | compliance, ems, oms, operations, portfolio, reporting, signal |
ListExecutionCostsResult |
record_series |
RecordSeries |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordSeriesResult |
list_series |
ListSeries |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | ems, oms, portfolio, signal |
ListSeriesResult |
record_statistics |
RecordStatistics |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordStatisticsResult |
list_statistics |
ListStatistics |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | portfolio, reporting, signal |
ListStatisticsResult |
request_series_records |
RequestSeriesRecords |
W3.31 Ask for a listed series' record when it is wanted | command | ems, oms, portfolio, signal |
RequestSeriesRecordsResult |
record_lifecycle_event |
RecordLifecycleEvent |
W9.16 Book a listed option's or a future's lifecycle event as the broker reports it | command | connectivity, custody |
RecordLifecycleEventResult |
propose_lifecycle_events |
ProposeLifecycleEvents |
W9.17 Propose the lifecycle events expected | command | servicing |
ProposeLifecycleEventsResult |
release_lifecycle_event |
ReleaseLifecycleEvent |
W9.18 Release a proposed lifecycle event no report came for | command | operations |
ReleaseLifecycleEventResult |
list_lifecycle_events |
ListLifecycleEvents |
W9.19 Read lifecycle events, and hear each | query | operations, portfolio, reporting, servicing |
ListLifecycleEventsResult |
resolve_company |
ResolveCompany |
W3.32 Resolve a company, asking the platform on a miss | query | data |
ResolveCompanyResult |
record_corporate_actions |
RecordCorporateActions |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordCorporateActionsResult |
list_corporate_actions |
ListCorporateActions |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | portfolio, reporting, signal |
ListCorporateActionsResult |
record_derived_series |
RecordDerivedSeries |
W10.4 Record prices, bars, trades and quotes in batches | command | signal |
RecordDerivedSeriesResult |
list_derived_series |
ListDerivedSeries |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | compliance, portfolio, reporting, signal |
ListDerivedSeriesResult |
record_scenarios |
RecordScenarios |
W12.8 Save a scenario or a scenario set | command | signal |
RecordScenariosResult |
list_scenarios |
ListScenarios |
W12.8 Save a scenario or a scenario set | query | compliance, portfolio, reporting, signal |
ListScenariosResult |
read_stale_reference_actions_permitted |
ReadStaleReferenceActionsPermitted |
W6.38 Set the stale-reference actions the deployment permits | query | ems |
ReadStaleReferenceActionsPermittedResult |
record_filings |
RecordFilings |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordFilingsResult |
list_filings |
ListFilings |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | portfolio, reporting, signal |
ListFilingsResult |
record_reported_facts |
RecordReportedFacts |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordReportedFactsResult |
list_reported_facts |
ListReportedFacts |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | portfolio, reporting, signal |
ListReportedFactsResult |
record_holdings_reports |
RecordHoldingsReports |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordHoldingsReportsResult |
record_holdings |
RecordHoldings |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordHoldingsResult |
list_holdings |
ListHoldings |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | portfolio, reporting, signal |
ListHoldingsResult |
record_rating_actions |
RecordRatingActions |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordRatingActionsResult |
list_rating_actions |
ListRatingActions |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | portfolio, reporting, signal |
ListRatingActionsResult |
record_quality_assessments |
RecordQualityAssessments |
W10.12 Escalate a row's quality | command | signal |
RecordQualityAssessmentsResult |
record_factors |
RecordFactors |
W10.4 Record prices, bars, trades and quotes in batches | command | data |
RecordObservationsReply |
list_factors |
ListFactors |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | operations, portfolio, reporting, servicing, signal |
ListFactorsReply |
list_expirations |
ListExpirations |
W10.6 Read prices, bars, trades and quotes, point in time, by source | query | ems, oms, portfolio, signal |
ListExpirationsReply |
Role is the plugin role that publishes the step, or the roles that may ask the query, from the interface's matrix. A plugin can call an operation only if it holds one of them, approved when it was launched. Otherwise the call raises NotGranted. See Plugins, roles and grants and Plugin manifest.
Kind says what comes back:
- An event returns
Published, the message's identifier on the bus. - A command or a query returns the answer of whatever serves it.
W2 is holdings ingestion from a brokerage. It is read-only throughout: nothing in it places an order. A custody plugin records what the custodian says is held, and each activity on the account as the custodian states it, and an operations plugin reads it, within its read scope, and hears it change with their role classes' on_<event> methods, the stream of what a plugin's roles hear (W4.3, rpc Receive). W3 is instrument resolution. W6.4 is linking the accounts a source reaches to the firm's own, which a plugin does on its own page at admin, for the admin of the plugin viewing it under Manage. The tutorial Record a holdings statement walks through W2 and W6.4.
W9 is the book of record: the firm's own record of what each account holds, which an operations plugin opens with an opening balance a person confirms, reconciles with the street on each statement, and corrects only by entries that resolve its breaks. portfolio, reporting, compliance and oms read it, and hear it change with receive. W3.6 is forward resolution, by which those roles join a book position to its instrument. The book refuses an entry missing what tax tracking, valuation, confirmation or settlement need, and names each field it lacks.
Conventions¶
Calling¶
Every operation is an async method of the role class holding it, meridian.roles.<role>.Role, and takes keyword arguments only: in the class, await self.<operation>(...); elsewhere, on the role object the plugin registered, written role.<operation>(...) on this page. An operation two roles hold is the same call from either class, and core checks every call against the plugin's declared roles and grants. The connection (self.plugin) makes no operation. The return types are the generated protobuf messages in meridian.plugin.v1.operations_pb2. Each parameter crosses the wire under its own name. See Role classes.
import meridian
from meridian.roles import custody
class Custody(custody.Role):
async def on_start(self) -> None:
published = await self.report_sync_status(
source="snaptrade", external_account_id="acct-1", connection_healthy=True,
)
meridian.run(declaration=DECLARATION, roles=[Custody()], pages=pages, port=PORT)
An event a role hears is its on_<event> method (on_observations_wanted, on_activity_recorded), handed a Heard.
Numbers and amounts¶
Numbers are Decimal in Python, and exact integers that carry their own scale on the wire
A quantity takes a decimal.Decimal or an int. An amount of currency takes a meridian.Money: an amount and its ISO 4217 currency code, together, so an amount is never separated from its currency. A Money names its cash instrument, the code resolved by core, a token by its instrument alone.
On the wire a number is its integer, in two 64-bit halves, and the scale it was stated with. Decimal("1.50") crosses as 150 at scale 2 and reads back as 1.50. Nothing on either side is a float, and nothing normalises the scale.
A number is refused rather than rounded, in the plugin's process, before anything is sent:
| Given | Raised |
|---|---|
A float, a bool, or anything but a Decimal or an int |
TypeError: quantity is a Decimal or an int, not float |
NaN or infinity |
ValueError: quantity is not a finite number |
| More than 18 decimal places | ValueError: quantity has 19 decimal places; at most 18 cross the wire, and it is refused rather than rounded |
| More than 38 digits | ValueError: quantity has more than 38 digits; it is refused rather than rounded |
For an amount, anything but a meridian.Money |
TypeError: market_value is a meridian.Money, not Decimal |
A Money whose currency_code is not a str |
TypeError: market_value's currency_code is a str, not NoneType |
The sidecar holds a plugin that builds its params by hand to the same bounds, and refuses one outside them as invalid, naming the field.
Convert what the venue sent to the platform's convention before calling: amounts in the currency's major unit, and quantities in the instrument's own units. A plugin that read cents converts them. Keep what the venue sent, as sent, in the plugin's own logs. A float the venue sent becomes Decimal(repr(value)), its shortest round-trip form, never Decimal(value), its binary expansion.
meridian.as_decimal and meridian.as_money read a number, or an amount, back off the wire exactly as it was stated.
Enums¶
A parameter whose type is an enum, such as AssetClass or HoldingSide, takes the value (meridian.AssetClass.ASSET_CLASS_EQUITY), its name as a string ("ASSET_CLASS_EQUITY"), or that name without the enum's prefix in lower case ("equity"). None or "" leaves it unset. Anything else, a different case or a value the enum does not define, raises ValueError naming the parameter and the values it takes, before anything is sent. The sidecar refuses a number the enum does not define with invalid, for a plugin that builds its params by hand.
Times and dates¶
A parameter ending _ns is a time in nanoseconds, as an int. time.time_ns() gives one. as_of_date is an ISO 8601 date string, such as "2026-09-25".
Every field the data dictionary types date (a business date, an as-of date, a trade date, a value date) takes a datetime.date, or its ISO 8601 text, and crosses the wire as the text. Text that is no day that exists ("2026-02-30"), text in another form ("20261009") and a datetime, which is a moment, raise ValueError naming the field before anything is sent; the sidecar refuses an invalid date from a plugin that builds its params by hand. A date read back is the text: date.fromisoformat(price.meta.business_date). See Dates and time.
Note
The interface names the unit of _ns fields but not their epoch. The examples on this page assume the Unix epoch, which is what time.time_ns() returns.
Defaults¶
Every parameter except quantity has a default in Python: the empty string, 0, False, an empty sequence, or None. A default is what the wire carries when the field is unset. It does not mean the operation succeeds without the parameter. The Required column below says which parameters are needed, and who refuses a call without them.
What the sidecar sets¶
Some fields describe the publisher rather than the event, and only the sidecar knows them truthfully. They are not parameters:
| Field | On | Set by the sidecar from |
|---|---|---|
account_id |
RecordHoldingsStatement, RecordHolding, RecordActivity, ReResolveActivity |
The link an admin of the plugin made from the plugin's external_account_id to an account. Refused when there is none, as NotLinked. |
account_id |
ReportSyncStatus |
The same link, or empty when there is none. Never refused. |
publisher_instance_id |
ReportMissingInstrument |
The instance the plugin was launched as. |
placeholder_instrument_id |
ReportMissingInstrument |
Nothing: always empty from a plugin. Only the instrument store sets it. |
plugin_instance_id |
LinkExternalAccount |
The instance the plugin was launched as. |
The sidecar also puts the plugin's own instance in place of {instance} in a topic, so a plugin can speak only as itself.
Reads are within the read scope¶
The sidecar stamps the plugin's read scope on every read, and the store answers only within it: a read naming an account outside it is refused with NotGranted, one naming none answers every account in it, and a plugin whose read scope is empty reads nothing. A plugin reads its whole scope as itself, and serves each person from it with caller.read. What it hears with their role classes' on_<event> methods is held to the same scope.
Each read answers a page, the next page's cursor in next_cursor, empty on the last, and as_of, the Watermark it was read at. Given a watermark as since, a read answers only what changed after it. receive reads this way to seed and to catch up, so a plugin hearing a row seldom reads it itself.
Acting for a person¶
Thirteen operations take acting_for: the two commands that record holdings, the one that records an activity and the one that re-resolves it; the seven commands of the book; and the two that link accounts. Pass the Meridian-Caller header of the page request you are serving: in a view on meridian.Pages, request.caller.header; with CallerMiddleware, request.state.caller.header.
For record_holdings_statement, record_holding, record_activity, re_resolve_activity and the book's commands, the sidecar applies the same rule:
- Unset: the plugin acts as itself.
- Set: the sidecar checks the assertion, admits the command only in a session opened by Open, at
write, and only when that person may write the account it names, and stamps the person on it. For a command that names no account, the person must be able to write something through the plugin. A command sent for a person in a session opened by Manage or View is refused withNotGranted, naming the session. The person must holdwriteon a role of the plugin whose grants include the command, the account among that role's write accounts: otherwise it is refused withNotGranted, naming each role that holds the command and what the person holds on it, such as RecordHoldingsStatement is custody's, and Ada Park holds read on custody. On a plugin holding one role this is the rule above. See Access per role.
A person narrows what a plugin may do and never widens it.
A service account's header. An act's route reached for a call the dashboard admitted for the role's service account reads a caller whose subject_kind is a service account, naming its owner (see Caller). Pass its header as acting_for, as for a person: the sidecar admits the command as it admits a person's under Open, by the account's write on the role and its accounts there, and stamps the service account, its kind and its owner beside it (acting_for_kind, owner_subject). Such claims are good for that one call, for at most 60 seconds, and reach no read or command of the deployment's configuration but filing a ticket and reading back what was filed: read_accounts_for_linking, link_external_account, reading a prepared change and saving a person's own settings are refused.
Of the book's commands, the findings (record_break, record_account_figures and record_encumbrances) are a plugin's to send as itself. The rest are justified acts, which the book refuses without a person or a service account, and a reason: see The book's commands.
For read_accounts_for_linking and link_external_account, it is required. They touch the deployment's configuration, which a plugin reaches only acting for an admin of the plugin in a session opened by Manage, at admin, and never as itself. Without an assertion, or with one from a session at any other level, the sidecar refuses the call with NotGranted. They are the only reads and commands the sidecar admits for a person in a Manage session: that session reaches no account's data.
The book's commands¶
Every command of the book answers after its entry commits, with every record it changed: see Book entry result.
- A finding or a person's act. A break, the figures and the encumbrances are findings, which the plugin may send as itself, acting for nobody. An opening balance, a break's cause and handling, its resolution and closing it as cleared are a person's: send them
acting_forthat person, with theirreason, or the book refuses them withREFUSAL_REASON_ACTOR_REQUIREDorREFUSAL_REASON_REASON_REQUIRED. The book records the person, or the plugin's instance, as the entry's actor. They are a user's, a person's or a service account's: a route reached for the role's service account sends themacting_forits header, the reason still required, and the book records the service account and its owner. - One arm of a oneof, by keyword. Where a message holds one of several things, the method takes each as a keyword: a break's
position=orfigure=, a resolution'sadjustment=,reversal=,entries=orexplanation=, a basis adjustment'scost_change=orstated_cost=, a cause's item. Two at once raiseValueErrornaming the oneof, before anything is sent. - The book's own refusals carry a code, and the SDK raises them as
CommandRefused. An incomplete entry's refusal also names each field it lacks: see What the book requires.
Idempotency keys¶
Each of the book's commands takes an idempotency_key: the plugin's key for the command, derived from its source, unique per account. The same command again with the same key is answered with the first's reply and applies nothing, so a plugin restarted halfway, or a person retrying after a lost reply, records nothing twice. The sidecar mints each message's identifier, so a retry is a new message: the key is what makes it the same command. A different command under a key the account's book already holds is refused with REFUSAL_REASON_IDEMPOTENCY_CONFLICT, nothing applied. Empty sends none.
Derive a key from what the command is about, such as opening/{account}/{statement} for an opening balance composed from a statement, or break/{account}/{statement}/{subject}/{category} for a break found in it.
Errors¶
A refusal is the call's gRPC status, chosen by what the caller should do about it. The SDK raises it as one of its own exceptions:
| Raised | Sidecar status | Means | Your next move |
|---|---|---|---|
NotGranted |
PERMISSION_DENIED |
None of the plugin's roles grants this operation; or the account is outside the plugin's write scope, or, for a read, its read scope; or the person in acting_for may not write it, or sent it from a session not opened by Open; or an operation on the deployment's configuration without the assertion of an admin of the plugin under Manage; or a new account named by somebody who is not a deployment admin; or a link for an external account this plugin did not report. |
Stop. It is configuration: a role, a permission, a link or an admin, which a person changes. |
NotLinked, kind="refused" |
FAILED_PRECONDITION, with the code REFUSAL_REASON_EXTERNAL_ACCOUNT_NOT_LINKED |
An external_account_id nobody has linked to an account. See An unlinked external account. |
Offer it for linking, and stop this statement. An admin of the plugin links the account, and the next statement records it. |
CallFailed, kind="refused" |
FAILED_PRECONDITION, with no code |
The sidecar considers the plugin not registered, or already left. | Connect again. |
CallFailed, kind="invalid" |
INVALID_ARGUMENT |
A required field is empty, such as external_account_id; or a number outside what the wire carries, in params built by hand. |
Fix the call. |
CallFailed, kind="no handler" |
UNAVAILABLE |
Nothing serves the topic right now. | Retry later. |
CallFailed, kind="timeout" |
DEADLINE_EXCEEDED |
What serves it did not answer in time. | Retry. |
CommandRefused, kind="refused" |
ABORTED, with a code |
The book refused the command with a code of its own, such as REFUSAL_REASON_BREAK_STATE, or REFUSAL_REASON_INCOMPLETE with each missing field in fields. See The book's refusals. |
Act on the code: read the book again and say what stands, or ask the person for what was missing, which fields names. Not retried. |
CallFailed, kind="handler error" |
ABORTED, with no code |
What serves it answered with a refusal. detail is its reason. |
Report it. |
CallFailed, kind="not vouched for" |
UNAUTHENTICATED |
The acting_for assertion was not accepted: expired, replayed, for another instance, or the sidecar holds none of the dashboard's keys. |
Ask the person to reload the page. |
NotRegistered |
none (raised by the SDK) | The plugin has called leave(). |
Don't use it after leaving. |
TypeError, ValueError |
none (raised by the SDK) | A number that is not a Decimal or an int, an amount that is not a Money, or a number that would have to be rounded; a statement whose figures the sidecar would refuse. |
Fix the call. |
grpc.aio.AioRpcError |
any other, such as INTERNAL |
Raised unchanged. |
On NotGranted and CallFailed, topic holds the operation's name, such as "RecordHolding". The exception's text is the operation's name, then the kind, then the sidecar's own words. For a row naming an external account nobody has linked:
RecordHolding: refused: external account acct-1 is not linked to an account; a deployment admin links it on the plugin's admin page (W6.4), and the next statement records it
Match on the exception's class, and on kind, never on these words: they are for a person reading a log, and may be reworded at any release.
Note
NotGranted and CallFailed use an attribute called topic, but for typed operations it holds the operation's name, not a bus topic.
An unlinked external account¶
A row naming an external account that nobody has linked is refused, and nothing is recorded for it. That refusal carries a code, so a plugin can tell it apart from the other refusal with the same status, a plugin that is not registered.
The sidecar sends the code beside the status: a meridian.v1.Refusal, encoded, in the call's trailing metadata meridian-refusal-bin. Its reason comes from the refusal catalogue, the RefusalReason enum in meridian/v1/sidecar.proto:
| Reason | Number | Status | Sent when |
|---|---|---|---|
REFUSAL_REASON_UNSPECIFIED |
0 | Never sent. A refusal the status already says everything about carries no code. | |
REFUSAL_REASON_EXTERNAL_ACCOUNT_NOT_LINKED |
1 | FAILED_PRECONDITION |
The operation named an external account nobody has linked to an account. Nothing was recorded, and the next statement after a link records it. |
REFUSAL_REASON_ACTOR_REQUIRED … REFUSAL_REASON_INCOMPLETE |
2 to 11 | ABORTED |
The book's refusals. See The book's refusals. |
REFUSAL_REASON_AGENT_LIVE_ORDER |
31 | ABORTED |
The book's refusal of an agent's order on a connection that is not demo. See The book's refusals. |
A reason is never reused for another cause, and a retired one's number stays reserved. record_holding can be refused this way, as can record_holdings_statement, which names its external account too, and record_activity; report_sync_status for an unlinked account is not refused.
The SDK reads the code and raises meridian.NotLinked. It is a CallFailed whose kind is "refused", as this refusal always was, so a plugin that caught CallFailed still catches it. It is raised by the code alone: a refusal that carries no code is a plain CallFailed, whatever its words say. A sidecar from before the catalogue sends none, so on such a deployment the same refusal arrives as CallFailed with kind="refused", which catching CallFailed still covers.
Catch NotLinked. Do not match the text of the exception:
try:
await role.record_holding(..., external_account_id="acct-3")
except meridian.NotLinked:
... # offer acct-3 for linking; stop this statement
To know before sending, read the plugin's links from account_scope(): scope.link_of("acct-3") is None while it is unlinked. The link can still be removed between reading and sending, so catch NotLinked all the same.
A plugin written in another language reads the same trailer: decode the Refusal from meridian-refusal-bin and compare its reason.
The book's refusals¶
The book of record refuses with a code, which the sidecar carries beside ABORTED in the same trailer, meridian-refusal-bin. The SDK raises meridian.CommandRefused: a CallFailed whose kind is "refused", with reason, the code's number, and reason_name, its name. It also has fields, a tuple of each field the command left out, by its path in the call, read from the same Refusal's fields; only REFUSAL_REASON_INCOMPLETE carries any, and every other refusal has none. Match the code and the paths, never the words.
| Reason | Number | Sent when |
|---|---|---|
REFUSAL_REASON_ACTOR_REQUIRED |
2 | A person's act sent for nobody: an opening balance, a break's handling, its resolution or closing, or an account's attribute: a user's act, a person's or a service account's. |
REFUSAL_REASON_REASON_REQUIRED |
3 | A justified act sent without its reason or explanation. |
REFUSAL_REASON_OPENING_BALANCE_RECORDED |
4 | A second opening balance while one stands. |
REFUSAL_REASON_NO_OPENING_BALANCE |
5 | A break, figures, encumbrances or an entry for an account with no opening balance. |
REFUSAL_REASON_BEFORE_OPENING_BALANCE |
6 | An entry moving a position effective on or before the opening balance's date. |
REFUSAL_REASON_LOTS_UNBALANCED |
7 | An opening position whose lots do not sum to its quantity, or an entry that would leave a position's open lots so. |
REFUSAL_REASON_BREAK_STATE |
8 | Updating, handling, resolving or closing a break that is not open. |
REFUSAL_REASON_LATER_ENTRIES_STAND |
9 | A reversal of an opening balance while a later entry moving the account's positions stands. |
REFUSAL_REASON_IDEMPOTENCY_CONFLICT |
10 | A key the account's book holds for a different command. |
REFUSAL_REASON_INCOMPLETE |
11 | An opening balance, or an adjustment opening a lot, missing a field the book requires, nothing applied. Each missing field is in fields. See What the book requires. |
REFUSAL_REASON_AGENT_LIVE_ORDER |
31 | A placement, or an accept of venue-originated fills to a new order, made through a delegation or by a service account on a connection that is not demo, while the agents' guard is on. Refused and recorded: an entry on the order names the ems, the connection and the actor, and a refused accept leaves the fills unmatched. A person's own act, and one a person makes from an agent's prepared change, are never refused by it. Check before sending with Caller.agent_refused, and offer the person a prepared change rather than retrying. |
The order path's other codes, and booking's, are on The order lifecycle and Booking.
try:
await role.record_opening_balance(..., acting_for=caller.header)
except meridian.CommandRefused as refused:
if refused.reason_name == "REFUSAL_REASON_OPENING_BALANCE_RECORDED":
... # already recorded: read it back with list_account_attributes and say so
elif refused.reason_name == "REFUSAL_REASON_INCOMPLETE":
... # show the person what to supply: ("positions[0].settled_quantity", ...)
What the book requires¶
The book refuses an entry missing what its downstream activities need, tax tracking, valuation, confirmation and settlement, with REFUSAL_REASON_INCOMPLETE, nothing applied, and names every missing field in CommandRefused.fields by its path in the call's parameters. The refusal applies to every plugin, whatever SDK it was built on. See What the book requires for why.
Of an opening balance (record_opening_balance):
| Path | Missing when |
|---|---|
as_of_date |
Empty. |
sources |
No source at all, even for an account entering holding nothing. |
sources[n].name |
A source naming no custodian or system, on a balance holding positions. |
positions[n].instrument_id, positions[n].side, positions[n].trade_date_quantity |
Unset. |
positions[n].settled_quantity |
Unset. Where the source states none, a person supplies it. |
positions[n].pending[m].quantity, positions[n].pending[m].value_date |
Unset or empty: every pending quantity has its value date. |
positions[n].pending |
The settled quantity and the pending quantities do not account for the whole trade-date quantity: the rest, neither settled nor pending on a date, is pending nobody has given. |
positions[n].lots |
No lots, on a position whose instrument's record says it is not cash. |
positions[n].lots[m].quantity, positions[n].lots[m].terms.cost, positions[n].lots[m].terms.acquired_date |
Unset or empty: every lot carries its quantity, its cost in all, and its acquisition date. |
Of an adjustment (resolve_break): adjustment.lines[n].opens_lot.cost and adjustment.lines[n].opens_lot.acquired_date, on a line that opens a lot without them.
The book reads whether an instrument is cash from its record: its asset class, or a currency identifier. Cash has no lots. Where the record cannot say, because the position is held under a placeholder, the record names no asset class and no currency identifier, or the instrument store does not answer in time, the book does not require its lots, for now, and still refuses any lot sent incomplete. An operations plugin flags such a position, and it does not hold the confirmation back.
A lot of unknown cost and the settlement bucket "not stated" are not admitted. They stay on the wire for what older records hold: BookPosition.not_stated_quantity is zero on every position the book records now, and its settled_quantity is set.
Refusals on a development deployment¶
On a development deployment, a refusal by the sidecar itself, for a grant, the write scope, the deployment's configuration, an external account the plugin did not report, or a number out of range, also appears as a refused event.
report_external_accounts¶
Reports every external account the plugin's connection reaches, as the source presents them. A custody plugin sends it before it records anything, and again whenever the list changes. One connection can reach several accounts, and an admin can link only an account the plugin reported.
It is the whole list each time. An account missing from it is one the connection no longer reaches.
async def report_external_accounts(
self, *, accounts: Sequence[ExternalAccount] = (),
) -> Published
| gRPC | rpc ReportExternalAccounts(ReportExternalAccountsParams) returns (Published) |
| Workflow step | W2.8, Report the accounts a connection reaches |
| Kind | event, on platform.custody.{instance}.event.external-accounts |
| Role | custody |
| Heard by | the dashboard, which counts the unlinked ones on the plugin's health |
| Name | Type | Required | Meaning |
|---|---|---|---|
accounts |
sequence of ExternalAccount |
no | Every account the connection reaches. |
The sidecar keeps the list as the accounts a link from this plugin may name.
Returns Published, with message_id, the message's identifier on the bus.
Errors: NotGranted without the custody role.
import meridian
await role.report_external_accounts(
accounts=[
meridian.ExternalAccount(
external_account_id="acct-1", name="Individual brokerage", venue_account_type="Individual"
),
meridian.ExternalAccount(
external_account_id="acct-2", name="Rollover IRA", venue_account_type="IRA"
),
],
)
report_sync_status¶
Reports how fresh a connected account's data is, as the rail (the brokerage aggregator) reports it, and why when it is not current. It is published so an operator can tell stale data from absent data, and knows whose fix it is. Those look identical on a holdings screen and mean different things.
async def report_sync_status(
self, *, source: str = "", last_synced_at_ns: int = 0, connection_healthy: bool = False,
status_detail: str = "", observed_at_ns: int = 0, external_account_id: str = "",
state: SyncState | str | None = None, holdings_as_of_ns: int = 0, history_as_of_ns: int = 0,
history_from: str = "",
) -> Published
| gRPC | rpc ReportSyncStatus(ReportSyncStatusParams) returns (Published) |
| Workflow step | W2.1, Observe the brokerage sync state |
| Kind | event, on platform.custody.{instance}.event.sync-status |
| Role | custody |
| Heard by | the dashboard, which shows it on the Overview tab of the plugin's view in Settings; and the street store, which keeps each one for operations to read and hear (W2.13, see list_sync_statuses) |
| Name | Type | Required | Meaning |
|---|---|---|---|
source |
str |
no | The rail's namespace, such as "snaptrade". |
last_synced_at_ns |
int |
no | When the rail last synced this account from the institution. Not when the data is as of: see the two _as_of_ns fields. |
connection_healthy |
bool |
no | Whether the rail considers the connection healthy now. False with a recent last_synced_at_ns means the data is good but the connection has since broken. state says why. |
status_detail |
str |
no | The rail's text, for whatever state does not say. Diagnostic only; nothing branches on it. |
observed_at_ns |
int |
no | When the plugin observed this. |
external_account_id |
str |
yes, by the sidecar | The account as the rail knows it. The sidecar refuses it when empty (invalid). It is not refused when unlinked: the dashboard shows the status beside the unlinked account, so an admin can tell whether it is worth linking. |
state |
SyncState or None |
no | Whether the data is current, and if not, why. None leaves it unset, which reads as SYNC_STATE_UNSPECIFIED, shown as what connection_healthy says. |
holdings_as_of_ns |
int |
no | When the holdings the rail serves are as of. 0 where the rail does not say. |
history_as_of_ns |
int |
no | When the history (transactions) is as of. Apart from holdings, because a connection can have one current and the other not. |
history_from |
str |
no | The first date, ISO 8601, the source can read the account's activity from: how far back a backfill of record_activity reaches, beside how fresh the history is. Empty where the source does not say. |
Returns Published, with message_id, the message's identifier on the bus.
Errors: invalid for an empty external_account_id; NotGranted without the custody role.
import time
import meridian
await role.report_sync_status(
source="snaptrade",
external_account_id="acct-1",
connection_healthy=True,
state=meridian.SyncState.SYNC_STATE_CURRENT,
last_synced_at_ns=last_sync_ns,
holdings_as_of_ns=last_sync_ns,
history_from="2024-06-03", # the first day of the history it can read
observed_at_ns=time.time_ns(),
)
record_holdings_statement¶
Opens one statement: the plugin's snapshot of one account, at one moment. Every holding row then attaches to it.
The statement names that account, as the source knows it, and the sidecar records it against the account the external account is linked to, as it does a row. A statement is one account's: a row naming another account is refused.
It carries two dates, and they are not the same thing:
as_of_dateis the date the positions reflect.read_at_nsis when the plugin fetched them.
A statement read this morning may be as of yesterday's close.
async def record_holdings_statement(
self, *, source: str = "", external_statement_id: str = "", as_of_date: str = "",
read_at_ns: int = 0, expected_rows: int = 0, buying_power: Money | None = None,
margin_requirement: Money | None = None, maintenance_excess: Money | None = None,
currency_assumed: bool = False, external_account_id: str = "",
figures: Sequence[StatementFigures] = (), institution: str = "",
security_interest: bool | None = None, acting_for: str | None = None,
) -> RecordHoldingsStatementResult
| gRPC | rpc RecordHoldingsStatement(RecordHoldingsStatementParams) returns (RecordHoldingsStatementResult) |
| Workflow step | W2.2, Open a holdings statement |
| Kind | command, on platform.street.command.record-statement |
| Role | custody |
| Served by | the street store: what custodians say is held |
| Name | Type | Required | Meaning |
|---|---|---|---|
source |
str |
no | The rail's namespace, such as "snaptrade". |
external_statement_id |
str |
no | The plugin's identifier for this snapshot, made from the account it read and when it read it, so the same read sent twice has the same one. Used to recognise a redelivery of the same statement. |
as_of_date |
str |
no | The ISO 8601 date the positions are as of. |
read_at_ns |
int |
no | When the plugin read them. |
expected_rows |
int |
yes, by the workflow | How many holding rows will follow. It is the only thing that marks the end of a statement. The street store closes the statement when this many rows have landed. A statement whose rows never all arrive stays open rather than publishing counts that are wrong. Hold the whole list before recording any of it. |
external_account_id |
str |
yes, by the sidecar | The account as the rail knows it, the one the statement's rows name. The sidecar translates it through its link, and refuses it when empty or not linked. |
institution |
str |
no | The institution holding the external account, as the plugin names it: the brokerage behind an aggregator, as SnapTrade names it, or the venue itself for a plugin that reads the venue directly. Empty where the source does not say. |
figures |
sequence of StatementFigures |
no | The account's figures, one set per margin segment the venue reports, each naming its segment as the venue does; the set with no segment is the account's as a whole. No two sets name the same segment. Every figure is as the venue reported it, and never derived from the holdings. |
currency_assumed |
bool |
no | True when the venue stated no currency for these figures, and the one given is the plugin's own assumption. Of every set in figures. Deprecated for the figures' provenance (keep what your custody plugin converts). |
security_interest |
bool or None |
no | True when the account servicer holds a lien or a right of set-off over the account, as the statement reports it; None where it does not say. Not an encumbrance: it reduces no holding's available quantity. |
buying_power, margin_requirement, maintenance_excess |
Money or None |
no | Superseded by figures. Sent alone, they are read as the set with no segment; sent beside figures, they are refused. meridian plugin migrate rewrites them into figures. |
acting_for |
str or None |
no | The Meridian-Caller header of the person this is sent for. See Acting for a person. |
A brokerage's own total account value goes in net_liquidation, in the set with no segment, as the brokerage reports it: never a sum the plugin makes of the holdings.
Returns RecordHoldingsStatementResult:
| Field | Type | Meaning |
|---|---|---|
statement_id |
str |
Assigned by the deployment. Every row references it. |
already_recorded |
bool |
True when this statement had already been recorded and the existing one is returned. Redelivery is a no-op, not a duplicate. |
Errors:
TypeErrororValueErrorfor an amount or a number, one insidefiguresnamed by its path (figures[0].collateral[1].haircut).ValueError, before anything is sent, for two sets naming one segment, a collateral balance neither posted nor received, or a flat figure besidefigures, in the sidecar's words: the sidecar refuses each asinvalidtoo.invalidfor an emptyexternal_account_id, andNotLinkedfor one not linked.NotGrantedwhen the linked account is outside the plugin's write scope, or when the person inacting_formay not write it.not vouched forfor anacting_forthat is not accepted.handler errorfrom the street store for a statement it refuses, with its reason, such as a collateral balance naming both or neither of an instrument and identifiers.no handlerortimeoutfrom the street store.NotGrantedwithout thecustodyrole.
import time
from decimal import Decimal
import meridian
statement = await role.record_holdings_statement(
source="snaptrade",
external_statement_id="acct-1@2026-09-25T13:30:00Z",
external_account_id="acct-1",
institution="Interactive Brokers",
as_of_date="2026-09-25",
read_at_ns=time.time_ns(),
expected_rows=len(rows),
figures=[
meridian.StatementFigures(
segment="",
buying_power=meridian.Money(Decimal("25000.00"), "USD"),
net_liquidation=meridian.Money(Decimal("93550.00"), "USD"),
),
],
)
record_holding¶
Records one holding, for one account, at one instrument, on one side, against an open statement.
Set exactly one of instrument_id and unresolved_identifiers:
instrument_idwhenresolve_identifierfound it: an instrument, perhaps the deployment's ownLCL-record, minted for an identifier set nothing matched;unresolved_identifierswhen it did not, because more than one instrument matched.
A row that could not be resolved is still recorded. A dropped holding would be invisible.
Cash is a holding like any other: of the currency's cash instrument, which the identifier scheme iso4217 names (scheme="iso4217", value="USD"), with the cash the venue reports in that currency as its quantity.
async def record_holding(
self, *, statement_id: str = "", instrument_id: str = "",
unresolved_identifiers: Sequence[Identifier] = (), quantity: Decimal | int,
market_value: Money | None = None, external_account_id: str = "",
side: HoldingSide | str | None = None, settle_date_quantity: Decimal | int | None = None,
currency_assumed: bool = False, also_counted_in_cash: bool = False,
cost_basis: Money | None = None, lots: Sequence[ReportedLot] = (),
margin_requirement: Money | None = None, average_cost: Money | None = None,
available_quantity: Decimal | int | None = None,
not_available_quantity: Decimal | int | None = None,
available_basis: AvailableBasis | str | None = None,
encumbrances: Sequence[ReportedEncumbrance] = (), acting_for: str | None = None,
) -> RecordHoldingResult
| gRPC | rpc RecordHolding(RecordHoldingParams) returns (RecordHoldingResult) |
| Workflow step | W2.3, Publish each holding |
| Kind | command, on platform.street.command.record-holding |
| Role | custody |
| Served by | the street store |
| Name | Type | Required | Meaning |
|---|---|---|---|
statement_id |
str |
yes, by the street store | The statement_id that record_holdings_statement returned. |
instrument_id |
str |
one of these two, by the street store | The instrument, when resolution found one: perhaps a record the deployment minted. |
unresolved_identifiers |
sequence of Identifier |
one of these two, by the street store | Everything the plugin held, when resolution was ambiguous, so an operator can see exactly what could not be accounted for. |
quantity |
Decimal or int |
yes, by Python | The trade-date quantity: what is held counting every trade executed, settled or not. Signed to match side: negative is short. At most 18 decimal places. |
market_value |
Money or None |
no | The rail's valuation of the holding, in its currency, recorded as reported and not recomputed. None where the venue reported none, which is not a value of zero. |
external_account_id |
str |
yes, by the sidecar | The account as the rail knows it. The sidecar translates it through its link, and refuses it when empty or not linked. |
side |
HoldingSide or None |
yes, by the street store | Long or short, stated rather than read off the sign. None leaves it unset, and the street store refuses the row. A venue that reports an account's long and short of one instrument apart sends two rows, one on each side. |
settle_date_quantity |
Decimal, int or None |
no | The settle-date quantity: what is held counting only settled trades, where the venue reports it. For cash, the settled cash. |
currency_assumed |
bool |
no | True when the venue stated no currency, and the one given is the plugin's own assumption: the market value's currency, and for cash the currency whose cash instrument the row names. Deprecated for the row's provenance. |
also_counted_in_cash |
bool |
no | True when this position's value is also included in the account's cash holding as the venue reports it. Deprecated: the street counts each asset once, and a custody plugin sends the cash net of the fund (keep what your custody plugin converts). |
cost_basis |
Money or None |
no | The holding's total cost, as the venue reports it. |
average_cost |
Money or None |
no | The venue's average cost per unit, in the venue's own unit: SnapTrade's is per share, even for an option whose quantity counts contracts. Never multiplied out by the quantity or a multiplier into a cost basis, nor a cost basis divided into it: give whichever the venue reports, or both. |
lots |
sequence of ReportedLot |
no | The holding's lots as the venue lists them. None is not one lot, and lots whose quantities do not sum to the holding's are recorded as reported. |
margin_requirement |
Money or None |
no | The margin requirement on the holding, as the venue reports it. |
available_quantity, not_available_quantity |
Decimal, int or None |
no | What of the holding is available and what is not, each as the source reports it, never derived from the other or from the quantity: available is never the quantity less what is encumbered. None where the source gives none. |
available_basis |
AvailableBasis, str or None |
no | What the available quantity is on, as the source says. |
encumbrances |
sequence of ReportedEncumbrance |
no | Each sub-balance the source reports as encumbered, one per kind, location and pledgee. Empty means none reported, not none held. |
acting_for |
str or None |
no | The Meridian-Caller header of the person this is sent for. |
Returns RecordHoldingResult:
| Field | Type | Meaning |
|---|---|---|
holding_id |
str |
The recorded row. |
resolved |
bool |
True when the row carried an instrument and updated a custodial position. False for an unresolved row, which updates nothing until the deployment knows what it holds. |
Errors:
TypeErrororValueErrorfor a number or an amount, one insidelotsnamed by its path (lots[0].cost).invalidfor an emptyexternal_account_id, andNotLinked, aCallFailedof kindrefused, for one not linked. The sidecar counts the unlinked account in its report of the plugin, and the next statement after it is linked records it.NotGrantedwhen the linked account is outside the plugin's write scope, as a closed account is, or when the person inacting_formay not write it.not vouched forfor anacting_forthat is not accepted.handler errorfrom the street store for a row it refuses, with its reason. It refuses a row that states no side, a quantity whose sign contradicts its side, both or neither ofinstrument_idandunresolved_identifiers, a statement it has not opened, or an account other than its statement's.no handlerortimeoutfrom the street store.
from decimal import Decimal
import meridian
result = await role.record_holding(
statement_id=statement.statement_id,
instrument_id=instrument_id,
side=meridian.HoldingSide.HOLDING_SIDE_LONG,
quantity=Decimal("150"),
market_value=meridian.Money(Decimal("34218.75"), "USD"),
external_account_id="acct-1",
cost_basis=meridian.Money(Decimal("21000.00"), "USD"),
lots=[
meridian.ReportedLot(quantity=Decimal("100"), cost=meridian.Money(Decimal("13500.00"), "USD"),
acquired_date="2025-03-14"),
meridian.ReportedLot(quantity=Decimal("50"), cost=meridian.Money(Decimal("7500.00"), "USD"),
acquired_date="2026-01-08"),
],
)
# An instrument that resolved ambiguously is still recorded. A short row's
# quantity is negative, and a venue that reported no value sends none:
await role.record_holding(
statement_id=statement.statement_id,
unresolved_identifiers=[meridian.Identifier(scheme="symbol", value="XYZQ", source="snaptrade")],
side=meridian.HoldingSide.HOLDING_SIDE_SHORT,
quantity=Decimal("-10"),
external_account_id="acct-1",
)
list_custodial_positions¶
Reads what the custodian says the accounts in the plugin's read scope hold, and, beside it, the holdings that could not be named, so one read answers both what is held and what could not be accounted for. See Reads are within the read scope.
async def list_custodial_positions(
self, *, account_id: str = "", include_unresolved: bool = False, page_size: int = 0,
cursor: str = "", since: Watermark | None = None,
) -> ListCustodialPositionsResult
| gRPC | rpc ListCustodialPositions(ListCustodialPositionsParams) returns (ListCustodialPositionsResult) |
| Workflow step | W2.7, Read custodial positions |
| Kind | query, on platform.street.query.list-custodial-positions |
| Role | operations |
| Served by | the street store |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
no | One account, which must be in the plugin's read scope. Empty for every account in it. |
include_unresolved |
bool |
no | Also answer the holdings that never resolved, with the first page only, so a read across pages sees each once. |
page_size |
int |
no | How many to a page: 100 when 0, and never more than 500. |
cursor |
str |
no | The previous page's next_cursor, or empty for the first. |
since |
Watermark or None |
no | Only the positions whose last change is after it, removed ones included. |
Returns ListCustodialPositionsResult:
| Field | Type | Meaning |
|---|---|---|
positions |
sequence of CustodialPosition |
The positions on the page. A removed one is answered only to a read given since. |
unresolved |
sequence of UnresolvedHolding |
With include_unresolved, on the first page. |
next_cursor |
str |
The next page's cursor, empty on the last. |
as_of |
Watermark |
The point in the store's record the page was read at. |
Errors: NotGranted for an account_id outside the read scope, and without the operations role. no handler, timeout or handler error from the street store.
page = await role.list_custodial_positions(include_unresolved=True)
for position in page.positions:
quantity = meridian.as_decimal(position.quantity)
list_statements¶
Reads the completed statements of the accounts in the plugin's read scope, each as the street store announced it when its last row landed. A statement's figures are on it and on no position, so this is how a plugin reads them without having heard the statement. An open statement is not listed: until all its rows have landed, it is not the custodian's whole word on the account. See Reads are within the read scope.
async def list_statements(
self, *, account_id: str = "", as_of_date: str = "", since: Watermark | None = None,
page_size: int = 0, cursor: str = "",
) -> ListStatementsResult
| gRPC | rpc ListStatements(ListStatementsParams) returns (ListStatementsResult) |
| Workflow step | W2.9, Read completed statements |
| Kind | query, on platform.street.query.list-statements |
| Role | operations |
| Served by | the street store |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
no | One account, which must be in the plugin's read scope. Empty for every account in it. |
as_of_date |
str |
no | Only statements as of this ISO 8601 date. Empty for any. |
since |
Watermark or None |
no | Only the statements completed after it. |
page_size |
int |
no | How many to a page: 100 when 0, and never more than 500. |
cursor |
str |
no | The previous page's next_cursor, or empty for the first. |
Returns ListStatementsResult:
| Field | Type | Meaning |
|---|---|---|
statements |
sequence of StatementRecordedEvent |
The completed statements on the page. |
next_cursor |
str |
The next page's cursor, empty on the last. |
as_of |
Watermark |
The point in the store's record the page was read at. |
Errors: NotGranted for an account_id outside the read scope, and without the operations role. no handler, timeout or handler error from the street store.
page = await role.list_statements(account_id="ACC-…")
for statement in page.statements:
for figures in statement.figures:
if figures.HasField("net_liquidation"):
value = meridian.as_money(figures.net_liquidation)
record_activity¶
Records one activity on an account as the custodian states it: a purchase, a sale, a reinvested dividend, a dividend or interest, a fee or a tax, a split or another corporate action, a transfer, a contribution, a withdrawal or a journal. It is evidence that explains a break, never a source: the street store keeps it as reported and derives no position, lot or figure from it, and nothing moves the book until a person confirms. See The custodian's activity, and Report the custodian's activity for a custody plugin's side.
async def record_activity(
self, *, external_account_id: str = "", source: str = "",
activity: CustodialActivity | None = None, acting_for: str | None = None,
) -> RecordActivityResult
| gRPC | rpc RecordActivity(RecordActivityParams) returns (RecordActivityResult) |
| Workflow step | W2.10, Record an account's activity |
| Kind | command, on platform.street.command.record-activity |
| Role | custody |
| Served by | the street store, which announces each new one as ActivityRecorded (W2.12) to operations |
| Stability | preview |
| Name | Type | Required | Meaning |
|---|---|---|---|
external_account_id |
str |
yes, by the sidecar | The account as the source knows it, which the sidecar translates to the account it is linked to. |
source |
str |
yes, by the sidecar | The plugin's scheme for its source, as on a statement, such as "snaptrade". |
activity |
CustodialActivity or None |
yes, by the sidecar | The activity, as the custodian states it. |
acting_for |
str or None |
no | Unset: the plugin reports as itself, as it does on every sync. See Acting for a person. |
The street keeps an activity once, by its source, its account and its external_activity_id. Sent again under the same identifier, it is answered already_recorded with the first one's activity_id, recorded and announced once, so a retry, a restart or a backfill sent again records nothing twice. A custodian restating an activity under a new identifier is a new activity, reported, never merged: operations sees both, and a person decides which applies.
Returns RecordActivityResult:
| Field | Type | Meaning |
|---|---|---|
activity_id |
str |
The street's identifier for the activity, such as ACT-…. |
already_recorded |
bool |
True when it was recorded before, by its source, account and external_activity_id, and the first one is answered. |
Errors: NotLinked for an external account nobody has linked: nothing is recorded, and the plugin reports the account's activity once it is linked. invalid for an empty external_account_id or source, no activity, an empty external_activity_id or trade_date, no raw record, a Money with no amount, a kind the enum does not define, or a value outside its bounds (an external_activity_id of 1 to 200 characters, a description of at most 500, at most 32 provenance entries), naming the field. NotGranted without the custody role. no handler, timeout or handler error from the street store.
from decimal import Decimal
import meridian
reply = await role.record_activity(
external_account_id="acct-1",
source="snaptrade",
activity=meridian.CustodialActivity(
external_activity_id=venue_activity["id"], # the custodian's own identifier
kind="reinvestment",
instrument_id=instrument_id, # resolved at the edge, as a holding's is
trade_date="2026-09-30",
settlement_date="2026-09-30",
units=Decimal("3.27"), # signed by what it did to the account
price=meridian.Money(Decimal("1.00"), "USD"),
amount=meridian.Money(Decimal("-3.27"), "USD"), # signed by what it did to the cash
description=venue_activity["description"],
raw_record=role.plugin.raw_record(f"activities/acct-1/{venue_activity['id']}"),
),
)
reply.activity_id, reply.already_recorded # "ACT-…", False
list_activities¶
Reads the activity of the accounts in the plugin's read scope, as the street store announced each, by trade date. The reply says from when the account's source can read history, so an operations plugin can say an opening balance is older than the history that would explain it. See Reads are within the read scope.
async def list_activities(
self, *, account_id: str = "", trade_date_from: str = "", trade_date_to: str = "",
since: Watermark | None = None, page_size: int = 0, cursor: str = "",
) -> ListActivitiesResult
| gRPC | rpc ListActivities(ListActivitiesParams) returns (ListActivitiesResult) |
| Workflow step | W2.11, List an account's activity |
| Kind | query, on platform.street.query.list-activities |
| Role | operations |
| Served by | the street store |
| Stability | preview |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
no | One account, which must be in the plugin's read scope. Empty for every account in it. |
trade_date_from, trade_date_to |
str |
no | ISO 8601 dates, inclusive. Empty for no bound on that side. |
since |
Watermark or None |
no | Only the activities recorded after it, in the order recorded rather than by trade date. |
page_size |
int |
no | How many to a page: 100 when 0, and never more than 500. |
cursor |
str |
no | The previous page's next_cursor, or empty for the first. |
Returns ListActivitiesResult:
| Field | Type | Meaning |
|---|---|---|
activities |
sequence of ActivityRecordedEvent |
The activities on the page, each as it was announced. |
next_cursor |
str |
The next page's cursor, empty on the last. |
as_of |
Watermark |
The point in the store's record the page was read at. |
history_from |
str |
The first date the named account's source can read activity from, as its latest sync status said. Empty where the read names no account, or the source has not said. |
re_resolutions |
sequence of ActivityReResolution |
Every re-resolution of the activities on the page, each naming its activity and account; on a read since a watermark, every re-resolution recorded after it, whether or not its activity was, merged with the activities in the order recorded, the page's size counting both. The activities stay as first recorded: an activity's instrument is its latest re-resolution's. Empty where none was re-resolved. |
Errors: NotGranted for an account_id outside the read scope, and without the operations role. no handler, timeout or handler error from the street store.
page = await role.list_activities(account_id="ACC-…", trade_date_from="2026-09-01")
for each in page.activities:
activity = each.activity
if activity.kind == meridian.ActivityKind.ACTIVITY_KIND_REINVESTMENT:
units = meridian.as_decimal(activity.units)
page.history_from # "2024-06-03", or "" where the source has not said
re_resolve_activity¶
Re-resolves an activity the plugin recorded before its instrument resolved: a retirement plan's own fund code linked to an instrument later, or a symbol the deployment's instrument records complete later. Sending the activity again would change nothing, since the street answers it as already recorded; a re-resolution is a record of its own, kept beside the activity, which stays as first recorded. See The custodian's activity.
async def re_resolve_activity(
self, *, external_account_id: str = "", source: str = "", external_activity_id: str = "",
instrument_id: str = "", provenance: Provenance | None = None, resolved_at_ns: int = 0,
acting_for: str | None = None,
) -> ReResolveActivityResult
| gRPC | rpc ReResolveActivity(ReResolveActivityParams) returns (ReResolveActivityResult) |
| Workflow step | W2.15, Re-resolve a recorded activity |
| Kind | command, on platform.street.command.re-resolve-activity |
| Role | custody |
| Served by | the street store, which announces each one it records as ActivityReResolved (W2.16) to operations |
| Stability | preview |
| Name | Type | Required | Meaning |
|---|---|---|---|
external_account_id |
str |
yes, by the sidecar | The account as the source knows it, which the sidecar translates to the account it is linked to. |
source, external_activity_id |
str |
yes, by the street | The source and the custodian's identifier the activity was recorded under, as first reported: with the account, what names it. |
instrument_id |
str |
no | The deployment's instrument record it now resolves to. Empty where what had resolved it was removed, such as a link deleted: it is then unresolved again, its code as first reported. |
provenance |
Provenance or None |
yes, by the street | How it was resolved this time: supplied, naming the person who set the link, or derived, naming the rule. Never the custodian's word. |
resolved_at_ns |
int |
yes, by the street | When what resolves it was made: the link set, a table setting row's changed_at, the rule run. The street stamps its own record time beside it. |
acting_for |
str or None |
no | Unset: the plugin re-resolves as itself. See Acting for a person. |
The street keeps the activity as first recorded, which never changes, and each re-resolution beside it, its own record, numbered and chained per account apart from the activities. An activity's instrument is its latest re-resolution's, or its own where there is none. A re-resolution naming what the latest resolution already names is answered already_recorded, takes no number and announces nothing, so a plugin can re-resolve an account's activities again whenever what resolves them changes.
Returns ReResolveActivityResult:
| Field | Type | Meaning |
|---|---|---|
activity_id |
str |
The street's identifier for the activity re-resolved. |
already_recorded |
bool |
True when the activity's latest resolution already named this instrument and provenance, and nothing was recorded. |
Errors: NotLinked for an external account nobody has linked. handler error from the street store, its words naming what is wrong, for an activity never recorded under that source, account and identifier (a re-resolution re-resolves an activity already recorded, and resolves none into existence), and for no provenance, a provenance that is the custodian's word, or no resolved_at_ns. invalid for an external_activity_id outside 1 to 200 characters, or a provenance kind the enum does not define. NotGranted without the custody role. no handler or timeout from the street store.
reply = await role.re_resolve_activity(
external_account_id="SNAP-ACC-401K",
source="snaptrade",
external_activity_id=activity_id, # as first reported
instrument_id="INS-...", # empty where the link was removed
provenance=meridian.Provenance(field="instrument_id",
kind="PROVENANCE_KIND_SUPPLIED",
person="Ada Park, in the plan-code links"),
resolved_at_ns=link_set_at_ns, # when the link was set or the rule ran
)
reply.activity_id, reply.already_recorded
list_sync_statuses¶
Reads the sync statuses the street store kept, for the accounts in the plugin's read scope: the latest of each connection, or every one recorded since a watermark. The street hears each sync status a custody plugin reports (report_sync_status) and keeps it, so an operations plugin tells a connection that needs a person to sign in again apart from data that is merely old. See Reads are within the read scope.
async def list_sync_statuses(
self, *, account_id: str = "", since: Watermark | None = None,
page_size: int = 0, cursor: str = "",
) -> ListSyncStatusesResult
| gRPC | rpc ListSyncStatuses(ListSyncStatusesParams) returns (ListSyncStatusesResult) |
| Workflow step | W2.14, Read an account's sync status |
| Kind | query, on platform.street.query.list-sync-statuses |
| Role | operations |
| Served by | the street store, which announces each one it keeps as SyncStatusRecorded (W2.13) to operations |
| Stability | preview |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
no | One account, which must be in the plugin's read scope. Empty for every account in it. |
since |
Watermark or None |
no | Unset: the latest of each connection. Set: every one recorded after it, in the order recorded. |
page_size |
int |
no | How many to a page: 100 when 0, and never more than 500. |
cursor |
str |
no | The previous page's next_cursor, or empty for the first. |
Returns ListSyncStatusesResult: statuses, a sequence of SyncStatusRecordedEvent, each as it was announced; next_cursor, empty on the last page; and as_of, the Watermark it was read at.
A sync status for an external account nobody has linked is kept with its account empty: it reaches no plugin, and the dashboard alone shows it.
Errors: NotGranted for an account_id outside the read scope, and without the operations role. no handler, timeout or handler error from the street store.
page = await role.list_sync_statuses(account_id="ACC-…")
for each in page.statuses:
if each.status.state == meridian.SyncState.SYNC_STATE_NEEDS_SIGN_IN:
... # a person must sign in again at the venue: say so, rather than "old"
resolve_identifier¶
Reverse resolution: asks which instrument a set of identifiers maps to, as of a date. The strongest identifier is matched first: a global identifier, then a symbol qualified by venue and currency.
There are two outcomes other than a match:
- Nothing matched. When the source states an identifier, a description and a currency, the store asks the platform to match or mint the security, and answers its record, or a provisional local record of the deployment's own (see Provisional below):
foundisTrue, andmintedisTrueon the resolve that minted the deployment's record. A later resolve of the same identifiers matches that record, withmintedFalse. Record the holding against it; the instrument store reports the miss itself. A source stating less mints nothing:foundisFalseandmiss_reasonisMISS_REASON_NOT_FOUND, and the holding is recorded withunresolved_identifiers. - More than one matched. The result is a miss rather than a pick:
foundisFalseandmiss_reasonisMISS_REASON_AMBIGUOUS. Record the holding withunresolved_identifiers, and report the miss.
async def resolve_identifier(
self, *, identifiers: Sequence[Identifier] = (), as_of_ns: int = 0,
exchange_mic: str = "", currency: str = "",
stated_asset_class: AssetClass | str | None = None, stated_currency: str = "",
stated_description: str = "", stated_instrument_type: InstrumentType | str | None = None,
provenance: Sequence[Provenance] = (),
stated_binary_event_contract: BinaryEventContract | None = None,
) -> ResolveIdentifierResult
| gRPC | rpc ResolveIdentifier(ResolveIdentifierParams) returns (ResolveIdentifierResult) |
| Workflow step | W3.1, Resolve an identifier set |
| Kind | query, on platform.reference.query.resolve-identifier |
| Role | custody; data, resolving its vendor's codes to the instruments its rows name; reporting, read-only; connectivity |
| Served by | the instrument store, the deployment's replica of the security master |
Provisional. Nothing matched, the store asks the platform to match or mint the security, within a short bounded wait; answered, the record is the platform's, under its INS- ID. Otherwise the store mints a provisional local record, under an LCL- ID, and the result's provisional is True; minted keeps its meaning, this resolve created the deployment's record. Test provisional, never the LCL- prefix: a resolved LCL- ID stays LCL- and answers as the INS- record it became. A source stating less than an identifier, a description and a currency mints nothing: found is False, miss_reason MISS_REASON_NOT_FOUND, and the holding is recorded unresolved. No open_meridian identifier is added to records. See One ID per instrument.
Read-only, for reporting. A reporting plugin names an instrument by an identifier, such as its reporting currency by its ISO 4217 code (Identifier(scheme="iso4217", value="EUR")), and the store answers the record it holds for the date. Asked by reporting, nothing is minted, joined, offered or listed: nothing matched is MISS_REASON_NOT_FOUND, several matched MISS_REASON_AMBIGUOUS. Core enforces it, from the asking instance's launched roles (see Instruments).
A currency is fetched, not minted. A resolve naming a currency by its ISO 4217 code (iso4217) that no record the deployment holds carries is answered with the platform master's record, which the instrument store fetches itself, with no person; a local record is minted for the code only when the master does not hold it, or while the platform cannot be reached (see A currency is fetched from the master).
As of any date the store holds. The store keeps each identifier's window on a record, so an identifier that has since left a record still answers, as of a date it was on it, the record that held it then.
| Name | Type | Required | Meaning |
|---|---|---|---|
identifiers |
sequence of Identifier |
yes, by the interface | At least one. Matched strongest first. An empty set is a miss, MISS_REASON_NOT_FOUND, and mints nothing. |
as_of_ns |
int |
no | The reference time: the date the mapping is being asked about. An identifier maps to different instruments over time. |
exchange_mic |
str |
no | Narrows a symbol match. Empty means unconstrained. |
currency |
str |
no | Narrows a symbol match. |
stated_asset_class, stated_currency, stated_description |
AssetClass, str, str |
no | What the plugin's source states of the security, where it states it, and nothing it would have to guess. Kept on the record as offers from this instance, in force only when a person accepts them. Not stated is unspecified or empty. stated_currency is an ISO 4217 code. |
stated_instrument_type |
InstrumentType |
no | Its type within the stated class, where the source says it: a custodian's sweep fund is a money market fund. |
stated_binary_event_contract |
BinaryEventContract |
no | A data plugin's event contract's terms as its venue states them: its payout, close, bounds and category, the payout left unset where the venue gives none. The store records the category the first time it sees the contract, sourced to the plugin; every other term, and a category unlike the one held, is offered, in force only when a person accepts it. A term out of bounds is refused naming stated_binary_event_contract.<field>. meridian.roles.data.event_contracts states it for a venue's contracts. Added in SDK 0.36.0. |
Returns ResolveIdentifierResult:
| Field | Type | Meaning |
|---|---|---|
found |
bool |
Whether instrument_id holds an answer: exactly one instrument matched, or nothing did and the deployment minted its record for the set. |
instrument_id |
str |
The instrument, when found. |
minted |
bool |
True when nothing matched and this resolve minted instrument_id, the deployment's LCL- record for the set; found is True beside it. A later resolve of the same identifiers matches the record, and is not minted. |
miss_reason |
MissReason |
Set only when found is False: MISS_REASON_AMBIGUOUS when more than one instrument matched, or MISS_REASON_NOT_FOUND when nothing matched and nothing was minted: an empty set, a source stating less than an identifier, a description and a currency, or a reporting plugin asking. |
Errors: no handler, timeout or handler error from the instrument store. NotGranted without one of its roles.
import time
import meridian
held = [
meridian.Identifier(scheme="isin", value="US0378331005"),
meridian.Identifier(scheme="symbol", value="AAPL", source="snaptrade"),
]
answer = await role.resolve_identifier(identifiers=held, as_of_ns=time.time_ns())
if answer.found:
instrument_id = answer.instrument_id # an instrument, perhaps one the deployment just minted
else:
reason = answer.miss_reason # ambiguous: record the row unresolved, report the miss, carry on
report_missing_instrument¶
Reports that a resolution missed. A fact, not a request. The plugin reports what it held and carries on with the next holding. It does not ask for an instrument to be created, does not wait for one, and could not create one. The deployment and the platform decide what the instrument is, and an administrator completes it.
A plugin reports only an ambiguous miss. When nothing matched, resolve_identifier answered a record the deployment minted, and the instrument store has already reported that miss, carrying it.
async def report_missing_instrument(
self, *, source: str = "", asset_class: AssetClass | str | None = None,
identifiers: Sequence[Identifier] = (), as_of_ns: int = 0,
reason: MissReason | str | None = None, observed_at_ns: int = 0,
) -> Published
| gRPC | rpc ReportMissingInstrument(ReportMissingInstrumentParams) returns (Published) |
| Workflow step | W3.2, Report that a resolution missed |
| Kind | event, on platform.reference.event.instrument-missing |
| Role | custody, data, connectivity |
| Heard by | the conductor, which asks the platform whether it already knows the instrument (W3.3) |
| Name | Type | Required | Meaning |
|---|---|---|---|
source |
str |
no | The namespace the miss occurred in, such as "snaptrade". |
asset_class |
AssetClass, str or None |
no | The instrument's asset class, such as "equity", when the plugin knows it. None leaves it unset, and the stub the platform mints has no class until an administrator completes it. An ETF is "fund" and an option "derivative". |
identifiers |
sequence of Identifier |
no | Everything the plugin held at the miss. Enough to look it up against a global scheme, or to create a stub carrying them. |
as_of_ns |
int |
no | The reference time of the missed resolution. The reaction targets the mapping effective then, not now. |
reason |
MissReason or None |
no | The miss_reason that resolve_identifier returned. None leaves it unset, which reads as MISS_REASON_UNSPECIFIED. |
observed_at_ns |
int |
no | When the plugin observed the miss. |
The sidecar sets publisher_instance_id, and leaves placeholder_instrument_id empty.
Returns Published, with message_id, the message's identifier on the bus.
Errors: ValueError for an asset class or a reason the enum does not define, such as "EQUITY" or "etf". NotGranted without the custody role.
import time
await role.report_missing_instrument(
source="snaptrade",
asset_class="equity",
identifiers=held,
as_of_ns=as_of_ns,
reason=answer.miss_reason,
observed_at_ns=time.time_ns(),
)
read_accounts_for_linking¶
Reads the deployment's accounts, so the plugin's own page at admin can offer the ones an external account may be linked to. It is read only for an admin of the plugin, the one viewing the page under Manage, and is answered each account's identity: only the accounts a deployment admin granted the plugin's instance, nothing by default (see Accounts a plugin may link to).
async def read_accounts_for_linking(
self, *, acting_for: str | None = None,
) -> ReadAccountsForLinkingResult
| gRPC | rpc ReadAccountsForLinking(ReadAccountsForLinkingParams) returns (ReadAccountsForLinkingResult) |
| Workflow step | W6.4, Link a plugin's external account |
| Kind | query, on platform.config.query.accounts |
| Role | custody |
| Served by | the conductor |
| Name | Type | Required | Meaning |
|---|---|---|---|
acting_for |
str or None |
yes, by the sidecar | The Meridian-Caller header of the admin viewing the page, in a session opened by Manage. See Acting for a person. |
Returns ReadAccountsForLinkingResult:
| Field | Type | Meaning |
|---|---|---|
accounts |
sequence of AccountRecord |
Every account granted to the instance, open and closed: each one's identifier, name, state, custodian, type, owner and note. No holdings. Empty until a deployment admin grants some. |
Offer only open accounts. A link to a closed account is refused.
Errors: NotGranted without an acting_for, or with one from a session not opened by Manage. not vouched for for an acting_for that is not accepted. no handler, timeout or handler error from the conductor. NotGranted without the custody role.
from meridian.plugin.v1 import operations_pb2 as ops
read = await role.read_accounts_for_linking(acting_for=request.state.caller.header)
offered = [a for a in read.accounts if a.state != ops.ACCOUNT_STATE_CLOSED]
link_external_account¶
Links an external account the plugin reported to one of the firm's accounts, or removes its link. The plugin sends it from its own page at admin, for the admin of the plugin viewing it under Manage.
Name one of these, never both:
account_id, to link to an existing account;new_account_name, to create an account and link to it in one step, so nothing is left half-done. Only a deployment admin names a new account.
Name neither to remove the link.
An account has one external account: a link naming an account that another external account is already linked to, through this plugin or any other, is refused. Two external accounts at one custodian link to two accounts. See Accounts.
The link is also the plugin's right to that account. The custody role grants the street store; the link grants the one account, which is in the plugin's read and write scope while the link stands, with no permission needed. A closed account stays readable through the link, and is not writable. Removing the link removes both.
async def link_external_account(
self, *, external_account_id: str = "", account_id: str = "", new_account_name: str = "",
new_account_custodian: str = "", new_account_type: str = "", new_account_owner: str = "",
new_account_note: str = "", acting_for: str | None = None,
) -> LinkExternalAccountResult
| gRPC | rpc LinkExternalAccount(LinkExternalAccountParams) returns (LinkExternalAccountResult) |
| Workflow step | W6.4, Link a plugin's external account |
| Kind | command, on platform.config.command.link-external-account |
| Role | custody |
| Served by | the conductor, which records the admin as the one who made the link |
| Name | Type | Required | Meaning |
|---|---|---|---|
external_account_id |
str |
yes, by the sidecar | The account as the source knows it. It must be one this plugin reported with report_external_accounts, or, to remove a link, one it already links. |
account_id |
str |
one of these two, or neither | An existing, open account to link to. |
new_account_name |
str |
one of these two, or neither | A new account's name, for the conductor to create and link in one step. Only for a deployment admin. |
new_account_custodian |
str |
no | The new account's custodian, such as "Fidelity". At most 200 characters. |
new_account_type |
str |
no | The new account's type, such as "Roth IRA". At most 200 characters. |
new_account_owner |
str |
no | One ownership or grouping label for the new account. At most 200 characters. |
new_account_note |
str |
no | Anything else worth knowing about the new account. At most 2,000 characters. |
acting_for |
str or None |
yes, by the sidecar | The Meridian-Caller header of the admin viewing the page, in a session opened by Manage. |
The four new_account_* attributes are free text, which a page may pre-fill from what the source reported, for the admin to change. They are ignored unless new_account_name is given: an existing account is edited only on the Accounts tab of the dashboard's Settings.
Returns LinkExternalAccountResult:
| Field | Type | Meaning |
|---|---|---|
plugin_instance_id |
str |
The plugin the link belongs to. |
external_account_id |
str |
The external account. |
account_id |
str |
The account it is linked to: the new account's identifier when one was created, and empty when the link was removed. |
Errors:
NotGrantedwithout anacting_for, or with one from a session not opened by Manage; for anew_account_namefrom an admin who is not a deployment admin; or for an external account this plugin did not report, an empty one included.not vouched forfor anacting_forthat is not accepted.handler errorfrom the conductor for a link it refuses, with its reason: bothaccount_idandnew_account_name, an account that does not exist or is closed, an account that already has an external account linked, or an attribute that is too long.CommandRefusedwithREFUSAL_REASON_ACCOUNT_NOT_LINKABLEfor anaccount_ida deployment admin has not granted the plugin's instance. A new account made by linking is granted to the instance that made it.no handlerortimeoutfrom the conductor.NotGrantedwithout thecustodyrole.
caller = request.state.caller
# Link to an existing account:
await role.link_external_account(
external_account_id="acct-1", account_id="ACC-…", acting_for=caller.header,
)
# Or create one and link it, pre-filled from what the source reported:
await role.link_external_account(
external_account_id="acct-2",
new_account_name="Rollover IRA",
new_account_custodian="Fidelity",
new_account_type="IRA",
acting_for=caller.header,
)
# Remove a link:
await role.link_external_account(external_account_id="acct-2", acting_for=caller.header)
resolve_instrument¶
Forward resolution: an instrument identifier to its record, so a position can be shown with a name rather than an opaque key, and a plugin that reads the book can join a position to its instrument by its ID. Reference data, so it is answered whatever the plugin's read scope.
async def resolve_instrument(
self, *, instrument_id: str = "", as_of_ns: int = 0,
) -> ResolveInstrumentResult
| gRPC | rpc ResolveInstrument(ResolveInstrumentParams) returns (ResolveInstrumentResult) |
| Workflow step | W3.6, Resolve an instrument for display |
| Kind | query, on platform.reference.query.resolve-instrument |
| Role | portfolio, reporting, compliance, oms, operations; data, reading the record of an instrument another source resolved to name it to its vendor; ems and connectivity |
| Served by | the instrument store |
| Name | Type | Required | Meaning |
|---|---|---|---|
instrument_id |
str |
yes | An INS- instrument, or the deployment's LCL- placeholder. |
as_of_ns |
int |
no | The reference time: the record as it stood then. |
Returns ResolveInstrumentResult:
| Field | Type | Meaning |
|---|---|---|
found |
bool |
Whether the store holds the instrument. |
instrument |
InstrumentRecord |
Its record, when found. |
Errors: no handler, timeout or handler error from the instrument store. NotGranted without one of those roles.
answer = await role.resolve_instrument(instrument_id=position.instrument_id)
if answer.found:
name = answer.instrument.description
record_opening_balance¶
Records what an account holds when it enters the book of record, once, as of a business date: its positions, each with its trade-date quantity, its settled quantity, its pending settlements by value date and its lots, each lot with its quantity, cost and acquisition date, as the custodian or the prior system reports them and a person completes them, naming that source. An account holding nothing enters with no positions. The book refuses one missing any of what it requires, naming each missing field: see What the book requires.
It is a person's act, the fact every later break inherits: send it acting_for the person confirming it, with their reason. See The book's commands.
async def record_opening_balance(
self, *, account_id: str = "", as_of_date: str = "", sources: Sequence[OpeningSource] = (),
positions: Sequence[OpeningPosition] = (), reason: str = "", replaces_entry_id: str = "",
idempotency_key: str = "", acting_for: str | None = None,
) -> RecordOpeningBalanceResult
| gRPC | rpc RecordOpeningBalance(RecordOpeningBalanceParams) returns (RecordOpeningBalanceResult) |
| Workflow step | W9.1, Record an account's opening balance |
| Kind | command, on platform.book.command.record-opening-balance |
| Role | operations |
| Served by | the book of record, which journals it as one entry opening each position, lot and pending settlement from zero (W9.2) |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
yes | The account. It must be in the plugin's write scope, and one the person may write. |
as_of_date |
str |
yes | The ISO 8601 business date it stands for. |
sources |
sequence of OpeningSource |
yes, by the book | One per custodian or system it was composed from, each naming it and the street records it was composed from. |
positions |
sequence of OpeningPosition |
no | What the account holds. Empty: it enters holding nothing. |
reason |
str |
yes, by the book | The person's own words. |
replaces_entry_id |
str |
no | The reversed opening balance this one replaces. Empty for the first. |
idempotency_key |
str |
no | See Idempotency keys. |
acting_for |
str or None |
yes, by the book | The Meridian-Caller header of the person confirming it. |
A position held under a placeholder instrument enters under the placeholder, flagged placeholder on the BookPosition, and the book moves it onto the instrument when the instrument is identified. Its settled quantity and its pending quantities must account for its trade-date quantity, and its lots must sum to it; cash sends none.
Returns RecordOpeningBalanceResult, a book entry's result: the positions it opened, and the account's attributes naming the standing opening balance.
Errors:
CommandRefused:REFUSAL_REASON_ACTOR_REQUIREDwith no person,REFUSAL_REASON_REASON_REQUIREDwith no reason,REFUSAL_REASON_OPENING_BALANCE_RECORDEDwhile one stands,REFUSAL_REASON_INCOMPLETEfor a field the book requires left out, each infields(positions[0].settled_quantity,positions[1].lots[0].terms.cost),REFUSAL_REASON_LOTS_UNBALANCEDfor lots that do not sum to their position,REFUSAL_REASON_IDEMPOTENCY_CONFLICTfor a key used by a different command.TypeErrororValueErrorfor a number, an amount or an enum, named by its path (positions[0].lots[1].terms.cost).NotGrantedfor an account outside the write scope, a person who may not write it, or a session not opened by Open.not vouched forfor anacting_forthat is not accepted.handler errorfrom the book for anything else it refuses, such as a position that states no side, with its reason.no handlerortimeoutfrom the book.NotGrantedwithout theoperationsrole.
import meridian
reply = await role.record_opening_balance(
account_id=account,
as_of_date="2026-09-08",
sources=[meridian.OpeningSource(kind="custodian", name="Interactive Brokers",
as_of_date="2026-09-08", basis="trade_date")],
positions=positions, # each complete: settled, pending by date, lots with cost and date
reason=reason, # the person's own words
idempotency_key=f"opening/{account}/{statement_id}",
acting_for=request.caller.header, # the person confirming it
)
record_break¶
Records a difference between the book and the street as a break, or brings an open one up to date: the account, the position or account-level figure it concerns, its category, each differing field with the book's value and the street's, what was compared, the business date it was seen, and the candidate causes the plugin's matching found. A finding, so the plugin may send it as itself.
async def record_break(
self, *, account_id: str = "", break_id: str = "", position: PositionKey | None = None,
figure: FigureKey | None = None, category: BreakCategory | str | None = None,
differences: Sequence[BreakDifference] = (), book_watermark: Watermark | None = None,
street: StreetRecordRef | None = None, business_date: str = "",
candidate_causes: Sequence[BreakCause] = (), idempotency_key: str = "",
unresolved_identifiers: Sequence[Identifier] = (), acting_for: str | None = None,
) -> RecordBreakResult
| gRPC | rpc RecordBreak(RecordBreakParams) returns (RecordBreakResult) |
| Workflow step | W9.4, Record a break |
| Kind | command, on platform.book.command.record-break |
| Role | operations |
| Served by | the book of record |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
yes | The account, in the plugin's write scope. |
break_id |
str |
no | Empty for a new break, whose identifier the book mints; an open break's, to bring it up to date. |
position |
PositionKey or None |
one of these two | The position it concerns: an instrument and a side. |
figure |
FigureKey or None |
one of these two | The account-level figure it concerns, under its margin agreement. |
category |
BreakCategory, str or None |
yes | What differs. |
differences |
sequence of BreakDifference |
no | Each differing field, with the book's value and the street's. |
book_watermark |
Watermark or None |
no | Where the book was read. |
street |
StreetRecordRef or None |
no | The street record compared, by value. |
business_date |
str |
yes | The reconciliation's ISO 8601 business date: first seen for a new break, last seen for one brought up to date. |
candidate_causes |
sequence of BreakCause |
no | The causes the plugin's matching found, for a person to confirm one. |
idempotency_key |
str |
no | See Idempotency keys. |
unresolved_identifiers |
sequence of Identifier |
on an unrecognized security | The identifiers the street row carries for a security the deployment could not recognise, as the street recorded them: at least one on BREAK_CATEGORY_UNRECOGNIZED_SECURITY, refused on any other category. The book resolves nothing from them. |
acting_for |
str or None |
no | Unset: the plugin reports the finding as itself. |
Every difference is recorded: a plugin may rank or group breaks for its people, never drop one. A difference that persists is one break, brought up to date by its break_id, not a new one each day.
Returns RecordBreakResult, a book entry's result holding the break.
Errors: CommandRefused with REFUSAL_REASON_NO_OPENING_BALANCE for an account with no opening balance, REFUSAL_REASON_BREAK_STATE for a break_id that is not open, or REFUSAL_REASON_IDEMPOTENCY_CONFLICT. ValueError for both position and figure. NotGranted for an account outside the write scope, and without the operations role. handler error, no handler or timeout from the book.
await role.record_break(
account_id=account,
position=meridian.PositionKey(instrument_id=instrument, side="long"),
category="trade_date_quantity",
differences=[meridian.BreakDifference(
field="trade_date_quantity",
book=meridian.BreakValue(quantity=Decimal("150")),
street=meridian.BreakValue(quantity=Decimal("175")),
)],
book_watermark=book_page.as_of,
street=meridian.StreetRecordRef(statement_id=statement.statement_id, as_of_date=statement.as_of_date),
business_date=statement.as_of_date,
candidate_causes=[meridian.BreakCause(category="unbooked_trade", none_found=True)],
idempotency_key=f"break/{account}/{statement.statement_id}/{instrument}/long/trade_date_quantity",
)
record_account_figures¶
Records the account's figures for a business date, one set per margin agreement, each as the street recorded it, with the collateral held under it and the custodian's own value and margin requirement for each position, labelled as the custodian's. A record of what was reported, never a figure the book computed. A finding, so the plugin may send it as itself.
async def record_account_figures(
self, *, account_id: str = "", business_date: str = "", source: StreetRecordRef | None = None,
agreements: Sequence[AgreementFigures] = (), idempotency_key: str = "",
acting_for: str | None = None,
) -> RecordAccountFiguresResult
| gRPC | rpc RecordAccountFigures(RecordAccountFiguresParams) returns (RecordAccountFiguresResult) |
| Workflow step | W9.5, Record the account's figures |
| Kind | command, on platform.book.command.record-account-figures |
| Role | operations |
| Served by | the book of record |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
yes | The account, in the plugin's write scope. |
business_date |
str |
yes | The ISO 8601 business date the figures are for. |
source |
StreetRecordRef or None |
no | The statement they were read from. |
agreements |
sequence of AgreementFigures |
no | One set per margin agreement. |
idempotency_key |
str |
no | See Idempotency keys. |
acting_for |
str or None |
no | Unset: the plugin reports the finding as itself. |
Returns RecordAccountFiguresResult, a book entry's result holding the figures, one record per account, agreement and business date.
Errors: CommandRefused with REFUSAL_REASON_NO_OPENING_BALANCE or REFUSAL_REASON_IDEMPOTENCY_CONFLICT. TypeError or ValueError for a number or an amount, named by its path. NotGranted for an account outside the write scope, and without the operations role. handler error, no handler or timeout from the book.
record_encumbrances¶
Records what of each position cannot move, as a completed statement states it: for each position, its encumbrances, the whole set, empty when the statement reports none. An attribute of the position, never a movement: its quantities do not change, and the book derives its free quantity from them. A finding, so the plugin may send it as itself.
async def record_encumbrances(
self, *, account_id: str = "", business_date: str = "", source: StreetRecordRef | None = None,
positions: Sequence[PositionEncumbrances] = (), idempotency_key: str = "",
acting_for: str | None = None,
) -> RecordEncumbrancesResult
| gRPC | rpc RecordEncumbrances(RecordEncumbrancesParams) returns (RecordEncumbrancesResult) |
| Workflow step | W9.15, Record a position's encumbrances |
| Kind | command, on platform.book.command.record-encumbrances |
| Role | operations |
| Served by | the book of record |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
yes | The account, in the plugin's write scope. |
business_date |
str |
yes | The statement's ISO 8601 business date. |
source |
StreetRecordRef or None |
no | The statement they were read from. |
positions |
sequence of PositionEncumbrances |
no | Each position's whole set of encumbrances. |
idempotency_key |
str |
no | See Idempotency keys. |
acting_for |
str or None |
no | Unset: the plugin reports the finding as itself. |
The book holds the kinds PLEDGED, POSTED, ON_LOAN, BLOCKED, RESTRICTED, IN_TRANSIT and OTHER, which needs the source's own code. The street's PENDING, REHYPOTHECATED and BORROWED are not the book's: pending stays in the settlement buckets.
Returns RecordEncumbrancesResult, a book entry's result holding each position changed, with its encumbrances and free_quantity.
Errors: CommandRefused with REFUSAL_REASON_NO_OPENING_BALANCE or REFUSAL_REASON_IDEMPOTENCY_CONFLICT. handler error from the book, naming the field, for an unspecified kind, a kind the book does not hold, OTHER with no code, or a position the book does not hold; that difference is a break of its own. NotGranted for an account outside the write scope, and without the operations role. no handler or timeout from the book.
handle_break¶
For a person: confirms one of a break's candidate causes, or records another, and sets who owns the break, its escalation level and its due date. Cause and handling are recorded attributes, not states: a break stays open until it is resolved or closed.
async def handle_break(
self, *, account_id: str = "", break_id: str = "", confirmed_cause: BreakCause | None = None,
handling: BreakHandling | None = None, reason: str = "", idempotency_key: str = "",
acting_for: str | None = None,
) -> HandleBreakResult
| gRPC | rpc HandleBreak(HandleBreakParams) returns (HandleBreakResult) |
| Workflow step | W9.6, Set a break's cause and handling |
| Kind | command, on platform.book.command.handle-break |
| Role | operations |
| Served by | the book of record |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
yes | The account, in the plugin's write scope, and one the person may write. |
break_id |
str |
yes | The break, which must be open. |
confirmed_cause |
BreakCause or None |
no | The cause the person confirms. None: unchanged. |
handling |
BreakHandling or None |
no | Its owner, escalation level and due date. None: unchanged; set, it replaces the handling whole. |
reason |
str |
yes, by the book | The person's own words. |
idempotency_key |
str |
no | See Idempotency keys. |
acting_for |
str or None |
yes, by the book | The Meridian-Caller header of the person. |
Returns HandleBreakResult, a book entry's result holding the break.
Errors: CommandRefused with REFUSAL_REASON_ACTOR_REQUIRED, REFUSAL_REASON_REASON_REQUIRED, REFUSAL_REASON_BREAK_STATE or REFUSAL_REASON_IDEMPOTENCY_CONFLICT. NotGranted for an account outside the write scope, a person who may not write it, a session not opened by Open, or without the operations role. not vouched for, handler error, no handler or timeout.
resolve_break¶
For a person: resolves one or more open breaks by the entry that corrects the book, in the same act, or by naming entries already recorded; or closes them with an explanation and no entry. The book moves only by the resolving entry, which names the breaks, never by an overwrite.
async def resolve_break(
self, *, account_id: str = "", break_ids: Sequence[str] = (), reason: str = "",
adjustment: Adjustment | None = None, reversal: Reversal | None = None,
entries: ResolvedByEntries | None = None, explanation: str | None = None,
idempotency_key: str = "", acting_for: str | None = None,
) -> ResolveBreakResult
| gRPC | rpc ResolveBreak(ResolveBreakParams) returns (ResolveBreakResult) |
| Workflow step | W9.7, Resolve or close a break |
| Kind | command, on platform.book.command.resolve-break |
| Role | operations |
| Served by | the book of record |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
yes | The account, in the plugin's write scope, and one the person may write. |
break_ids |
sequence of str |
yes | The breaks, each open. |
reason |
str |
yes, by the book | The person's own words. |
adjustment |
Adjustment or None |
one of these four | Resolves them by an adjustment journalled in the same act: its movement lines and lot basis adjustments, effective after the opening balance's date. |
reversal |
Reversal or None |
one of these four | Resolves them by reversing an entry: the book negates its lines. |
entries |
ResolvedByEntries or None |
one of these four | Resolves them by entries already recorded. |
explanation |
str or None |
one of these four | Closes them with this explanation, moving nothing. |
idempotency_key |
str |
no | See Idempotency keys. |
acting_for |
str or None |
yes, by the book | The Meridian-Caller header of the person. |
Returns ResolveBreakResult, a book entry's result: the breaks resolved or closed, and the positions the resolving entry moved.
Errors:
CommandRefused:REFUSAL_REASON_ACTOR_REQUIRED,REFUSAL_REASON_REASON_REQUIRED,REFUSAL_REASON_BREAK_STATEfor a break that is not open,REFUSAL_REASON_INCOMPLETEfor an adjustment's line opening a lot without its cost or acquisition date (adjustment.lines[0].opens_lot.cost,adjustment.lines[0].opens_lot.acquired_date),REFUSAL_REASON_BEFORE_OPENING_BALANCEfor an entry effective on or before the opening balance's date,REFUSAL_REASON_LOTS_UNBALANCEDfor an entry that would leave a position's open lots not summing to it,REFUSAL_REASON_LATER_ENTRIES_STANDfor a reversal of the opening balance while a later entry moves the account's positions,REFUSAL_REASON_IDEMPOTENCY_CONFLICT.ValueErrorfor more than one of the four, andTypeErrororValueErrorfor a number or an amount, named by its path.NotGrantedfor an account outside the write scope, a person who may not write it, a session not opened by Open, or without theoperationsrole.not vouched for,handler error,no handlerortimeout.
await role.resolve_break(
account_id=account,
break_ids=[break_id],
reason="The custodian's statement shows a buy of 25 we had not booked.",
adjustment=meridian.Adjustment(
effective_date="2026-09-10",
lines=[meridian.MovementLine(
instrument_id=instrument, side="long", bucket="settled", quantity=Decimal("25"),
opens_lot=meridian.LotTerms(cost=meridian.Money(Decimal("4625.00"), "USD"),
acquired_date="2026-09-10", source="adjustment"),
)],
),
acting_for=request.caller.header,
)
close_breaks_as_cleared¶
For a person, or the role's service account: closes breaks whose difference has gone, a settlement landing or the custodian catching up, citing the statement where it was gone, and moves nothing. A break is never closed by silence.
async def close_breaks_as_cleared(
self, *, account_id: str = "", break_ids: Sequence[str] = (),
cleared_at: StreetRecordRef | None = None, reason: str = "", idempotency_key: str = "",
acting_for: str | None = None,
) -> CloseBreaksAsClearedResult
| gRPC | rpc CloseBreaksAsCleared(CloseBreaksAsClearedParams) returns (CloseBreaksAsClearedResult) |
| Workflow step | W9.7, Resolve or close a break |
| Kind | command, on platform.book.command.close-breaks-as-cleared |
| Role | operations |
| Served by | the book of record |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
yes | The account, in the plugin's write scope, and one the person may write. |
break_ids |
sequence of str |
yes, by the book | The breaks, each open. |
cleared_at |
StreetRecordRef or None |
yes, by the book | The statement where the difference was gone, by value, its statement_id set. |
reason |
str |
yes, by the book | The person's own words. |
idempotency_key |
str |
no | See Idempotency keys. |
acting_for |
str or None |
yes, by the book | The Meridian-Caller header of the person. |
Returns CloseBreaksAsClearedResult, a book entry's result holding the breaks closed.
Errors: CommandRefused with REFUSAL_REASON_ACTOR_REQUIRED, REFUSAL_REASON_REASON_REQUIRED, REFUSAL_REASON_BREAK_STATE or REFUSAL_REASON_IDEMPOTENCY_CONFLICT. handler error from the book for no breaks or no statement. NotGranted for an account outside the write scope, a person who may not write it, a session not opened by Open, or without the operations role. not vouched for, no handler or timeout.
list_positions¶
Reads the book's positions within the plugin's read scope, or one account's, each with its lots, pending settlements, encumbrances and free quantity, and its opening balance's sources; or those changed since a watermark; or the positions at the end of a business date, as known at a watermark or now. See Reads are within the read scope.
async def list_positions(
self, *, account_id: str = "", since: Watermark | None = None, business_date: str = "",
at: Watermark | None = None, page_size: int = 0, cursor: str = "",
) -> ListPositionsResult
| gRPC | rpc ListPositions(ListPositionsParams) returns (ListPositionsResult) |
| Workflow step | W9.10, Read positions |
| Kind | query, on platform.book.query.list-positions |
| Role | portfolio, reporting, compliance, oms, operations |
| Served by | the book of record |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
no | One account, which must be in the plugin's read scope. Empty for every account in it. |
since |
Watermark or None |
no | Only the positions whose last change is after it, removed ones included. |
business_date |
str |
no | The positions at the end of this ISO 8601 business date, served by replay from the journal. |
at |
Watermark or None |
no | As the book knew them at this watermark, so a report re-run there reproduces itself. |
page_size |
int |
no | How many to a page: 100 when 0, and never more than 500. |
cursor |
str |
no | The previous page's next_cursor, or empty for the first. |
A read by business date or at a watermark takes no since.
Returns ListPositionsResult: positions, a sequence of BookPosition; next_cursor; and as_of, the Watermark it was read at.
Errors: NotGranted for an account_id outside the read scope, and without one of the five roles. handler error from the book for a since beside business_date or at, or a business date that is not YYYY-MM-DD. no handler or timeout from the book.
page = await role.list_positions(account_id=account)
for position in page.positions:
trade_date = meridian.as_decimal(position.trade_date_quantity)
free = meridian.as_decimal(position.free_quantity) if position.HasField("free_quantity") else None
list_breaks¶
Reads breaks within the plugin's read scope, or one account's, open, resolved, closed or any of them, each with its cause, handling and resolution; or those changed since a watermark. See Reads are within the read scope.
async def list_breaks(
self, *, account_id: str = "", states: Sequence[BreakState | str] = (),
since: Watermark | None = None, page_size: int = 0, cursor: str = "",
) -> ListBreaksResult
| gRPC | rpc ListBreaks(ListBreaksParams) returns (ListBreaksResult) |
| Workflow step | W9.11, Read breaks |
| Kind | query, on platform.book.query.list-breaks |
| Role | operations, oms, compliance, portfolio, reporting |
| Served by | the book of record |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
no | One account, in the read scope. Empty for every account in it. |
states |
sequence of BreakState or str |
no | The states to answer. Empty for every state. |
since |
Watermark or None |
no | Only the breaks changed after it. |
page_size, cursor |
int, str |
no | As on list_positions. |
Returns ListBreaksResult: breaks, a sequence of Break; next_cursor; and as_of.
Errors: NotGranted for an account_id outside the read scope, and without one of the five roles. no handler, timeout or handler error from the book.
list_account_figures¶
Reads the accounts' figures within the plugin's read scope, by account and margin agreement, for a business date or a range of them; or those recorded since a watermark. Margin movement is a series per agreement: the book adds nothing up across agreements, and a reader that wants a total adds them. See Reads are within the read scope.
async def list_account_figures(
self, *, account_id: str = "", agreement: MarginAgreementRef | None = None,
from_date: str = "", to_date: str = "", since: Watermark | None = None,
at: Watermark | None = None, page_size: int = 0, cursor: str = "",
) -> ListAccountFiguresResult
| gRPC | rpc ListAccountFigures(ListAccountFiguresParams) returns (ListAccountFiguresResult) |
| Workflow step | W9.12, Read the account's figures |
| Kind | query, on platform.book.query.list-account-figures |
| Role | operations, portfolio, compliance, reporting |
| Served by | the book of record |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
no | One account, in the read scope. Empty for every account in it. |
agreement |
MarginAgreementRef or None |
no | One agreement. None for every agreement. |
from_date, to_date |
str |
no | ISO 8601 business dates, inclusive. Empty for open-ended. |
since |
Watermark or None |
no | Only the figures recorded after it. |
at |
Watermark or None |
no | As the book knew them at this watermark. |
page_size, cursor |
int, str |
no | As on list_positions. |
Returns ListAccountFiguresResult: figures, a sequence of AccountFigures; next_cursor; and as_of.
Errors: NotGranted for an account_id outside the read scope, and without one of the four roles. no handler, timeout or handler error from the book.
list_account_attributes¶
Reads the book's attributes of the accounts within the plugin's read scope, or one account's: the base currency, the default method of relieving lots, and the standing opening balance, with its entry, its date and its sources; or those changed since a watermark. A plugin learns from it that an account is in the book, and from which date it reconciles, without proposing an opening balance again. A deployment admin sets the first two on the dashboard's Accounts tab, in an account's In the book. See Reads are within the read scope.
async def list_account_attributes(
self, *, account_id: str = "", since: Watermark | None = None, page_size: int = 0,
cursor: str = "",
) -> ListAccountAttributesResult
| gRPC | rpc ListAccountAttributes(ListAccountAttributesParams) returns (ListAccountAttributesResult) |
| Workflow step | W9.14, Read an account's attributes |
| Kind | query, on platform.book.query.list-account-attributes |
| Role | portfolio, reporting, compliance, oms, operations |
| Served by | the book of record |
| Name | Type | Required | Meaning |
|---|---|---|---|
account_id |
str |
no | One account, in the read scope. Empty for every account in it. |
since |
Watermark or None |
no | Only the attributes changed after it. |
page_size, cursor |
int, str |
no | As on list_positions. |
Returns ListAccountAttributesResult: attributes, a sequence of AccountAttributes; next_cursor; and as_of.
Errors: NotGranted for an account_id outside the read scope, and without one of the five roles. no handler, timeout or handler error from the book.
page = await role.list_account_attributes(account_id=account)
if page.attributes and page.attributes[0].HasField("opening_balance"):
d0 = page.attributes[0].opening_balance.as_of_date # in the book since this date
record_prices¶
This operation is preview. Records a batch of 1 to 500 Prices into the lake, whole or refused naming the row and the field. A data plugin's.
async def record_prices(
self, *, prices: Sequence[Price] = (), want_id: str = "", acting_for: str | None = None,
) -> RecordPricesResult
| gRPC | rpc RecordPrices(RecordPricesParams) returns (RecordPricesResult) |
| Workflow step | W10.4, Record prices and bars in batches |
| Kind | command, on platform.lake.command.record-prices |
| Role | data |
| Served by | the lake, which records, sequences and publishes each row on its dataset's subject (W10.5) |
| Name | Type | Required | Meaning |
|---|---|---|---|
prices |
sequence of Price |
yes, 1 to 500 | Each with its envelope, ObservationMeta: a row key, 1 to 8 subjects the instrument store holds, its source's dataset (one the instance's catalogue declares, serving prices of that kind), its valid time, a daily value's business date, the source's times, and its raw record. Fewer than 1 or more than 500 raise ValueError before anything is sent. |
want_id |
str |
no | The want the rows answer, as heard in ObservationsWantedEvent.want_id; empty for rows recorded unasked. |
acting_for |
str or None |
no | A person's assertion, where a person asked for it. |
The sidecar stamps each row's source.instance and source.plugin_version; the lake decides recorded_at_ns, version, sequence and previous_sequence. Each Money is resolved to its cash instrument: a token's code in currency_code is refused.
Returns RecordPricesResult: recorded, the rows new; restated, the rows recorded as a new version of a row key already recorded with a changed value; unchanged, those repeating a version's values (by decimal value: 764.2 is 764.20); and the dataset's watermark.
Errors: CallFailed with kind="invalid" naming the row and field by its path (prices[3].meta.business_date): a dataset the instance does not declare or that does not serve prices, a subject the instrument store does not hold, a business date that is no day, a source time given twice, a venue that is no venue ID, a Money naming no asset or two. NotGranted without data.
from datetime import date
from decimal import Decimal
from meridian import Money, ObservationMeta, Price, SourceTime
from meridian.plugin.v1 import operations_pb2 as ops
done = await role.record_prices(prices=[
Price(
meta=ObservationMeta(
row_key="SPY:1d:2026-10-08", # from the raw record: a repeat changes nothing
subjects=[ops.SubjectRef(entity_id=spy)],
source=ops.Source(dataset=f"{plugin.identity.instance_id}:daily"),
valid_from_ns=open_ns, valid_until_ns=close_ns,
business_date=date(2026, 10, 8),
source_times=[SourceTime(kind="published", at_ns=published_ns)],
raw=role.plugin.raw_record("bars/SPY/2026-10-08"),
),
kind="close",
price=Money(Decimal("671.16"), "USD"),
basis="per_unit",
),
])
done.recorded, done.restated, done.unchanged
record_bars¶
This operation is preview. Records a batch of 1 to 500 Bars, as record_prices records prices.
async def record_bars(
self, *, bars: Sequence[Bar] = (), want_id: str = "", acting_for: str | None = None,
) -> RecordBarsResult
| gRPC | rpc RecordBars(RecordBarsParams) returns (RecordBarsResult) |
| Workflow step | W10.4, Record prices and bars in batches |
| Kind | command, on platform.lake.command.record-bars |
| Role | data |
| Served by | the lake |
Each bar's open, high, low, close and VWAP are in one asset, refused otherwise; its volume is never negative; its VWAP and trade count are left unset where the source gives none, which is not zero. The interval is its envelope's valid time, and a daily bar names its business date. Its parameters, result and errors are record_prices's, with bars for prices.
record_trades¶
This operation is preview. Records a batch of 1 to 500 Trades into the lake, as record_prices records prices. A data plugin's, from a dataset declaring meridian.v1.Trade.
async def record_trades(
self, *, trades: Sequence[Trade] = (), want_id: str = "", acting_for: str | None = None,
) -> RecordTradesResult
| gRPC | rpc RecordTrades(RecordTradesParams) returns (RecordTradesResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-trades |
| Role | data |
| Served by | the lake, which records each and publishes every one on its dataset's subject, never conflated (W10.5) |
Each trade is keyed by UTC instants: valid from its event time at its venue, valid_until_ns 0, and no business date. Its venue is the venue it printed on (a consolidated dataset's trade names its market centre). A correction or a withdrawal is the next version under the same row key, a withdrawal with cancelled=True. Its parameters and result are record_prices's, with trades for prices.
Errors: as record_prices, and: a quantity not more than zero, an unspecified trade characteristic, a trade naming a business date, a dataset not serving trades. NotGranted without data.
from decimal import Decimal
from meridian import Eligibility, Money, ObservationMeta, Trade, TradeAttributes
from meridian.plugin.v1 import operations_pb2 as ops
every = Eligibility(high_low="eligible", open="eligible", close="eligible", volume="eligible")
await role.record_trades(trades=[
Trade(
meta=ObservationMeta(
row_key="BTC-USD:t:812345678", # the product and the venue's trade ID
subjects=[ops.SubjectRef(entity_id=btc)],
source=ops.Source(dataset=f"{plugin.identity.instance_id}:trades", venue_id=venue),
valid_from_ns=traded_at_ns,
raw=role.plugin.raw_record("matches/BTC-USD/812345678"),
),
price=Money(Decimal("62510.01"), "USD"),
quantity=Decimal("0.0125"),
attributes=TradeAttributes(consolidated=every, market_centre=every),
aggressor="buy", # the side that took liquidity; unset where the source says nothing
source_sequence=812345678,
),
])
record_quotes¶
This operation is preview. Records a batch of 1 to 500 Quotes, as record_prices records prices. A data plugin's, from a dataset declaring meridian.v1.Quote.
async def record_quotes(
self, *, quotes: Sequence[Quote] = (), want_id: str = "", acting_for: str | None = None,
) -> RecordQuotesResult
| gRPC | rpc RecordQuotes(RecordQuotesParams) returns (RecordQuotesResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-quotes |
| Role | data |
| Served by | the lake, which publishes each, conflated per subject, dataset, venue and asset (W10.5) |
A quote is valid from its time until the next for the same subject, dataset, venue and asset, and names no business date. A side the source left empty is left unset (ask=None), never zero. Its parameters and result are record_prices's, with quotes for prices.
Errors: as record_prices, and: a bid and an ask in two assets, a quantity not more than zero, an unspecified quote characteristic, a quote naming a business date. NotGranted without data.
await role.record_quotes(quotes=[
Quote(meta=meta, bid=Money(Decimal("62510.00"), "USD"), bid_quantity=Decimal("0.84")), # no offer
])
decline_want¶
This operation is preview. Says what a data plugin cannot serve of a want, per subject, with a reason.
A read the lake cannot answer from what it holds becomes a want, heard only by the instance serving its dataset, by its data class's on_observations_wanted: an ObservationsWantedEvent with its want_id, dataset, data_type, subjects, kinds (for prices), interval_ns (for bars), a business_date or a valid range, and standing. The plugin fetches what it covers and records it with want_id=; what it cannot, it declines. A standing want asks that its subjects be kept current until a WantWithdrawnEvent (want_id, dataset), heard by on_want_withdrawn, withdraws it.
async def decline_want(
self, *, want_id: str = "", subjects: Sequence[SubjectRef] = (),
reason: UnansweredReason | str | None = None, acting_for: str | None = None,
) -> DeclineWantResult
| gRPC | rpc DeclineWant(DeclineWantParams) returns (DeclineWantResult) |
| Workflow step | W10.7, Want what a read could not answer |
| Kind | command, on platform.lake.command.decline-want |
| Role | data |
| Served by | the lake, which tells the waiting readers |
| Name | Type | Required | Meaning |
|---|---|---|---|
want_id |
str |
yes | The want, as heard. |
subjects |
sequence of SubjectRef |
yes | The subjects declined. |
reason |
UnansweredReason |
yes | Such as "not_covered", or "beyond_history". |
Returns DeclineWantResult, empty. Errors: CallFailed for a want this instance does not serve. NotGranted without data.
A decline stands for the business date or range its want asked, or for the latest where it asked the latest, and for no other date of that dataset and subject: a later want of another date is asked again.
class Lake(data.Role):
async def on_observations_wanted(self, heard: meridian.Heard) -> None:
want = heard.message
await self.record_prices(prices=fetched(want), want_id=want.want_id)
if uncovered:
await self.decline_want(want_id=want.want_id, subjects=uncovered, reason="not_covered")
async def on_want_withdrawn(self, heard: meridian.Heard) -> None:
stop_keeping_current(heard.message)
resolve_venue¶
This operation is preview. Asks which venue a set of codes names on a date, among the venues the deployment holds. Never mints one: a deployment pulls venues from the platform's venue master.
async def resolve_venue(
self, *, identifiers: Sequence[Identifier] = (), as_of_ns: int = 0, venue_id: str = "",
) -> ResolveVenueResult
| gRPC | rpc ResolveVenue(ResolveVenueParams) returns (ResolveVenueResult) |
| Workflow step | W3.14, Resolve a venue |
| Kind | query, on platform.reference.query.resolve-venue |
| Role | data |
| Served by | the instrument store |
| Name | Type | Required | Meaning |
|---|---|---|---|
identifiers |
sequence of Identifier |
one of these two | A MIC under iso10383, or the vendor's own code as a symbol with the vendor as its source. |
venue_id |
str |
one of these two | A venue's VEN- ID, to read the venue held under it: answered with its record, or a miss where the deployment holds none. Refused, naming venue_id, beside identifiers. |
as_of_ns |
int |
no | The date it is asked about; 0 for now. A MIC names the venue in force then. |
Returns ResolveVenueResult: found, when exactly one venue held is named; venue, its VenueRecord; and miss_reason, MISS_REASON_NOT_FOUND or MISS_REASON_AMBIGUOUS, when not.
Errors: no handler or timeout from the instrument store. NotGranted without data.
answer = await role.resolve_venue(
identifiers=[meridian.Identifier(scheme="symbol", value="V", source="alpaca")],
)
venue_id = answer.venue.venue_id if answer.found else "" # not held: report it, name none
report_missing_venue¶
This operation is preview. Reports that a venue the plugin's source named resolved to none the deployment holds. A fact, not a request: the plugin carries on, its row naming no venue and keeping the code as the source reported it.
async def report_missing_venue(
self, *, source: str = "", identifiers: Sequence[Identifier] = (), as_of_ns: int = 0,
reason: MissReason | str | None = None, observed_at_ns: int = 0,
) -> Published
| gRPC | rpc ReportMissingVenue(ReportMissingVenueParams) returns (Published) |
| Workflow step | W3.15, Report a venue the deployment does not hold |
| Kind | event, on platform.reference.event.venue-missing |
| Role | data |
| Heard by | the conductor, which asks the platform for the venue by its public codes, once and again only after ten minutes; and the lake, which counts the miss against the instance's datasets |
| Name | Type | Required | Meaning |
|---|---|---|---|
source |
str |
no | The namespace the code belongs to, such as "tradier". |
identifiers |
sequence of Identifier |
no | The codes the source named the venue by. |
as_of_ns |
int |
no | The date it was asked about. |
reason |
MissReason or None |
no | The miss_reason resolve_venue answered. |
observed_at_ns |
int |
no | When the plugin observed the miss. |
Returns Published. Errors: NotGranted without data.
list_prices¶
This operation is preview. Reads prices for up to 500 subjects at one of the latest in force at a valid time, a business date or a valid range; as the lake knew them at a recorded time; from the deployment's default sources, named datasets or every dataset side by side. Only what the plugin is entitled to is answered, and each field it may not read is stripped and named.
async def list_prices(
self, *, subjects: Sequence[SubjectRef] = (), kinds: Sequence[PriceKind | str] = (),
sources: SourceChoice | None = None, at_ns: int = 0, business_date: date | str = "",
valid_from_ns: int = 0, valid_until_ns: int = 0, as_of_ns: int = 0,
page_size: int = 0, cursor: str = "",
) -> ListPricesResult
| gRPC | rpc ListPrices(ListPricesParams) returns (ListPricesResult) |
| Workflow step | W10.6, Read prices and bars, point in time, by source |
| Kind | query, on platform.lake.query.list-prices |
| Role | reporting, portfolio, compliance, signal; operations, for closes and other conflated prices |
| Served by | the lake |
| Name | Type | Required | Meaning |
|---|---|---|---|
subjects |
sequence of SubjectRef |
yes | 1 to 500 instruments. |
kinds |
sequence of PriceKind |
no | Which kinds, such as ["close"]; none for every kind. |
sources |
SourceChoice or None |
no | The deployment's default (None, or default=True), named=[...] datasets, or side_by_side=True. |
at_ns |
int |
no | The latest in force at this valid time; 0 for now. |
business_date |
datetime.date or str |
no | A daily value's business date, in each dataset's own day. |
valid_from_ns, valid_until_ns |
int |
no | A valid-time range, from inclusive to exclusive. |
as_of_ns |
int |
no | The recorded-time cut: what the lake knew then; 0 for now. |
page_size, cursor |
int, str |
no | At most 500 a page, 100 when 0; the previous page's next_cursor. |
Give one of at_ns, business_date or the range. A read the lake cannot answer from what it holds is wanted of the data plugin serving the dataset, and answered asked_source in unanswered; the rows follow, heard with receive(prices_recorded=...). The latest is chosen per subject, dataset, kind, venue and the price's asset, so BTC priced in USD and in USDC on one venue answers both.
Returns ListPricesResult: prices, each a Price with its envelope as recorded; unanswered, each an Unanswered naming the subject, dataset, field and reason; datasets, each DatasetRef in the answer, once; the watermark it was read at; and next_cursor. A default read that fell through to a lower dataset says why the first did not answer.
Errors: CallFailed with kind="invalid" for no subject or more than 500, a business date that is no day. NotGranted without one of the four roles.
from datetime import date
closes = await role.list_prices(subjects=held, kinds=["close"], business_date=date(2026, 10, 8))
for price in closes.prices:
close = meridian.as_money(price.price) # names its cash instrument
for gap in closes.unanswered:
... # unvalued, never zero: gap.reason says why
then = await role.list_prices(subjects=held, business_date=date(2026, 10, 8), as_of_ns=friday_ns)
list_bars¶
This operation is preview. Reads bars as list_prices reads prices, with interval_ns (the bar's length, such as 86_400 * 10**9 for a day; 0 for every interval) in place of kinds.
async def list_bars(
self, *, subjects: Sequence[SubjectRef] = (), interval_ns: int = 0,
sources: SourceChoice | None = None, at_ns: int = 0, business_date: date | str = "",
valid_from_ns: int = 0, valid_until_ns: int = 0, as_of_ns: int = 0,
page_size: int = 0, cursor: str = "",
) -> ListBarsResult
| gRPC | rpc ListBars(ListBarsParams) returns (ListBarsResult) |
| Workflow step | W10.6, Read prices and bars, point in time, by source |
| Kind | query, on platform.lake.query.list-bars |
| Role | reporting, portfolio, compliance, signal |
| Served by | the lake |
Returns ListBarsResult: bars, each a Bar; unanswered, datasets, watermark and next_cursor, as list_prices.
list_trades¶
This operation is preview. Reads trades for up to 500 subjects over a valid-time range within one day of each dataset, or after a watermark: the trades each dataset recorded after the sequence the reader last saw there, whatever their valid time, a late or out-of-sequence print among them. From the deployment's default sources, named datasets, or side by side; as of a recorded time.
async def list_trades(
self, *, subjects: Sequence[SubjectRef] = (), sources: SourceChoice | None = None,
valid_from_ns: int = 0, valid_until_ns: int = 0, after_watermark: Watermark | None = None,
as_of_ns: int = 0, page_size: int = 0, cursor: str = "", latest_recorded: bool = False,
) -> ListTradesResult
| gRPC | rpc ListTrades(ListTradesParams) returns (ListTradesResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-trades |
| Role | signal, ems; data, for its own rows |
| Served by | the lake |
| Name | Type | Required | Meaning |
|---|---|---|---|
subjects |
sequence of SubjectRef |
yes | 1 to 500 instruments. |
sources |
SourceChoice or None |
no | The deployment's default, named=[...] datasets, or side_by_side=True. |
valid_from_ns, valid_until_ns |
int |
one of the two ways | A valid-time range, from inclusive to exclusive, within one day of each dataset as it declares its day; a wider range is refused naming it. |
after_watermark |
Watermark or None |
one of the two ways | The watermark the reader last saw: a previous answer's watermark, or one built from what it heard. Older than the lake keeps is answered beyond_history. |
as_of_ns |
int |
no | The recorded-time cut: nothing recorded after it answers. |
page_size, cursor |
int, str |
no | At most 500 a page; the previous page's next_cursor. |
latest_recorded |
bool |
no | A data plugin's: the last trade its own instance recorded of each subject, per dataset and venue, from its own datasets alone, in place of a range or a watermark. What it reads on start to backfill a restart's gap from the venue's history. A subject it never recorded answers nothing. |
Returns ListTradesResult: trades, each a Trade with its envelope as recorded; unanswered (not entitled, not kept and beyond history said per dataset); datasets; the watermark it was answered at, which a later catch-up names; and next_cursor.
Errors: CallFailed with kind="invalid" for no subject or more than 500, or a range wider than one day of a dataset. NotGranted without signal or ems, or data (which reads only its own rows, with latest_recorded).
day = await role.list_trades(subjects=held, valid_from_ns=open_ns, valid_until_ns=now_ns)
late = await role.list_trades(subjects=held, after_watermark=day.watermark) # a late print among them
A plugin hearing trades with their role classes' on_<event> methods has the SDK make the catch-up read for it.
A data plugin starting again:
or meridian.roles.data.backfill_restart, which reads it and records what the venue's history states since (see Write a data plugin).
list_quotes¶
This operation is preview. Reads quotes for up to 500 subjects at the latest in force at a valid time, chosen per subject, dataset, venue and the quote's asset, or over a valid-time range within one day of each dataset.
async def list_quotes(
self, *, subjects: Sequence[SubjectRef] = (), sources: SourceChoice | None = None,
at_ns: int = 0, valid_from_ns: int = 0, valid_until_ns: int = 0,
as_of_ns: int = 0, page_size: int = 0, cursor: str = "",
) -> ListQuotesResult
| gRPC | rpc ListQuotes(ListQuotesParams) returns (ListQuotesResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-quotes |
| Role | signal, ems |
| Served by | the lake |
Its parameters are list_trades's, with at_ns (the latest in force at this valid time; 0 for now) in place of after_watermark. A read the lake cannot answer is wanted of the data plugin serving the dataset, as a price's is. Returns ListQuotesResult: quotes, each a Quote; unanswered, datasets, watermark and next_cursor.
An event contract's outcomes¶
Added in SDK 0.27.0. This operation is preview. A data plugin
records an event contract's outcome, and prices' readers and operations
read it. See
An event contract's outcome.
record_outcomes¶
Records 1 to 500 event contracts' outcomes, each under its contract's row key, whole or refused naming the row and field.
| gRPC | rpc RecordOutcomes(RecordOutcomesParams) returns (RecordOutcomesResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-outcomes |
| Role | data |
| Served by | the lake |
Returns RecordOutcomesResult: recorded, restated and unchanged,
and the watermark. Each is delivered whole, every version, on
platform.lake.{dataset}.event.outcomes-recorded.
list_outcomes¶
Reads outcomes for 1 to 500 subjects, the event contracts' instruments: the version in force, as of a recorded time, or those recorded after a watermark.
async def list_outcomes(
self, *, subjects: Sequence[SubjectRef] = (), after_watermark: Watermark | None = None,
as_of_ns: int = 0,
) -> ListOutcomesResult
| gRPC | rpc ListOutcomes(ListOutcomesParams) returns (ListOutcomesResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-outcomes |
| Role | reporting, portfolio, compliance, signal, operations |
| Served by | the lake |
An outcome has no business date, so none is asked. Returns
ListOutcomesResult: outcomes, each an Outcome, and the
watermark.
list_datasets¶
This operation is preview. Reads the datasets the plugin may read, each with its instance, vendor, aggregator and catalogue entry, the licence of each, and the plugin's own entitlements. The SDK reads it once to join each heard row's dataset (Heard.dataset).
| gRPC | rpc ListDatasets(ListDatasetsParams) returns (ListDatasetsResult) |
| Workflow step | W10.9, Read the datasets |
| Kind | query, on platform.lake.query.list-datasets |
| Role | reporting, portfolio, compliance, signal, ems; data, for its own datasets |
| Served by | the lake |
Returns ListDatasetsResult: datasets, each a DatasetRef; licences, each dataset's licence enforced; and entitlements, the plugin's own.
Each DatasetRef carries closed_day_count and outside_coverage_count
(added in chart 0.1.303), and declared_delay_ns, stale_after_ns and
liveness (see
Data age and liveness).
A data plugin's own datasets. Asked by a data plugin, it answers only the datasets its own catalogue declares, each with the licence a deployment admin set on it, so its Datasets page says "Licensed" or "Not licensed yet" exactly; a dataset no deployment admin has licensed answers no licence set by the deployment, and is kept and read with each use right read restrictively.
list_source_priorities¶
This operation is preview. Reads the order a default read takes its sources in: for each data type, and for prices each kind, the datasets first to last. Added in SDK 0.36.0.
| gRPC | rpc ListSourcePriorities(ListSourcePrioritiesParams) returns (ListSourcePrioritiesResult) |
| Workflow step | W10.2, Order the sources a default read takes |
| Kind | query, on platform.lake.query.list-source-priorities |
| Role | reporting, portfolio, compliance, signal, ems, oms, operations, servicing; read-only |
| Served by | the lake |
Returns ListSourcePrioritiesResult: priorities, each a SourcePriority: its data_type, its kind for a price, its datasets first to last, and who set it, when and why. Each lists only the datasets the plugin is entitled to read, and a priority naming none of them is not answered, so what it answers is the whole of what the plugin may use. Setting a priority is a deployment admin's, at Data sources (see Licences and entitlements). The role suites' case reads-the-source-priorities holds a plugin to it.
The order path¶
Every operation here is
preview. What each role does on the path, the states and the transition
table are on The order lifecycle; the
Python SDK's overview is The order path.
- A command answers the record whole, with the book's
entryand itsjournalreference: an order's commands answer theorder; a placement's, theplacement; a report, whichever records it changed (placement,execution,order,charge) or, where the book could not place it, theunplacedfact; and a change, itschange_request_id. It is answered only after its entry commits. - Every command but a fact report acts for someone: pass
acting_for=request.caller.headerfor a person, or call it from an act reached for the role's service account. One with nobody behind it is refusedREFUSAL_REASON_ACTOR_REQUIRED. A fact a connectivity plugin reports from its venue (report_placement,report_execution,report_charge,record_locate) names nobody. - Orders are
portfolio's and theoms's, placements theems's, fills the connectivity plugin's. A connectivity plugin'srecord_orderorcreate_placementis refused by its sidecar,NotGranted(PERMISSION_DENIED), as any operation its role does not hold. It reports a fill the venue originated on no placement (report_executionnaming no placement), which theemsaccepts (accept_execution) or answers DK (dont_know_execution). - Idempotency. A command naming an
idempotency_keyis applied once for it; the same key on another command is refusedREFUSAL_REASON_IDEMPOTENCY_CONFLICT. A venue fact repeated with the same venue identifiers is applied once. - A command naming a record by its ID -- an order, a placement, a change
request or a locate -- is held by the book to the plugin's write scope and
the person's write access: outside them it raises
NotGranted, with no code, and changes nothing. - Enums take their lower-case names as elsewhere:
side="buy",order_type="limit",time_in_force="day",condition="claimed",event="acknowledged"(see Enums). - Refusals by the order's state, a claim or a link are a
CommandRefusedwith its code; see The order lifecycle's refusals.
propose_order¶
portfolio proposes an order; the oms does too; an ems or the oms
proposes a child order,
naming its parent in link (OrderLink(kind="split", parent_order_id=...)).
Answers the order at proposed, or for a child at released.
| Parameter | Meaning |
|---|---|
account_id, instrument_id, side |
Its identity, never changed: buy, sell, sell short or sell short exempt. A short names its locate_id |
quantity or cash_quantity |
Exactly one: a unit quantity, a Decimal, or a cash quantity, a Money. Both or neither is refused invalid, naming both. 0 is refused |
order_type, limit_price, stop_price |
Its type, its limit and a stop's trigger, each a Money where given |
time_in_force, expire_date, expire_time_ns |
Its time in force, and a good-till-date's date or a good-till-time's time |
sleeve |
The part of the account it is for; empty for the unsleeved part |
dealt_currency, legs |
On a pair, the dealt currency's cash instrument; legs, each an instrument, a side and a ratio. A package names no top-level instrument and 2 to 16 legs, the ratios whole and in lowest terms, at most one leg in no option or future, no leg in an expired series or one with no INS- record; its quantity is package units and its limit one net price per unit, positive a debit |
position_effect |
open or close, required on an order or a leg in an option or a future, refused on any other |
quote_currency |
On a pair: the quote currency's cash instrument, the pair's second currency as quoted. One naming the order's own instrument is refused invalid naming it; a limit or stop in another currency, naming limit_price or stop_price |
allocation_instruction |
The accounts and amounts or weights it is for; none for the whole in its own account. A child carries none |
execution_instructions, lot_relief_method, relieve_lot_ids, capacity |
The oms's: the standard execution instructions, how a sale relieves lots or the lots it names, and capacity |
direction, parties, decided_by |
A client's order received, the parties as delivered, and who decided it where that differs from who enters it |
customer_id, firm_designated_id, handling_instructions, received_at_ns, received_precision, quote_at_receipt, represents_order_ids |
Fields recorded for reporting, as the proposer knows them |
value_date |
An FX order's value date as portfolio states it, an ISO 8601 date; empty is spot, the pair's spot date on the trade date the order opened |
net_member_order_ids |
The oms's net order: its members, released FX orders of one pair and one value date, of both sides. See the refusals there |
axe_source, axe_counterparty_id |
Carried empty |
link |
A child's split link to its parent |
idempotency_key, acting_for |
As above |
record_order¶
The oms records an order the book did not create, a telephoned or outside
order, for a person or its role's service account: never through the gate,
recorded at the state its facts imply. A connectivity plugin records no order (NotGranted).
| Parameter | Meaning |
|---|---|
account_id |
The account it is in, within the oms's write scope and the person's write access |
instrument_id, side, sleeve |
What it trades, its side and the part of the account it is for |
quantity, order_type, limit_price, time_in_force |
As the person recording it states them |
venue_order_id |
The venue's or broker's order ID, kept as an external reference, never a key |
origin |
telephoned: a telephoned or outside order |
idempotency_key, acting_for |
As above. One sent for no one is refused REFUSAL_REASON_ACTOR_REQUIRED |
An instrument whose record is incomplete is refused
REFUSAL_REASON_INCOMPLETE, and a venue order ID already recorded
REFUSAL_REASON_IDENTIFIER_IN_USE. Its executions follow as done-away
entries naming it (report_execution).
request_order_change¶
Asks for a change to an order: a cancel, an amendment of its limit, time in
force or execution instructions, a recall, a withdrawal, or portfolio's
increase or reduction with its allocation amended in the same act
(change, an OrderChange), with a reason where the change is justified.
Answers the order, at change requested while any is outstanding, and the
change_request_id. An ems changes no quantity
(REFUSAL_REASON_ORDER_STATE).
record_check¶
compliance's verdict, pass, warn, block or refuse, with its rule
and a note: on an order, naming the order_version it checked, or on a
placement_id before its connectivity plugin sends it. A refuse ends a
proposed order refused; the last verdict awaited clears awaiting check.
decide_approval¶
Sets approval required on a proposed order by policy, approves it, overrides
a block with a reason, or, by the oms asked to work it, rejects it
(decision). An approval or an override needs a person
(REFUSAL_REASON_ACTOR_REQUIRED), an override a reason.
release_order¶
The oms releases a proposed order through the gate: allocation, block,
approval, state, refused at the first that fails. Where the account waits
for compliance and a covering compliance plugin has not answered, the
order stays proposed, awaiting check, and nothing is refused.
set_working_condition¶
Sets or clears claimed, held or paused on an order
(condition, set), with a reason. While an order is claimed only the
claimant creates or changes its placements and child orders
(REFUSAL_REASON_CLAIMED). A hold may carry its
cause, hold_cause="reference_price_stale", with stale_reference, a
StaleReference (the dataset, the price's age_ns and the ceiling_ns
in force), kept on the held condition so a reader reads the cause typed;
roles.ems.ReferenceCheck.hold sends it. A cause on any condition but
held is refused invalid, naming hold_cause. See
The stale-reference check.
create_placement¶
The ems places part of a released order at one of the connectivity
plugins linked to it; no other role creates a placement.
| Parameter | Meaning |
|---|---|
order_id |
The released order |
connectivity_instance_id |
The connectivity plugin it goes to: one of request.caller.connectivity_instance_ids. Any other is refused REFUSAL_REASON_CONNECTIVITY_NOT_ALLOWED, and recorded. A manual placement names none, and every other names one: refused invalid naming it otherwise |
venue_account_code |
The code the ems's map holds for the order's account at that plugin |
quantity, limit_price, time_in_force |
The placement's |
strategy |
A StrategyInstruction to work at the venue: its kind (VWAP, TWAP, POV, IS), start and end, participation, urgency and limits |
destination, route_type, handling_instructions |
The destination's venue ID, the route type, and handling instructions, recorded for reporting |
placement_type |
How it is executed, set once: dma, algo (which needs a strategy), care, rfq or manual; DMA, care and manual carry no strategy, and an order of type RFQ takes only RFQ placements, each refused invalid naming the field. Unset reads as DMA. See Placement types |
counterparty_contact, agreed_at_ns, agreed_precision |
A manual placement's trade details, its evidence: the counterparty's contact, and when the trade was agreed with its precision. Its counterparty is its destination |
stale_reference |
A placement the ems sends past its reference price's ceiling, under warn: the book records it with the condition PLACEMENT_CONDITION_SENT_ON_STALE_REFERENCE |
rfq_id, axe_id |
Carried empty |
idempotency_key, acting_for |
As above |
Answers the placement at queued; the order is working once quantity commits.
request_placement_change¶
The ems or the oms asks to cancel or replace a placement (change, a
PlacementChange: its kind, cancel or replace, and a replace's new
quantity, limit_price and time_in_force), with a reason; tracked to
its outcome. The placement carries its own change requests
(change_requests), each with its PlacementChange and its outcome
(pending, applied or rejected), so its connectivity plugin, hearing it,
tells a cancel from a replace by the kind, never by a condition's reason;
several may be outstanding. A connectivity plugin reports through it only a
cancel it already sent at the venue under a stop, naming the stop's entry
as its cause.
report_placement¶
A connectivity plugin reports what the venue did with a placement
(event): sent, acknowledged (with its venue_order_id, routed_at_ns
and routed_precision), replaced, done for day, restated (with its
restatement_reason), suspended, triggered, cancelled, expired, rejected
(with its rejection_reason: unsupported, venue rejected or held by
pre-trade check, and rejection_as_reported only where none maps), outcome
unknown (with its unknown_reason, and status_as_reported for a status
that maps to nothing), or that outcome resolved; each with its
raw_record.
report_execution¶
A connectivity plugin reports an execution of a placement; the ems or the
oms enters a manual or done-away one, for a person.
| Parameter | Meaning |
|---|---|
placement_id, order_id, account_id, venue_account_code |
What it fills. A connectivity plugin names the code, and the sidecar stamps the account from the ems's map |
venue_execution_id |
The venue's, or one derived from the fill the same way every time |
kind, source |
Venue reported, manual, done away or inferred; primary or drop copy |
quantity, price, trade_time_ns, trade_date |
The fill |
settlement_date |
The date the venue states, kept as stated |
computed_settlement_date, settlement_date_basis |
The date compute_date gave and its basis, where the venue states none or the plugin also asks. A fill with no settlement date at all is refused invalid, naming settlement_date |
finality, fees |
Its finality and when reached; its fees, each a kind, a signed amount and its asset, a rebate negative |
supersedes, effective_date |
For a bust or correction: the execution it supersedes, and the date it takes effect |
counterparty, liquidity_indicator, venue_id |
The counterparty where known, maker or taker, and the place of execution |
uti, uti_generated_by, prior_uti, upi, given_up_to, trade_chain_reference, settlement_counterparty |
Fields recorded for reporting, as the venue states them |
cross_rate_source |
On an internal cross of a net order, which convention set its rate: net_street_rate or mid_at_netting. A cross on an order that is no net, or one with none, is refused invalid naming the field |
multi_leg_reporting_type, package_execution_id |
A package's fill: package for the package's own execution, which books nothing, and leg for each leg's, naming the package's (FIX 442). A leg's fill names its package execution, and nothing else names one |
instrument_id, side, venue_order_id, venue_client_order_id |
A fill on no placement the venue originated: its instrument, side and the venue's order ID, each required on such a fill and refused invalid naming it without, and the venue's client order ID where sent. Recorded unmatched |
raw_record, idempotency_key, acting_for |
As above |
A fee's kind is exchange, cancel, network, financing or
commission (the last two).
report_charge¶
A fee with no fill on a placement (fee), such as a venue's cancel fee, or
a rolling position's financing at a roll, with its
trade_date, settlement_date and raw_record: it moves cash and counts
toward no quantity. One naming no placement the book holds, or none, is
kept unplaced (UNPLACED_REASON_UNKNOWN_PLACEMENT).
acknowledge_flag¶
The oms or operations acknowledges an order's late fact
(condition), for a person, with a reason. Does not tie out is never
acknowledged.
list_trading_instructions¶
The trading instructions in force, whatever the plugin's accounts: read on
start, and after a gap with since, the watermark last seen, answered
as_of; paged by page_size and cursor. Its control_sequence is the
instructions' sequence as of as_of.
list_orders¶
The orders in the plugin's read scope (account_id narrows to one), as of
now or changed since a watermark, answered as_of: orders,
placements, executions and unplaced_facts, each in its own list. A
connectivity plugin reads only the placements naming it, and the orders
behind them. execution_state (unmatched, matched,
dont_know) answers only the executions in that state; unmatched leaves
out a fill superseded by a bust or a correction, and the bust.
read_order_history¶
One order's journal from its first entry (account_id, order_id), every
entry with its actor, cause and times, paged. The history never changes.
record_locate¶
A fund's connectivity plugin records a locate it requested of its prime
broker: the instrument_id, the quantity_requested and the
venue_account_code; and later the prime's answer on the same record
(locate_record_id): the quantity approved, the rate, the expiry and the
prime's ID; each with its raw_record.
list_locates¶
The locates in the plugin's read scope, as of now or changed since a
watermark, each with its uses and its remaining quantity.
record_locate_use¶
compliance or the oms records a use of a locate (use): a reservation
for an order, its give back, or its consumption by fills. A use of an
expired locate is refused REFUSAL_REASON_ORDER_STATE.
report_venue_catalogue¶
A connectivity plugin publishes its venue's catalogue for one venue account
code (catalogue, a VenueCatalogue): order types with their time-in-force
values, the broker's strategies with their parameters (each a name, a type,
whether it is required, its range or allowed values and its default), and
eligibility for the instruments it states; and
execution_acknowledgement, what its venue takes of an accept or a DK
(none, bn or dont_know_trade; unset reads as none); and
environment, the environment its session reached,
read from the vendor's host: live, paper or sandbox, empty for no
report, which the agents' guard counts
live; and placement_types, the
placement types its venue
takes, beside its order types. Delivered latest per plugin and code; heard
by the ems and the oms.
read_venue_catalogue¶
An ems or an oms reads a connectivity plugin's catalogue for a venue
account code (connectivity_instance_id, venue_account_code), on start
and after a loss; empty for a code not published.
map_venue_account¶
An ems's admin page maps a book account to the venue account code it
trades under at one of the ems's connectivity plugins
(connectivity_instance_id, venue_account_code, account_id; an empty
account_id removes the mapping), sent acting for the admin viewing it.
Answers the ems's mappings. An account not granted to the ems is
refused REFUSAL_REASON_ACCOUNT_NOT_LINKABLE; a connectivity plugin not
linked to it REFUSAL_REASON_CONNECTIVITY_NOT_ALLOWED; a code already
mapped on that plugin for another account is refused.
accept_execution¶
Added in SDK 0.27.0. The ems accepts 1 to 500
unmatched executions of one account, instrument, side, connectivity plugin
and trade date to an order, for a person or its service account. See
Venue-originated fills.
| Parameter | Meaning |
|---|---|
execution_ids |
The unmatched executions, each once; one named twice is refused invalid, naming execution_ids[i] |
order_id or new_order |
The oneof matched_order: an existing order the ems may place against, or a NewOrderFromExecutions (its sleeve and note) made from the fills, recorded filled with origin ORDER_ORIGIN_ACCEPTED_EXECUTION |
note |
Why, kept on the accept's entry |
acting_for |
As above |
Returns AcceptExecutionResult: the executions at matched, the
order, the placement created at filled, and the journal reference.
Refused REFUSAL_REASON_EXECUTION_STATE, _EXECUTIONS_DIFFER,
_QUANTITY_EXCEEDS_ORDER, _ORDER_STATE, _CLAIMED or _ACTOR_REQUIRED.
dont_know_execution¶
Added in SDK 0.27.0. The ems answers 1 to 500
unmatched executions DK (execution_ids), with a reason, a DkReason
(unknown_instrument, wrong_side, quantity_exceeds_order,
no_matching_order, price_exceeds_limit, calculation_difference,
other), and text, required with other (refused invalid naming
text). Returns DontKnowExecutionResult: the executions at DK, each
keeping dk_reason and dk_text, and the journal reference. Refused
REFUSAL_REASON_EXECUTION_STATE or _ACTOR_REQUIRED.
report_value_date_roll¶
Added in SDK 0.27.0. A connectivity plugin reports its venue's roll of an account's spot position in a pair to the next value date. See A venue's value-date roll.
| Parameter | Meaning |
|---|---|
venue_account_code |
The code; the sidecar stamps the account from the ems's map |
pair |
The pair's two cash instruments, as the date read's spot inputs name them; refused invalid naming pair unless both are cash instruments |
from_value_date |
The value date the pending lines leave |
to_value_date, value_date_basis |
The date compute_date gave for the roll's moment, and its basis (a meridian.DateBasis) |
rolled_at_ns |
The roll's moment |
charge_ids |
The CHG- IDs of the financing charges reported first |
raw_record, idempotency_key |
As above |
Returns the book's fact reply, ReportValueDateRollResult: its entry
(kind value-date-rolled) and journal, or the unplaced fact, its kind
value-date-roll, where the code is unmapped
(UNPLACED_REASON_UNMAPPED_VENUE_ACCOUNT) or nothing is pending on the
from date (UNPLACED_REASON_NOTHING_PENDING). A missing date or basis, or
a new date not after the old, is refused invalid, naming the field.
Booking and the one-ID model's operations¶
Added in SDK 0.28.0. Every one is preview. A command acting for
a person takes acting_for, as the order path's do. See Booking and
One ID per instrument.
set_allocation_instruction¶
portfolio, or operations for a client's instruction, or from chart 0.1.309 the oms, amends an order's
allocation instruction: order_id, allocation_instruction (its lines,
each an account with its amount or weight and its sleeve) and reason.
Returns the order. Refused REFUSAL_REASON_ORDER_STATE where an
account would fall below what its live bookings already allocate;
_REASON_REQUIRED, _ACTOR_REQUIRED.
book_order¶
The oms books an explicit list of executions on one order, a block
included: order_id, execution_ids, allocations (each an
Allocation: account_id, sleeve, quantity, average_price,
gross_amount, fees each with its kind and capitalised, net_amount,
intended_settlement_date, average_priced, relieve_lot_ids, and on an
error account error_cause, reason and error_text) and hand_off, to
hand off in the same act where the check passes. Returns the
booking (its BKG- ID, state and allocations, each with its ALC- ID),
its entry and journal. Refused REFUSAL_REASON_BOOKING_UNBALANCED,
_ACCOUNT_NOT_INSTRUCTED, _ORDER_STATE (naming the execution),
_REASON_REQUIRED or _ACTOR_REQUIRED; ERROR_CAUSE_OTHER with no text
invalid, naming the field.
hand_off_booking¶
The oms hands a booked booking off to operations (booking_id), or
closes a client's booking the firm does not settle (close). Returns
the booking handed off or closed, or held with its held_reason where
executed no longer equals allocated, a held-booking alert raised. Refused
REFUSAL_REASON_ORDER_STATE for a booking handed off, closed or
cancelled; _ACTOR_REQUIRED.
correct_booking¶
booking_id, kind (BOOKING_CORRECTION_KIND_CANCEL, the oms's before
the hand-off; BOOKING_CORRECTION_KIND_REPLACE, operations' after it),
the whole new allocations, effective_date (a replace's, the trade date
by default) and reason. Returns the booking cancelled, or its new
version, the movement lines journalled as their own entry. Refused as
book_order is, and _ORDER_STATE for the wrong kind for the state or
the actor.
list_bookings¶
The bookings in the plugin's read scope: account_id, since (a
watermark), state, page_size and cursor. Returns bookings, each
with its allocations, as_of and next_cursor. A reader also hears each booking change, BookingUpdated.
report_give_up¶
A connectivity or confirmation plugin reports a prime broker's answer
to a give-up: execution_id, allocation_id where one is booked,
answer (GIVE_UP_ANSWER_ACCEPTED or GIVE_UP_ANSWER_REJECTED),
prime_reference, reason and raw_record. A fact, never refused for its
state. Returns the book's fact reply; a report naming nothing the book
holds is an unplaced fact.
record_sleeve_cross¶
The oms records a cross between two sleeves of one account, at
portfolio's decision: a SleeveCross naming the instrument, the giving
and receiving sleeves, the quantity, the cross price and its source, who
decided and why, and order_ids, the two opposite orders it stands in for.
Returns the sleeve_cross (its SXC- ID) and journal. Refused
invalid naming order_ids for an order of another account or
instrument, or two of one side; _ORDER_STATE for an order ended;
_ACTOR_REQUIRED, _REASON_REQUIRED.
raise_alert¶
compliance raises an alert of its own on an account: account_id,
kind (ALERT_KIND_COMPLIANCE), reason and subject (an order, a
booking, an allocation or a position). Returns the alert (its ALR-
ID) and journal.
acknowledge_alert¶
compliance acknowledges an alert for a person: alert_id and reason.
An error-account alert is acknowledged so; a held-booking alert records
the acknowledgement and stays until the booking hands off or closes.
Refused _ACTOR_REQUIRED with no person, _REASON_REQUIRED.
list_alerts¶
The alerts in the plugin's read scope: account_id, since, state,
kind, page_size and cursor. Returns alerts, as_of and
next_cursor. A reader also hears each alert change, AlertChanged.
read_local_record_orders¶
Takes nothing. Returns allows_local_record_orders, the setting in
force, and open_order_count, the live orders on local records across the
deployment, naming no account and no order. A plugin that proposes or
accepts reads it, so it can tell a person before sending that an order on a
local record would be refused (REFUSAL_REASON_LOCAL_RECORD_NOT_ALLOWED).
list_replacements¶
Every role. The replacements the instrument store recorded after
after_sequence: returns replacements, each as its
instrument-replaced event carried it (the record replaced, the record it
became, its cause, REPLACEMENT_CAUSE_MERGED, _RESOLVED or
_PLATFORM_MERGED, and its sequence), and the sequence read to.
Reference data, answered whatever the plugin's accounts. Every role also
hears each replacement as it happens; the SDK keeps a current-ID map from
both.
list_templates¶
Every role. The template catalogue the deployment holds, each template
at its latest version, or with asset_class that class's templates, its
base template among them: each template's template_id,
template_version, name, asset_class,
instrument_type (unspecified for a class's base template), base, its
fields (each with its path, type and whether it is required) and its
match_rule.
read_template¶
Every role. One template at a version, template_id and
template_version, as list_templates answers each; or not held.
offer_template_fields¶
A reference plugin offers a record's template fields, each value with
its provenance, the plugin itself the source: instrument_id,
template_id, template_version and fields. The values are kept as
offers, never decisions: one is in force only once a person accepts it,
and never overwrites a person's. The plugin never asks for a mint.
Returns the record at its new version. Refused, naming the field, for
a field the template does not have, a value not of its type, or a template
or version the catalogue does not hold.
Settlement calendars' reads¶
Every role reads both, whatever its accounts. See Settlement calendars and, in the Python SDK, Settlement calendars.
read_calendar¶
A calendar's days over a range, calendar_id, from_date to to_date, as
of a recorded time (as_of_ns) or its latest version. Answers found, the
calendar_id and version, its weekends, the days listed in the range
(each a date, closed or a weekend business day, its name and its source),
its coverage and its sources. A calendar not held is answered not found
and asked of the platform; a range ending before it starts is refused,
naming to_date. A calendar of the kind
CALENDAR_KIND_TRADING_SESSIONS also answers trading_sessions, its time
zone, sessions and the early closes in the range (see
Trading sessions);
every other calendar answers it unset.
compute_date¶
Works out a date, one way, in core. Exactly one question:
| Question | Inputs |
|---|---|
settlement |
SettlementDateInputs: an instrument and a trade date; answered by its market's rule |
spot |
SpotDateInputs: a pair of cash instruments and a trade date, or an execution's moment (at_ns) through the pair's cut |
tenor |
TenorDateInputs: a pair, a trade date and a Tenor (a count and a unit: day, week, month, year, overnight, tom-next, spot-next) |
roll |
RollInputs: a date, a convention and a set of calendars |
business_day |
BusinessDayInputs: a date and a set of calendars |
and as_of_ns, a recorded time, 0 for the latest versions. Answers date
and its basis (the rule and its version, each calendar and its version)
where the outcome is DATE_OUTCOME_COMPUTED; business_day for that
question; otherwise the outcome says why nothing was computed:
DATE_OUTCOME_CALENDAR_NOT_HELD, DATE_OUTCOME_OUTSIDE_COVERAGE or
DATE_OUTCOME_RULE_NOT_HELD. A malformed question is refused invalid,
naming the field; a cut's zone the deployment does not hold is refused,
naming spot.at_ns.
The analytics component, event groups and the agents' guard¶
Added in SDK 0.31.0. Every one is preview. They serve
the analytics component,
event groups,
the agents' guard and the lake's bounded
query. The Python SDK wraps most of them: meridian.analytics builds and
runs a job, meridian.roles.pricing.Pricer answers a pricing plugin's
batches, meridian.EventGroups keeps the event groups read and heard, and
plugin.query_lake is the bounded query. Three events come with them,
heard through their role classes' on_<event> methods: event_group_changed
(every role but pricing), job_finished (the roles that run jobs, each
hearing its own) and price_batch (pricing, each instance hearing the
batches routed to it).
report_event_group¶
A venue's data plugin reports the grouping its venue states for an event. See Reported, then minted.
async def report_event_group(
self, *, venue_id: str = "", venue_event_ref: str = "", title: str = "",
member_instrument_ids: Sequence[str] = (), mutually_exclusive: EventGroupFlag | str | None = None,
exhaustive: EventGroupFlag | str | None = None, series_id: str = "", valid_from_ns: int = 0,
raw_record: RawRecordRef | None = None, member_bounds: Sequence[EventGroupMemberBound] = (),
acting_for: str | None = None,
) -> ReportEventGroupResult
| gRPC | rpc ReportEventGroup(ReportEventGroupParams) returns (ReportEventGroupResult) |
| Workflow step | W3.29, Report an event group |
| Kind | command, on platform.reference.command.report-event-group |
| Role | data |
| Served by | the instrument store |
| Parameter | Meaning |
|---|---|
venue_id |
The venue that states the group, by its venue ID (resolve_venue) |
venue_event_ref |
The venue's own reference for its event, 1 to 256 characters: with the venue, the group's identity |
title |
The venue's words for the event, up to 1,024 characters; data, never instructions |
member_instrument_ids |
1 to 500 members, each the deployment's record of one of the event's contracts, resolved (resolve_identifier) before it is sent. One the store does not hold, or one named twice, is refused, naming it; one replaced since is followed to its replacement |
mutually_exclusive, exhaustive |
Each as the venue states it, true or false, or not_stated where it says nothing, never false for unknown. Unset reads as not stated |
series_id |
The venue's series for a recurring event, up to 256 characters; empty for none |
valid_from_ns |
When the grouping took effect; 0 for now |
raw_record |
The raw record it was read from (role.plugin.raw_record(...)) |
member_bounds |
Each range member's floor, cap and bound_unit as the venue states them, each an EventGroupMemberBound naming one of the members. The store offers them for the member's record, where a person accepts them; a person's value wins. A bound naming an instrument that is not a member is refused invalid, naming member_bounds[i].instrument_id |
Returns ReportEventGroupResult: event_group, the
EventGroup at its version, under the platform's EVG- ID
or the deployment's own LCL- ID; and pending_review, true where the
platform holds the group for review while the deployment keeps its own. A
report saying what the version in force already says is answered with that
version, and keeps nothing new. A report with no venue or event reference,
or with a title, series or reference too long, is refused invalid,
naming the field.
list_event_groups¶
Reads event groups, by member or by group, at the version in force at a moment, or every version kept after a sequence.
async def list_event_groups(
self, *, instrument_ids: Sequence[str] = (), event_group_ids: Sequence[str] = (),
as_of_ns: int = 0, after_sequence: int = 0, page_size: int = 0, cursor: str = "",
) -> ListEventGroupsResult
| gRPC | rpc ListEventGroups(ListEventGroupsParams) returns (ListEventGroupsResult) |
| Workflow step | W3.30, Read event groups, and hear each change |
| Kind | query, on platform.reference.query.list-event-groups |
| Role | every role but pricing |
| Served by | the instrument store |
| Parameter | Meaning |
|---|---|
instrument_ids |
The groups holding these instruments, each followed through its replacement |
event_group_ids |
Or these groups |
as_of_ns |
The version in force at this moment; 0 for now |
after_sequence |
Or every version kept after this sequence, to catch up after a gap |
page_size, cursor |
Up to 500 a page; the next_cursor of the page before |
Returns ListEventGroupsResult: event_groups, each an
EventGroup; the sequence read to; and next_cursor,
empty on the last page. Each new version is also delivered whole, as
event_group_changed. Reference data, answered whatever the plugin's
accounts.
query_lake¶
One read-only query over one of the lake's kinds, within the asking instance's entitlements and its roles' kinds.
async def query_lake(
self, *, kind: str = "", subjects: Sequence[SubjectRef] = (), sources: SourceChoice | None = None,
valid_from_ns: int = 0, valid_until_ns: int = 0, from_date: date | str = "", to_date: date | str = "",
as_of_ns: int = 0, fields: Sequence[str] = (), row_limit: int = 0,
) -> QueryLakeResult
| gRPC | rpc QueryLake(QueryLakeParams) returns (QueryLakeResult) |
| Workflow step | W10.10, Query the lake within bounds |
| Kind | query, on platform.lake.query.query-lake |
| Role | reporting, portfolio, compliance, signal, ems, operations, data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
kind |
prices, bars, trades, quotes, outcomes or, rates. One the asking role does not read is refused, naming it (see Who reads what) |
subjects |
At most 500 |
sources |
A SourceChoice; none set is the deployment's source priority |
valid_from_ns, valid_until_ns |
A range of valid times, from inclusive, until exclusive |
from_date, to_date |
Or a range of business dates, both inclusive. Neither range set reads the latest |
as_of_ns |
The recorded-time cut-off; 0 for now |
fields |
The fields wanted, each by its data dictionary entry, such as meridian.v1.Price.price; none names every field the plugin may read |
row_limit |
1 to 10,000; 0 reads 1,000 |
Returns QueryLakeResult: the rows of the kind asked, in prices,
bars, trades, quotes, outcomes or rates, each with only the fields named,
the other lists empty; unanswered, per subject, dataset and field, each
an Unanswered; the datasets read; the watermark; and
truncated, true when more rows matched than row_limit. It is never
paged: narrow the query instead.
read_agent_orders_demo_only¶
Reads the agents' guard in force.
| gRPC | rpc ReadAgentOrdersDemoOnly(ReadAgentOrdersDemoOnlyParams) returns (ReadAgentOrdersDemoOnlyResult) |
| Workflow step | W11.39, Read whether agents' orders are kept to demo connections |
| Kind | query, on platform.book.query.read-agent-orders-demo-only |
| Role | oms, ems, portfolio, compliance |
| Served by | the book |
Takes nothing. Returns agent_orders_demo_only: true when the book
refuses a placement, or an accept of fills to a new order, made through a
delegation or by a service account on a connection that is not demo,
REFUSAL_REASON_AGENT_LIVE_ORDER. It is true in every deployment of this
release. A plugin reads it so it can tell a person before sending;
Caller.agent_refused(connectivity_instance_id, guard_on=...) says the
same of a caller and a connection.
run_job¶
Asks the analytics component for a job, answered inline or later. See A job.
| gRPC | rpc RunJob(RunJobParams) returns (RunJobResult) |
| Workflow step | W12.1, Run a job |
| Kind | query, on platform.analytics.query.run-job |
| Role | reporting, portfolio, compliance, signal |
| Served by | the analytics component |
job is a Job, best built with meridian.analytics.job(...):
| Field | Meaning |
|---|---|
account_ids |
The accounts it is over, one or more, even for a job asking only implied_distribution; each in the plugin's read scope, all read at one watermark. One outside it raises NotGranted, naming job.account_ids[n] |
inputs |
The book's watermark (book_at), the lake's as-of (lake_as_of_ns) and the source choice (sources), one for the whole job; unset, now and the deployment's source priority |
measures |
Each a MeasureRef: a definition and version the component serves, its breakdowns, and for resolution_payoff and implied_distribution its event_group_id |
what_if |
Optionally, trades added to one of the job's accounts (account_id, trades: each an instrument, a side, a quantity and an assumed price or none), answered beside the base |
standing |
True for a standing job, its inputs live, each measure naming its refresh (per_change, or cadence with cadence_ns and material_move_bp). A watermark, as-of, business date or what-if beside it is refused naming standing; a measure with no refresh where its definition states none, naming its refresh; one past the coordinator's analytics.standing.most, naming standing. Added in SDK 0.36.0 |
A job the component cannot answer at all is refused invalid, naming the
field under job.: no account, no measure, a definition or version not
served (job.measures[0].version), an event measure naming no group or
another measure naming one, a what-if over an account the job is not
over, or a what-if trade with no instrument, quantity or side. A breakdown
by a scheme the deployment does not hold is not refused: it is answered
not evaluated. Returns RunJobResult: answered_inline; the job_id,
JOB- and a ULID; and, when answered inline, the answer: its figures,
each a Figure (its measure, account, breakdown, scenario_key, value
or a weight's numerator and denominator, currency_instrument_id and
computed_as); what was not_evaluated and why, each a NotEvaluated
naming its account, instrument, measure, NotEvaluatedReason and detail,
never answered as zero; and its provenance, the inputs by reference, the
implementations and versions, and the answer_hash. A job not answered
within the request's window is answered later: see
list_finished_jobs.
list_measure_definitions¶
Reads the measure definitions the component serves.
| gRPC | rpc ListMeasureDefinitions(ListMeasureDefinitionsParams) returns (ListMeasureDefinitionsResult) |
| Workflow step | W12.1, Run a job |
| Kind | query, on platform.analytics.query.list-measure-definitions |
| Role | reporting, portfolio, compliance, signal |
| Served by | the analytics component |
Takes nothing. Returns definitions, each a MeasureDefinition: its
definition and version, its parameters fixed by the version (each a
name and its value as written, such as confidence 0.99), the
breakdowns it allows, the scale its values are rounded to, and a
description for people. meridian.analytics.measures_of(...) keys them
by name, so a plugin checks a breakdown is allowed before it asks. See
The measures.
list_price_batches¶
A pricing plugin reads the batches waiting for it after a sequence, as after a restart.
| gRPC | rpc ListPriceBatches(ListPriceBatchesParams) returns (ListPriceBatchesResult) |
| Workflow step | W12.3, Price a batch |
| Kind | query, on platform.analytics.query.list-price-batches |
| Role | pricing |
| Served by | the analytics component |
Returns ListPriceBatchesResult: batches, only the asking
instance's, each a PriceBatchRequest as price_batch delivered it (its
batch_id, model_id and model_version, its units, each a
PricingUnit: an instrument and its template version, a scenario_key
and the market objects it is priced from, its deadline_ns, batch_hash
and sequence); and the sequence read to. See
What a batch carries.
answer_price_batch¶
A pricing plugin answers a batch whole.
async def answer_price_batch(
self, *, batch_id: str = "", values: Sequence[PricedUnit] = (),
sensitivities: Sequence[Sensitivity] = (), acting_for: str | None = None,
) -> AnswerPriceBatchResult
| gRPC | rpc AnswerPriceBatch(AnswerPriceBatchParams) returns (AnswerPriceBatchResult) |
| Workflow step | W12.3, Price a batch |
| Kind | command, on platform.analytics.command.answer-price-batch |
| Role | pricing |
| Served by | the analytics component |
| Parameter | Meaning |
|---|---|
batch_id |
The batch answered. One not waiting for this instance is refused invalid, naming it |
values |
One PricedUnit per unit the batch named: its instrument_id, its scenario_key, and its value_per_unit, a Money in the base currency the unit's inputs convert to |
sensitivities |
None: no model in this release declares one |
Returns the batch_id. A batch answered twice is harmless, and an
answer after the batch's deadline is not taken: the figures through it are
then not evaluated, IMPLEMENTATION_UNAVAILABLE.
list_finished_jobs¶
The jobs the asking instance ran that finished later, after a sequence.
| gRPC | rpc ListFinishedJobs(ListFinishedJobsParams) returns (ListFinishedJobsResult) |
| Workflow step | W12.4, Finish a job later, and read its answer |
| Kind | query, on platform.analytics.query.list-finished-jobs |
| Role | reporting, portfolio, compliance, signal |
| Served by | the analytics component |
Returns ListFinishedJobsResult: finished, each a
JobFinishedEvent as job_finished delivered it (job_id,
answer_hash, finished_at_ns, sequence), and the sequence read to.
meridian.analytics.Jobs catches up with it after a gap.
read_job_answer¶
The answer to a job the asking instance ran, by its ID.
| gRPC | rpc ReadJobAnswer(ReadJobAnswerParams) returns (ReadJobAnswerResult) |
| Workflow step | W12.4, Finish a job later, and read its answer |
| Kind | query, on platform.analytics.query.read-job-answer |
| Role | reporting, portfolio, compliance, signal |
| Served by | the analytics component |
Returns the answer as run_job returns it inline: figures,
not_evaluated and provenance, and, for a standing job, its values. Another instance's job raises
NotGranted, naming job_id. A job still running, or one whose answer
has left the component's memory, is a CallFailed of kind
"handler error" saying so: run the job again, and its answer hash says
whether the figures are the same.
RFQ quotes, execution costs, rates, liveness and latency¶
Added in SDK 0.32.0. Every one is preview. They serve
placements and RFQ quotes,
execution costs,
the lake's rates and
data liveness. The Python SDK wraps
most of them: meridian.roles.data.rates records and reads rates,
Wants.liveness records a dataset's liveness, roles.Latency records
latency, roles.ems.open_quotes orders an RFQ placement's quotes, and a
connectivity plugin's Trader reports its venue's quotes. Two events come
with them, heard through their role classes' on_<event> methods:
rates_recorded (reporting, portfolio, compliance, signal) and
liveness_recorded (those four and the ems).
These also change operations listed above:
propose_order takes a net order's members and a value
date, set_working_condition a hold's cause,
create_placement the placement type, a manual
placement's trade details and a stale reference,
report_execution an internal cross's rate source,
report_venue_catalogue the placement types a
venue takes, report_event_group a range member's
bounds, list_datasets each dataset's delay, ceiling
and liveness, read_calendar a calendar's trading
sessions and query_lake the kind rates;
list_prices is read by operations too, and
set_allocation_instruction is sent by the
oms too.
record_rates¶
A data plugin records a batch of rates: fixings, averages, index levels and a curve's points. See Rates.
async def record_rates(
self, *, rates: Sequence[Rate] = (), want_id: str = "", acting_for: str | None = None,
) -> RecordRatesResult
| gRPC | rpc RecordRates(RecordRatesParams) returns (RecordRatesResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-rates |
| Role | data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
rates |
1 to 500 Rates, each the SDK's frozen dataclass: its meta (the row key, its subject, a referential INS- record, its dataset, its valid times and business date, its published source time where the publisher states it, and its raw record); its kind (fixing, average, index_level, par_yield, zero, discount or coupon_equivalent); its value, a UnitValue (a decimal with its unit: percent, basis_points, index with its index_base, and the rest of the closed list, or a UCUM code); its convention (day_count and compounding, with periods_per_year where compounded); its tenor for a curve's point, or an exact maturity_date; whether it is preliminary; and where published, its volume, transaction_count and percentiles |
want_id |
The want it answers, where it answers one |
acting_for |
As above |
Returns RecordRatesResult, as record_prices
answers: recorded, restated, unchanged and the dataset's
watermark; a version whose only change is its raw reference is a
confirmation, counted unchanged. A rate with no kind, unit or convention, with no value, or a
curve's point naming neither a tenor nor a maturity is refused invalid,
naming rates[i] and the field. A publisher's revision is the next
version of its row key, ordered by its published time. Heard as
rates_recorded, conflated: the latest per subject, dataset, kind, tenor,
maturity and convention.
list_rates¶
Reads rates, point in time, as list_prices reads prices,
and as the source had published them by a moment.
async def list_rates(
self, *, subjects: Sequence[SubjectRef] = (), kinds: Sequence[RateKind | str] = (),
tenors: Sequence[Tenor] = (), sources: SourceChoice | None = None, at_ns: int = 0,
business_date: date | str = "", valid_from_ns: int = 0, valid_until_ns: int = 0,
as_of_ns: int = 0, published_as_of_ns: int = 0, page_size: int = 0, cursor: str = "",
) -> ListRatesResult
| gRPC | rpc ListRates(ListRatesParams) returns (ListRatesResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-rates |
| Role | reporting, portfolio, compliance, signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
subjects |
1 to 500 referential records |
kinds, tenors |
Narrow the read to these kinds and tenors; none reads every one |
sources |
A SourceChoice; none set is the deployment's source priority for rates |
at_ns, business_date, valid_from_ns, valid_until_ns |
One of: the latest in force at a valid time, a business date (a curve for a date is its subject's rows on that date, one a tenor), or a range of valid times |
as_of_ns |
The recorded-time cut-off; 0 for now. The audit answer |
published_as_of_ns |
Optionally, what the source had published by this moment, among the rows recorded by the cut-off, so a backfill recorded today still answers for an earlier date |
page_size, cursor |
Up to 500 a page; the next_cursor of the page before |
Returns ListRatesResult: rates; unanswered, each an
Unanswered; datasets; the watermark; and
next_cursor. A tenor the source did not publish is no row, read as
source silent, never zero. meridian.roles.data.rates.read_curve reads
every page of a curve for a date, in tenor order.
record_liveness¶
A data plugin records its datasets' signs of life: a stream's heartbeat or a poll that found nothing changed, which confirms every value in force. See Data age and liveness.
async def record_liveness(
self, *, liveness: Sequence[DatasetLiveness] = (), acting_for: str | None = None,
) -> RecordLivenessResult
| gRPC | rpc RecordLiveness(RecordLivenessParams) returns (RecordLivenessResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-liveness |
| Role | data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
liveness |
1 to 500 DatasetLiveness items, each a dataset the plugin's catalogue declares, the venue_id where it has one (empty for its consolidated view), and alive_at_ns, the source's last heartbeat or poll |
acting_for |
As above |
Returns RecordLivenessResult: kept, how many were later than the
one the lake holds. Liveness is never a row: the lake keeps the latest per
dataset and venue, answers it on the dataset's DatasetRef.liveness, and
delivers it as liveness_recorded. A dataset the plugin does not declare
is refused, naming it. Wants.liveness(key) sends one.
report_latency¶
A data, connectivity or ems plugin's latency: its sessions' histograms
and its hops' data age, every 10 seconds.
Core's latency monitor receives it, and from SDK
0.33.0 roles.Latency.report() sends it; in SDK 0.32 it sent nothing. A deployment before chart 0.1.313 serves no report_latency. See
Data age and liveness.
async def report_latency(
self, *, snapshots: Sequence[LatencySnapshot] = (), acting_for: str | None = None,
) -> ReportLatencyResult
| gRPC | rpc ReportLatency(ReportLatencyParams) returns (ReportLatencyResult) |
| Workflow step | W4.16, Report a session's latency and a hop's data age |
| Kind | command, on platform.deployment.command.report-latency |
| Role | data, connectivity, ems |
| Served by | core's latency monitor, in the dashboard, |
| Parameter | Meaning |
|---|---|
snapshots |
1 to 500 LatencySnapshots, each one session's or one hop's histograms over the interval, its counters and the ceilings in force |
acting_for |
As above |
Returns ReportLatencyResult. A snapshot naming neither a session nor
a dataset, or both, or whose buckets do not sum to its total, refuses the
call whole, naming the snapshot. Measurements, not records: nothing is
journalled.
report_placement_quote¶
A connectivity plugin records a dealer's quote received on the firm's RFQ placement, and moves it on as the venue reports what became of it. See RFQ placements.
async def report_placement_quote(
self, *, placement_id: str = "", quote_id: str = "", dealer_id: str = "",
dealer_quote_id: str = "", side: Side | str | None = None, price: Money | None = None,
quantity: Decimal | int | None = None, received_at_ns: int = 0, valid_until_ns: int = 0,
outcome: PlacementQuoteOutcome | str | None = None, raw_record: RawRecordRef | None = None,
idempotency_key: str = "", acting_for: str | None = None,
) -> ReportPlacementQuoteResult
| gRPC | rpc ReportPlacementQuote(ReportPlacementQuoteParams) returns (ReportPlacementQuoteResult) |
| Workflow step | W11.40, Record a quote received on an RFQ placement |
| Kind | command, on platform.book.command.report-placement-quote |
| Role | connectivity |
| Served by | the book |
| Parameter | Meaning |
|---|---|
placement_id |
The RFQ placement, one naming this instance |
quote_id |
Empty for a new quote, which the book mints PQT-; the quote's ID to record a later outcome |
dealer_id, dealer_quote_id |
The dealer, by its VEN- ID, and its QuoteID as delivered |
side, price, quantity |
The dealer's side, its price, a Money, and its quantity |
received_at_ns, valid_until_ns |
When it was received, and until when it stands (0 when unstated) |
outcome |
open, picked, accepted, expired, withdrawn or not_picked |
raw_record, idempotency_key, acting_for |
As above |
Returns the placement, carrying its quotes, each a
PlacementQuote. A placement that is not RFQ or not this instance's, or an
outcome moving backwards, is refused REFUSAL_REASON_ORDER_STATE; a quote
missing its dealer, side or price is refused invalid, naming the field;
one on a placement outside the plugin's scope PERMISSION_DENIED.
pick_placement_quote¶
The ems picks one open quote on an RFQ placement it made, for a person
or as its service account. The pick need not be the best quote.
async def pick_placement_quote(
self, *, placement_id: str = "", quote_id: str = "", reason: str = "",
idempotency_key: str = "", acting_for: str | None = None,
) -> PickPlacementQuoteResult
| gRPC | rpc PickPlacementQuote(PickPlacementQuoteParams) returns (PickPlacementQuoteResult) |
| Workflow step | W11.41, Pick a quote received on an RFQ placement |
| Kind | command, on platform.book.command.pick-placement-quote |
| Role | ems |
| Served by | the book |
| Parameter | Meaning |
|---|---|
placement_id, quote_id |
The placement and the quote picked |
reason |
Why, where the firm's policy asks one |
idempotency_key, acting_for |
As above |
Returns the placement, its picked_quote_id naming the quote, which
its connectivity plugin hears and accepts at the venue. A quote not open
or past its valid-until time, or a second pick while one stands, is
refused REFUSAL_REASON_ORDER_STATE; another ems's placement
PERMISSION_DENIED. The agents' guard
applies as to a placement: an agent's pick is demo only where every
connection the caller may route through is demo, and is otherwise refused
REFUSAL_REASON_AGENT_LIVE_ORDER, and recorded.
list_execution_costs¶
Reads one account's execution costs, the rows the analytics component records. See Execution costs.
async def list_execution_costs(
self, *, account_id: str = "", execution_ids: Sequence[str] = (), order_id: str = "",
trade_date: date | str = "", benchmarks: Sequence[TcaBenchmark | str] = (),
as_of_ns: int = 0, page_size: int = 0, cursor: str = "",
) -> ListExecutionCostsResult
| gRPC | rpc ListExecutionCosts(ListExecutionCostsParams) returns (ListExecutionCostsResult) |
| Workflow step | W10.11, Record and read execution costs |
| Kind | query, on platform.lake.query.list-execution-costs |
| Role | reporting, portfolio, compliance, signal, oms, ems, operations |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
account_id |
The account, required: an account outside the plugin's read scope is refused PERMISSION_DENIED, naming account_id |
execution_ids, order_id, trade_date |
By execution, by order, or by trade date |
benchmarks |
Narrow to these benchmarks: decision, arrival, placement_arrival, mid_at_fill, interval_vwap, fix |
as_of_ns |
The recorded-time cut-off; 0 for now |
page_size, cursor |
Up to 500 a page; the next_cursor of the page before |
Returns ListExecutionCostsResult: costs, each an ExecutionCost,
and next_cursor. The lake's first account-scoped row: a reader reads
only the accounts its read scope holds. What each row says is in
Execution costs.
Listed options and futures, companies, derived series and scenarios¶
Added in SDK 0.33.0. Every one is preview. They serve
listed options and futures
(a chain's series and statistics, a series asked for, and the lifecycle
events in the book), companies and corporate actions,
a signal's derived series and
saved scenarios, and an ems's read of the
stale-reference actions permitted.
Ten more are the filings slice and quality states (see
The lake: filings, quality states and data use).
The Python SDK wraps them in meridian.helpers.chains, .lifecycle and
.packages, and meridian.roles.signal, .data.filings and .data.quality (see
Helpers). Four events
come with them, heard through their role classes' on_<event> methods:
statistics_recorded (portfolio, reporting, signal),
corporate_actions_recorded and filings_recorded (reporting,
signal) and lifecycle_event_recorded (operations, servicing,
portfolio, reporting).
SubjectRef carries its role. A row's subject
may name its role (subject, holder, held, issuer,
reporting_owner, filer, underlying, rater), and a read naming a
subject in a role answers only rows naming it so. From SDK 0.33.0 every
typed operation takes meridian.SubjectRef, the SDK's own, and refuses the
wire's.
These also change operations listed above:
propose_order takes a package's legs with their
position_effect, and an order's own; report_execution
a package's fill and each leg's, linked (multi_leg_reporting_type,
package_execution_id); record_trades a trade's
quote_at_trade; list_trades and
list_quotes a chain's rows, only when asked for by
series_keys or all_series; every row's envelope its series_key, and
its quality and quality_reasons (not yet acted on by core); a
SourceChoice include_quarantined (likewise); run_job a
job's chains, scenario_set and scenario_ref, and a figure's
series_key; list_templates and
read_template each field's requirement and
repeated, a package's model_bindings, and a version's withdrawn and
successor_version; resolve_instrument a listed
series' terms (InstrumentRecord.listed_option, .future); and a data
plugin's catalogue licence its eligibility.
record_series¶
A data plugin records an underlying's listed series, each as its template's fields. Recording a series mints nothing. See The chain.
async def record_series(
self, *, series: Sequence[ListedSeries] = (), want_id: str = "",
acting_for: str | None = None,
) -> RecordSeriesResult
| gRPC | rpc RecordSeries(RecordSeriesParams) returns (RecordSeriesResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-series |
| Role | data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
series |
1 to 500 ListedSeries: each its meta, the underlying as its subject and the series' key (series_key: occ_osi and the OSI symbol, or one ticker with its venue's MIC in source); its template_id and template_version, the listed_option, future or future_option template's; and its fields, each by its template path. instrument_id is the lake's to fill on a read, never a writer's |
want_id, acting_for |
As above |
Returns RecordSeriesResult, as record_prices answers: recorded, restated, unchanged and the dataset's watermark. A row missing what it requires is refused invalid, naming series[i] and the field, and the batch is recorded whole or not at all. An adjustment is the next version of the series' row key. A series is never published as an event.
list_series¶
Reads an underlying's listed series at the as-of, narrowed by type, expiration window and key, each with the deployment's INS- record where one is held, matched read-only and never minted.
async def list_series(
self, *, subjects: Sequence[SubjectRef] = (),
instrument_type: InstrumentType | str | None = None, expiration_from: date | str = "",
expiration_to: date | str = "", series_keys: Sequence[Identifier] = (),
sources: SourceChoice | None = None, as_of_ns: int = 0, page_size: int = 0,
cursor: str = "",
) -> ListSeriesResult
| gRPC | rpc ListSeries(ListSeriesParams) returns (ListSeriesResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-series |
| Role | ems, oms, portfolio, signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
subjects |
1 to 64 underlyings, each its INS- record |
instrument_type |
listed_option, future or future_option; unset for every listed type |
expiration_from, expiration_to |
Plain dates; empty for no bound |
series_keys |
Up to 500 series' keys, each answered where it is listed under the subjects asked |
sources |
A SourceChoice; none set is the deployment's source priority |
as_of_ns |
The recorded-time cut-off; 0 for now |
page_size, cursor |
Up to 500 a page, 100 when 0; the next_cursor of the page before |
Returns ListSeriesResult: series, the rows, each naming its dataset; unanswered, each an Unanswered; datasets; the watermark; and next_cursor. Each page is filled after the type and the window are applied. meridian.helpers.chains.read_chain reads every page.
record_statistics¶
A data plugin records a count for a trading date: a series' open interest, volume or block volume, or a share's short and total volume reported to a FINRA facility.
async def record_statistics(
self, *, statistics: Sequence[Statistic] = (), want_id: str = "",
acting_for: str | None = None,
) -> RecordStatisticsResult
| gRPC | rpc RecordStatistics(RecordStatisticsParams) returns (RecordStatisticsResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-statistics |
| Role | data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
statistics |
1 to 500 Statistics: each its meta (its subject, the contract's record or the underlying with the series' key, and its business_date, the trading date it is for, required), its kind (open_interest, volume, block_volume, short_volume, total_volume) and its value, a UnitValue in contracts or shares, never negative |
want_id, acting_for |
As above |
Returns RecordStatisticsResult, as record_prices answers: recorded, restated, unchanged and the dataset's watermark. A row missing what it requires is refused invalid, naming statistics[i] and the field, and the batch is recorded whole or not at all. Heard as statistics_recorded by portfolio, reporting and signal, conflated per subject, series key, kind and date.
list_statistics¶
Reads statistics by kind, for a trading date or a range, an underlying's own or its chain's.
async def list_statistics(
self, *, subjects: Sequence[SubjectRef] = (), kinds: Sequence[StatisticKind | str] = (),
business_date: date | str = "", from_date: date | str = "", to_date: date | str = "",
series_keys: Sequence[Identifier] = (), all_series: bool = False,
sources: SourceChoice | None = None, as_of_ns: int = 0, page_size: int = 0,
cursor: str = "",
) -> ListStatisticsResult
| gRPC | rpc ListStatistics(ListStatisticsParams) returns (ListStatisticsResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-statistics |
| Role | portfolio, reporting, signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
subjects |
1 to 64 INS- records; with series_keys or all_series, an underlying's chain |
kinds |
Narrow to these kinds; none reads every one |
business_date, or from_date and to_date |
One trading date, the latest each subject has where none is named; or a range, refused beside business_date |
series_keys, all_series |
Rows keyed by these series, or by any series of the underlying; neither leaves every series' rows out, so a reader of an underlying never receives its chain |
sources |
A SourceChoice; none set is the deployment's source priority |
as_of_ns |
The recorded-time cut-off; 0 for now |
page_size, cursor |
Up to 500 a page, 100 when 0; the next_cursor of the page before |
Returns ListStatisticsResult: statistics, the rows, each naming its dataset; unanswered, each an Unanswered; datasets; the watermark; and next_cursor. meridian.helpers.chains.read_open_interest reads a chain's open interest for a date.
request_series_records¶
Asks for the INS- record of a listed series the deployment does not hold, when an order or a standing want needs it, under the deployment's series request rule. See A series gets its record when it is wanted.
async def request_series_records(
self, *, series: Sequence[SeriesWant] = (), note: str = "", acting_for: str | None = None,
) -> RequestSeriesRecordsResult
| gRPC | rpc RequestSeriesRecords(RequestSeriesRecordsParams) returns (RequestSeriesRecordsResult) |
| Workflow step | W3.31, Ask for a listed series' record when it is wanted |
| Kind | command, on platform.reference.command.request-series-records |
| Role | ems, oms, portfolio, signal |
| Served by | the instrument store |
| Parameter | Meaning |
|---|---|
series |
1 to 500 SeriesWants: each its series_key, its underlying_instrument_id (the INS- record its chain rows name) and its cause, order or standing |
note |
Why, kept on the request's record; required when sent for a person |
acting_for |
As above |
Returns RequestSeriesRecordsResult: answers, one per series asked, in order, each its series_key and its instrument_id where held, matched or minted; pending_review where it is reviewed first, asked again daily; or refused_by_rule where the rule does not allow its cause or the day's limit is reached, nothing sent. A key no chain row holds is refused invalid, naming series[n].series_key. Each request the rule refuses is its own record. meridian.helpers.chains.want_series asks for one.
record_lifecycle_event¶
A custody or connectivity plugin books a listed option's or a future's lifecycle event as its broker reports it: an exercise, an assignment, an expiry or a day's settlement variation. See Lifecycle events in the book.
async def record_lifecycle_event(
self, *, event: LifecycleEvent | None = None, idempotency_key: str = "",
acting_for: str | None = None,
) -> RecordLifecycleEventResult
| gRPC | rpc RecordLifecycleEvent(RecordLifecycleEventParams) returns (RecordLifecycleEventResult) |
| Workflow step | W9.16, Book a listed option's or a future's lifecycle event as the broker reports it |
| Kind | command, on platform.book.command.record-lifecycle-event |
| Role | connectivity, custody |
| Served by | the book |
| Parameter | Meaning |
|---|---|
event |
A LifecycleEvent: its account_id; its instrument_id, a listed_option, future_option or future record; its kind (exercise, assignment, expiry, settlement_variation); its quantity, the contracts, or on a variation those held at the settlement; its event_date; its deliveries, each an instrument, a signed quantity (positive received) and its price; its cash, signed, positive received; its settlement_price for a variation or a cash settlement; its external_event_id as the broker states it; and its raw_record |
idempotency_key, acting_for |
As above |
Returns RecordLifecycleEventResult: the event, its LCE- event_id, its state and the proposal it answered where it matched one. A report sent twice is answered with the first. Refused naming the field: an instrument that is no listed option or future, an exercise, assignment or expiry on a future, a variation on an option, more contracts than held, a variation with no settlement price or cash. Heard as lifecycle_event_recorded. meridian.helpers.lifecycle.report sends one.
propose_lifecycle_events¶
servicing proposes the lifecycle events it expects, such as an exercise by exception at expiration. A proposal moves nothing.
async def propose_lifecycle_events(
self, *, events: Sequence[LifecycleEvent] = (), acting_for: str | None = None,
) -> ProposeLifecycleEventsResult
| gRPC | rpc ProposeLifecycleEvents(ProposeLifecycleEventsParams) returns (ProposeLifecycleEventsResult) |
| Workflow step | W9.17, Propose the lifecycle events expected |
| Kind | command, on platform.book.command.propose-lifecycle-events |
| Role | servicing |
| Served by | the book |
| Parameter | Meaning |
|---|---|
events |
1 to 500 LifecycleEvents, each in its account, as record_lifecycle_event takes them, with its proposal_basis (the underlying's close, or the settlement price) |
acting_for |
As above |
Returns ProposeLifecycleEventsResult: events, one per event proposed, in order, each its event_id and state proposed. A report matching one by account, instrument, kind and date answers it, and it is never booked as well. meridian.helpers.lifecycle.propose sends them.
release_lifecycle_event¶
operations releases a proposed lifecycle event no report answered, and the book books it as proposed.
async def release_lifecycle_event(
self, *, event_id: str = "", note: str = "", acting_for: str | None = None,
) -> ReleaseLifecycleEventResult
| gRPC | rpc ReleaseLifecycleEvent(ReleaseLifecycleEventParams) returns (ReleaseLifecycleEventResult) |
| Workflow step | W9.18, Release a proposed lifecycle event no report came for |
| Kind | command, on platform.book.command.release-lifecycle-event |
| Role | operations |
| Served by | the book |
| Parameter | Meaning |
|---|---|
event_id |
The proposal, among the sender's accounts |
note |
Why, 1 to 2,000 characters, kept on the release's entry; none is refused REFUSAL_REASON_REASON_REQUIRED |
acting_for |
As above |
Returns ReleaseLifecycleEventResult: the event, booked. meridian.helpers.lifecycle.due_for_release says when one may be released.
list_lifecycle_events¶
Reads an account's lifecycle events, in the account's sequence.
async def list_lifecycle_events(
self, *, account_id: str = "", instrument_id: str = "",
kinds: Sequence[LifecycleEventKind | str] = (), from_date: date | str = "",
to_date: date | str = "", since: Watermark | None = None, page_size: int = 0,
cursor: str = "",
) -> ListLifecycleEventsResult
| gRPC | rpc ListLifecycleEvents(ListLifecycleEventsParams) returns (ListLifecycleEventsResult) |
| Workflow step | W9.19, Read lifecycle events, and hear each |
| Kind | query, on platform.book.query.list-lifecycle-events |
| Role | operations, portfolio, reporting, servicing |
| Served by | the book |
| Parameter | Meaning |
|---|---|
account_id |
An account in the reader's scope |
instrument_id, kinds |
Narrow to one instrument and to these kinds |
from_date, to_date |
Plain dates on event_date; empty from the account's opening balance and to today |
since |
A watermark: events whose last change is after it |
page_size, cursor |
Up to 500 a page, 100 when 0; the next_cursor of the page before |
Returns ListLifecycleEventsResult: events, each with its state; as_of, the head of each partition the read saw; and next_cursor. meridian.helpers.lifecycle.read_events reads every page.
resolve_company¶
A data plugin resolves a company to its ENT- record: by its ID, or by a CIK or an LEI as of a date. A miss by identifiers asks the platform. See Companies and corporate actions.
async def resolve_company(
self, *, company_id: str = "", identifiers: Sequence[Identifier] = (), as_of_ns: int = 0,
) -> ResolveCompanyResult
| gRPC | rpc ResolveCompany(ResolveCompanyParams) returns (ResolveCompanyResult) |
| Workflow step | W3.32, Resolve a company, asking the platform on a miss |
| Kind | query, on platform.reference.query.resolve-company |
| Role | data |
| Served by | the instrument store |
| Parameter | Meaning |
|---|---|
company_id |
Its ENT- ID; empty where identifiers name it |
identifiers |
Up to 4: a cik or an lei, against each identifier's validity window |
as_of_ns |
The moment the identifiers are read at; 0 for now |
Returns ResolveCompanyResult: the company_id, its current name, its identifiers with their windows, its former_names and its version. Two companies named at once are refused. A company the platform queues for its staff, or a platform not reached, leaves a miss refused naming identifiers, nothing kept. meridian.roles.data.filings.Companies resolves a filer once.
record_corporate_actions¶
A data plugin records a company's declared corporate actions; in chart 0.1.313, a cash dividend. See Corporate actions.
async def record_corporate_actions(
self, *, actions: Sequence[CorporateActionAnnounced] = (), want_id: str = "",
acting_for: str | None = None,
) -> RecordCorporateActionsResult
| gRPC | rpc RecordCorporateActions(RecordCorporateActionsParams) returns (RecordCorporateActionsResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-corporate-actions |
| Role | data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
actions |
1 to 500 CorporateActionAnnounced rows: each its meta, the security as a subject and its issuer as a company in the issuer role; its kind, cash_dividend; its amount_per_share, a Money; its declared_date, ex_date, record_date and payment_date, each required, a plain date; its rule; and its filing where given |
want_id, acting_for |
As above |
Returns RecordCorporateActionsResult, as record_prices answers: recorded, restated, unchanged and the dataset's watermark. A row missing what it requires is refused invalid, naming actions[i] and the field, and the batch is recorded whole or not at all. A correction is the next version of its row key. Heard as corporate_actions_recorded, every version, never conflated.
list_corporate_actions¶
Reads corporate actions by subject, kind and a range of the kind's date (a cash dividend's ex-date), point in time; or every version recorded after a watermark.
async def list_corporate_actions(
self, *, subjects: Sequence[SubjectRef] = (), from_date: date | str = "",
to_date: date | str = "", kinds: Sequence[CorporateActionKind | str] = (),
published_as_of_ns: int = 0, sources: SourceChoice | None = None, as_of_ns: int = 0,
page_size: int = 0, cursor: str = "", after_watermark: Watermark | None = None,
) -> ListCorporateActionsResult
| gRPC | rpc ListCorporateActions(ListCorporateActionsParams) returns (ListCorporateActionsResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-corporate-actions |
| Role | portfolio, reporting, signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
subjects |
1 to 64 companies or instruments, each with the role it must hold on the row where given |
from_date, to_date, kinds |
A range of the kind's date, and the kinds; none reads every one |
published_as_of_ns |
The version in force by published time, among rows recorded by the cut-off |
after_watermark |
Every version each dataset recorded after the watermark the reader last saw, whatever its dates |
sources |
A SourceChoice; none set is the deployment's source priority |
as_of_ns |
The recorded-time cut-off; 0 for now |
page_size, cursor |
Up to 500 a page, 100 when 0; the next_cursor of the page before |
Returns ListCorporateActionsResult: actions, the rows, each naming its dataset; unanswered, each an Unanswered; datasets; the watermark; and next_cursor.
record_derived_series¶
A signal plugin records what it computed from the lake into its own derived dataset. See Derived series.
async def record_derived_series(
self, *, values: Sequence[DerivedSeries] = (), acting_for: str | None = None,
) -> RecordDerivedSeriesResult
| gRPC | rpc RecordDerivedSeries(RecordDerivedSeriesParams) returns (RecordDerivedSeriesResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-derived-series |
| Role | signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
values |
1 to 500 DerivedSeries: each its meta (its subject, its own dataset and its business_date, required), its series name, its value, a UnitValue, its rule (a meridian.MeasureRef, a definition and version) and its inputs, each dataset read with the as-of it read at |
acting_for |
As above |
Returns RecordDerivedSeriesResult, as record_prices answers: recorded, restated, unchanged and the dataset's watermark. A row missing what it requires is refused invalid, naming values[i] and the field, and the batch is recorded whole or not at all. Its latest per series is kept. Never published as an event. meridian.roles.signal.derived builds one.
list_derived_series¶
Reads derived series by subject and name, over a range of business dates, every readable derived dataset side by side.
async def list_derived_series(
self, *, subjects: Sequence[SubjectRef] = (), series: Sequence[str] = (),
from_date: date | str = "", to_date: date | str = "",
) -> ListDerivedSeriesResult
| gRPC | rpc ListDerivedSeries(ListDerivedSeriesParams) returns (ListDerivedSeriesResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-derived-series |
| Role | compliance, portfolio, reporting, signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
subjects |
1 to 64 INS- records |
series |
The series' names; none reads every one |
from_date, to_date |
Plain dates; empty for no bound |
Returns ListDerivedSeriesResult: values, each naming its rule and inputs. meridian.roles.signal.read_derived reads them.
record_scenarios¶
A signal plugin saves a scenario, or a scenario set's axes, as a row of its own dataset under its row key. See Scenarios.
async def record_scenarios(
self, *, scenarios: Sequence[SavedScenario] = (), acting_for: str | None = None,
) -> RecordScenariosResult
| gRPC | rpc RecordScenarios(RecordScenariosParams) returns (RecordScenariosResult) |
| Workflow step | W12.8, Save a scenario or a scenario set |
| Kind | command, on platform.lake.command.record-scenarios |
| Role | signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
scenarios |
1 to 50 SavedScenarios: each its meta (its row key, its own dataset, no subjects), and one scenario or one scenario_set (1 to 4 axes of 1 to 32 steps), with its description |
acting_for |
As above |
Returns RecordScenariosResult, as record_prices answers: recorded, restated, unchanged and the dataset's watermark. A row missing what it requires is refused invalid, naming scenarios[i] and the field, and the batch is recorded whole or not at all. Saving a row key again is its next version. A shock whose form does not fit its object, with no unit, or naming both a subject and every, is refused naming it.
list_scenarios¶
Reads saved scenarios by row key, each at its latest or the version asked.
async def list_scenarios(
self, *, row_keys: Sequence[str] = (), version: int = 0,
) -> ListScenariosResult
| gRPC | rpc ListScenarios(ListScenariosParams) returns (ListScenariosResult) |
| Workflow step | W12.8, Save a scenario or a scenario set |
| Kind | query, on platform.lake.query.list-scenarios |
| Role | compliance, portfolio, reporting, signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
row_keys |
Their row keys; none reads every saved scenario |
version |
With one row key, that version; 0 for the latest |
Returns ListScenariosResult: scenarios, each at the version asked. A job names one by its row key and version (Job.scenario_ref).
read_stale_reference_actions_permitted¶
An ems reads whether the deployment permits Warn beside Refuse for a stale reference price, at its own role, with no person. See What a deployment admin permits.
| gRPC | rpc ReadStaleReferenceActionsPermitted(ReadStaleReferenceActionsPermittedParams) returns (ReadStaleReferenceActionsPermittedResult) |
| Workflow step | W6.38, Set the stale-reference actions the deployment permits |
| Kind | query, on platform.config.query.read-stale-reference-actions-permitted |
| Role | ems |
| Served by | the conductor |
Returns ReadStaleReferenceActionsPermittedResult: warn_permitted (false, refuse only, by default, when a plugin admin's Warn is read as Refuse), and changed_at_ns and changed_by of the last change. meridian.roles.ems.ReferenceCheck.permitted reads it.
record_filings¶
A data plugin records filings: each its filer and the subjects it is about, each in its role, its accession number, form, kind, filing date and items (an 8-K's 2.02 among them).
async def record_filings(
self, *, filings: Sequence[Filing] = (), want_id: str = "", acting_for: str | None = None,
) -> RecordFilingsResult
| gRPC | rpc RecordFilings(RecordFilingsParams) returns (RecordFilingsResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-filings |
| Role | data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
filings |
1 to 500 rows, each with its meta and subjects in their roles |
want_id, acting_for |
As above |
Returns RecordFilingsResult, as record_prices answers: recorded, restated, unchanged and the dataset's watermark. A row missing what it requires is refused invalid, naming filings[i] and the field, and the batch is recorded whole or not at all.
list_filings¶
Reads filings by subject, kind and filing date, point in time, or every version recorded after a watermark.
async def list_filings(
self, *, subjects: Sequence[SubjectRef] = (), from_date: date | str = "",
to_date: date | str = "", kinds: Sequence[FilingKind | str] = (),
published_as_of_ns: int = 0, sources: SourceChoice | None = None, as_of_ns: int = 0,
page_size: int = 0, cursor: str = "", after_watermark: Watermark | None = None,
) -> ListFilingsResult
| gRPC | rpc ListFilings(ListFilingsParams) returns (ListFilingsResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-filings |
| Role | portfolio, reporting, signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
subjects |
1 to 64 companies or instruments, each with the role it must hold on the row where given |
from_date, to_date, kinds |
A range of dates and the kinds; none reads every one |
published_as_of_ns |
The version in force by published time |
after_watermark |
Every version recorded after the watermark the reader last saw |
sources |
A SourceChoice; none set is the deployment's source priority |
as_of_ns |
The recorded-time cut-off; 0 for now |
page_size, cursor |
Up to 500 a page, 100 when 0; the next_cursor of the page before |
Returns ListFilingsResult: filings, the rows, each naming its dataset; unanswered, each an Unanswered; datasets; the watermark; and next_cursor.
record_reported_facts¶
A data plugin records the facts a filing reports, each a concept, its period and its value, a restatement the next version of its row key.
async def record_reported_facts(
self, *, facts: Sequence[ReportedFact] = (), want_id: str = "",
acting_for: str | None = None,
) -> RecordReportedFactsResult
| gRPC | rpc RecordReportedFacts(RecordReportedFactsParams) returns (RecordReportedFactsResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-reported-facts |
| Role | data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
facts |
1 to 500 rows, each with its meta and subjects in their roles |
want_id, acting_for |
As above |
Returns RecordReportedFactsResult, as record_prices answers: recorded, restated, unchanged and the dataset's watermark. A row missing what it requires is refused invalid, naming facts[i] and the field, and the batch is recorded whole or not at all.
list_reported_facts¶
Reads reported facts by subject, concept and period, point in time.
async def list_reported_facts(
self, *, subjects: Sequence[SubjectRef] = (), from_date: date | str = "",
to_date: date | str = "", published_as_of_ns: int = 0, sources: SourceChoice | None = None,
as_of_ns: int = 0, page_size: int = 0, cursor: str = "", concepts: Sequence[str] = (),
) -> ListReportedFactsResult
| gRPC | rpc ListReportedFacts(ListReportedFactsParams) returns (ListReportedFactsResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-reported-facts |
| Role | portfolio, reporting, signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
subjects |
1 to 64 companies or instruments, each with the role it must hold on the row where given |
from_date, to_date |
A range of periods |
concepts |
Each a taxonomy and name; none reads every one |
published_as_of_ns |
The version in force by published time |
sources |
A SourceChoice; none set is the deployment's source priority |
as_of_ns |
The recorded-time cut-off; 0 for now |
page_size, cursor |
Up to 500 a page, 100 when 0; the next_cursor of the page before |
Returns ListReportedFactsResult: facts, the rows, each naming its dataset; unanswered, each an Unanswered; datasets; the watermark; and next_cursor.
record_holdings_reports¶
A data plugin records a holdings report: who reports, the period and its kind.
async def record_holdings_reports(
self, *, reports: Sequence[HoldingsReport] = (), want_id: str = "",
acting_for: str | None = None,
) -> RecordHoldingsReportsResult
| gRPC | rpc RecordHoldingsReports(RecordHoldingsReportsParams) returns (RecordHoldingsReportsResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-holdings-reports |
| Role | data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
reports |
1 to 500 rows, each with its meta and subjects in their roles |
want_id, acting_for |
As above |
Returns RecordHoldingsReportsResult, as record_prices answers: recorded, restated, unchanged and the dataset's watermark. A row missing what it requires is refused invalid, naming reports[i] and the field, and the batch is recorded whole or not at all.
record_holdings¶
A data plugin records each holding a report states: the holder, what is held, its quantity and market value, and its share of the class where stated.
async def record_holdings(
self, *, holdings: Sequence[Holding] = (), want_id: str = "",
acting_for: str | None = None,
) -> RecordHoldingsResult
| gRPC | rpc RecordHoldings(RecordHoldingsParams) returns (RecordHoldingsResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-holdings |
| Role | data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
holdings |
1 to 500 rows, each with its meta and subjects in their roles |
want_id, acting_for |
As above |
Returns RecordHoldingsResult, as record_prices answers: recorded, restated, unchanged and the dataset's watermark. A row missing what it requires is refused invalid, naming holdings[i] and the field, and the batch is recorded whole or not at all.
list_holdings¶
Reads holdings, and the reports they came from, by holder or by what is held.
async def list_holdings(
self, *, subjects: Sequence[SubjectRef] = (), from_date: date | str = "",
to_date: date | str = "", kinds: Sequence[HoldingsReportKind | str] = (),
published_as_of_ns: int = 0, sources: SourceChoice | None = None, as_of_ns: int = 0,
page_size: int = 0, cursor: str = "",
) -> ListHoldingsResult
| gRPC | rpc ListHoldings(ListHoldingsParams) returns (ListHoldingsResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-holdings |
| Role | portfolio, reporting, signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
subjects |
1 to 64 companies or instruments, each with the role it must hold on the row where given |
from_date, to_date, kinds |
A range of dates and the reports' kinds |
published_as_of_ns |
The version in force by published time |
sources |
A SourceChoice; none set is the deployment's source priority |
as_of_ns |
The recorded-time cut-off; 0 for now |
page_size, cursor |
Up to 500 a page, 100 when 0; the next_cursor of the page before |
Returns ListHoldingsResult: holdings, the rows, each naming its dataset; unanswered, each an Unanswered; datasets; the watermark; and next_cursor. Beside them, reports, each report its holdings came from, once.
record_rating_actions¶
A data plugin records a rating action: the rated company or security, the rater in the rater role, the rating, its scale and the action.
async def record_rating_actions(
self, *, actions: Sequence[RatingAction] = (), want_id: str = "",
acting_for: str | None = None,
) -> RecordRatingActionsResult
| gRPC | rpc RecordRatingActions(RecordRatingActionsParams) returns (RecordRatingActionsResult) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-rating-actions |
| Role | data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
actions |
1 to 500 rows, each with its meta and subjects in their roles |
want_id, acting_for |
As above |
Returns RecordRatingActionsResult, as record_prices answers: recorded, restated, unchanged and the dataset's watermark. A row missing what it requires is refused invalid, naming actions[i] and the field, and the batch is recorded whole or not at all.
list_rating_actions¶
Reads a company's or a security's rating history.
async def list_rating_actions(
self, *, subjects: Sequence[SubjectRef] = (), from_date: date | str = "",
to_date: date | str = "", kinds: Sequence[RatingActionKind | str] = (),
published_as_of_ns: int = 0, sources: SourceChoice | None = None, as_of_ns: int = 0,
page_size: int = 0, cursor: str = "",
) -> ListRatingActionsResult
| gRPC | rpc ListRatingActions(ListRatingActionsParams) returns (ListRatingActionsResult) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-rating-actions |
| Role | portfolio, reporting, signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
subjects |
1 to 64 companies or instruments, each with the role it must hold on the row where given |
from_date, to_date, kinds |
A range of dates and the actions' kinds |
published_as_of_ns |
The version in force by published time |
sources |
A SourceChoice; none set is the deployment's source priority |
as_of_ns |
The recorded-time cut-off; 0 for now |
page_size, cursor |
Up to 500 a page, 100 when 0; the next_cursor of the page before |
Returns ListRatingActionsResult: actions, the rows, each naming its dataset; unanswered, each an Unanswered; datasets; the watermark; and next_cursor.
record_quality_assessments¶
A signal plugin escalates a recorded row's quality, each assessment its own record; a state only escalates.
async def record_quality_assessments(
self, *, assessments: Sequence[QualityAssessment] = (), acting_for: str | None = None,
) -> RecordQualityAssessmentsResult
| gRPC | rpc RecordQualityAssessments(RecordQualityAssessmentsParams) returns (RecordQualityAssessmentsResult) |
| Workflow step | W10.12, Escalate a row's quality |
| Kind | command, on platform.lake.command.record-quality-assessments |
| Role | signal |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
assessments |
1 to 500 QualityAssessments, each naming the row, its state (suspicious or invalid) and its reasons |
acting_for |
As above |
Returns RecordQualityAssessmentsResult: recorded. meridian.roles.signal.escalate records them.
Factors and expirations¶
These are bonds and fixed income.
Every operation here is preview. The SDK's
meridian.helpers.debt
wraps the factor's: debt.factor(...) builds a row, debt.read_factors
reads a pool's history every page, and debt.latest takes the version in
force. Two events come with them, each an on_<event> method of the role
classes hearing it: on_factors_recorded (operations, portfolio,
reporting, servicing, signal), every version, never conflated, caught
up by list_factors; and on_series_recorded (ems,
oms, portfolio, signal), a listed series recorded.
These also change operations listed above:
propose_ordertakes a fixed-income limit,price_basiswithlimit_yieldorlimit_spread_bpsand thebenchmark_instrument_ida spread is over; a single option or future order states itsposition_effect.report_executiontakes a fixed-income fill:price_basisandyieldbeside the dollar price per 100 of face, whichpricealways is;factor_used, an override only, for a pool's or a tranche's fill, which otherwise states original face and takes the factor the book finds;settlement_date_unknown;trade_time_precision; and the trade-reporting fieldscontra_party_type,parties,capacity,no_remuneration,affiliate_back_to_back,special_pricewith itsspecial_price_reason,weighted_average_price,primary_market,list_offering_price_takedown,traded_flat,stipulated,portfolio_tradeandtreasury_trade_modifier.Price,TradeandQuotetake aPriceBasisof percent of par, yield or spread (withbenchmark_instrument_id), and a capped size (Trade.quantity_capped,Quote.bid_size_capped).list_trades,list_quotesandlist_statisticstake an expiration window,expiration_fromandexpiration_to, andfields, the dictionary entries a page shows, a field not asked coming back unset;list_seriestakespaths, the template paths a page draws; a want (ObservationsWantedEvent) carriesseries_keys,all_seriesand the expiration window.read_job_answeris read a page at a time,page_sizeandcursor, answeringnext_cursor.record_derived_seriesis held bydataas well assignal.- A quality assessment names its data type, a derived value in money is
money_value,DatasetRefcounts its valid, suspicious and invalid rows, and a quarantined dataset is answeredUNANSWERED_REASON_QUARANTINED, never fallen back from.
record_factors¶
An agency's data plugin records each held pool's or REMIC class's factor as the agency published it, one row per pool or class and factor month, never a whole file.
async def record_factors(
self, *, factors: Sequence[Factor] = (), want_id: str = "",
acting_for: str | None = None,
) -> RecordObservationsReply
| gRPC | rpc RecordFactors(RecordFactorsParams) returns (RecordObservationsReply) |
| Workflow step | W10.4, Record prices, bars, trades and quotes in batches |
| Kind | command, on platform.lake.command.record-factors |
| Role | data |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
factors |
1 to 500 Factor rows, each its meta (the pool's or class's record as its subject, its row key the agency, the pool or deal and class, and the factor month), the factor exactly as published, its factor_month, record_date and payment_date, and where the disclosure states them the pool's wac, wam and wala and a floating class's period coupon_rate |
want_id, acting_for |
As above |
Returns RecordObservationsReply, as record_prices
answers: recorded, restated, unchanged and the dataset's
watermark. A corrected or final factor is the next version of its row
key, and the latest version is the one in force.
from meridian.helpers import debt
row = debt.factor(pool_id, "0.84123456", "2026-10", dataset="fannie_mae",
wac="6.125", wam=342, wala=17)
await role.record_factors(factors=[row])
list_factors¶
Reads the factors the lake holds for pools or classes over a range of dates, point in time and by source.
async def list_factors(
self, *, subjects: Sequence[SubjectRef] = (), from_date: date | str = "",
to_date: date | str = "", sources: SourceChoice | None = None,
as_of_ns: int = 0, page_size: int = 0, cursor: str = "",
after_watermark: Watermark | None = None,
) -> ListFactorsReply
| gRPC | rpc ListFactors(ListFactorsParams) returns (ListFactorsReply) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-factors |
| Role | operations, portfolio, reporting, servicing, signal; the book reads it too, to price a fill |
| Served by | the lake |
| Parameter | Meaning |
|---|---|
subjects |
1 to 500 pools or classes |
from_date, to_date |
The range of dates read; debt.read_factors answers each pool's rows by payment date |
sources, as_of_ns |
As list_prices takes them |
page_size, cursor |
At most 500 a page, capped |
after_watermark |
Only what was recorded after it, to catch up |
Returns ListFactorsReply: factors, each at its version in force
(or at as_of_ns); unanswered; the datasets read; the watermark;
and next_cursor. debt.read_factors(role, subjects, from_date, to_date)
reads every page, and a pool no source covers is named unanswered, never
given a factor of 1.
list_expirations¶
Reads an underlying's expirations alone, in date order, each with how many series it lists, so a page chooses its expiration with one small read instead of listing every series.
async def list_expirations(
self, *, underlying_id: str = "",
instrument_type: InstrumentType | str | None = None,
expiration_from: date | str = "", expiration_to: date | str = "",
) -> ListExpirationsReply
| gRPC | rpc ListExpirations(ListExpirationsParams) returns (ListExpirationsReply) |
| Workflow step | W10.6, Read prices, bars, trades and quotes, point in time, by source |
| Kind | query, on platform.lake.query.list-expirations |
| Role | ems, oms, portfolio, signal |
| Served by | the lake |
Returns ListExpirationsReply: expirations, each its
expiration_date and series_count; unanswered; the datasets read;
and the watermark. chains.read_expirations(role, underlying_id,
expiration_from, expiration_to) wraps it.
Types¶
The plugin-facing types these operations take and return. Identifier and MissReason are described with the Python SDK. Money, StatementFigures, ReportedCollateral, ReportedLot, ReportedEncumbrance and the book's OpeningSource, OpeningPosition, OpeningLot, PendingSettlement, LotTerms, PositionKey, BreakDifference, BreakValue, BreakCause, PendingSettlementRef, AgreementFigures, ReportedPositionValue, PositionEncumbrances, Encumbrance, Adjustment, MovementLine and BasisAdjustment are the SDK's frozen dataclasses, exported from meridian, which take their numbers as Decimal and their amounts as Money, and are converted and refused as a call's own parameters are. Every other type below is a generated protobuf message or enum in meridian.plugin.v1.operations_pb2, and AssetClass, CollateralDirection, ExternalAccount, HoldingSide and SyncState are also exported from meridian. What a read answers is all generated messages, StatementFigures among them: read a number or an amount off one with as_decimal and as_money.
Money¶
An amount of currency, meridian.Money(amount, currency_code): a frozen dataclass.
| Field | Type | Meaning |
|---|---|---|
amount |
Decimal or int |
In the currency's major unit. |
currency_code |
str |
ISO 4217, such as "USD". Empty for an asset with no ISO 4217 code. |
instrument_id |
str |
The cash instrument the amount is in, fiat and tokens alike. Empty from a plugin naming a fiat currency by its code, which core resolves, dated; never empty on what core keeps and answers. |
A Money always names an instrument (see Money and instruments). Money(Decimal("12.50"), "USD") keeps its shape; a token is named by its instrument alone, Money(Decimal("2410.5"), instrument_id=usdc), as resolve_identifier resolved it. A Money naming neither raises ValueError before anything is sent; a token's code in currency_code, and a code and an instrument naming two assets, are refused naming the field. A Money read back with as_money carries instrument_id beside the code: a test comparing one with a Money it made compares amount and currency_code.
ExternalAccount¶
One account a connection reaches, as the custodian presents it.
| Field | Type | Meaning |
|---|---|---|
external_account_id |
str |
Stable: the plugin makes it so where the venue does not. It is the external_account_id the account's rows name. A handle the venue wants on each call stays inside the plugin. |
name |
str |
The custodian's own name for it, as a person there would recognise it. |
venue_account_type |
str |
The venue's own word for the kind of account, verbatim and for display only. Deprecated for the account kind, and the venue's word as reported where it does not convert. |
AssetClass¶
The kind of claim holding an instrument gives. A closed list: a class joins it by a ruling, never because a venue sent one. In a string, a value is spelled as its name without ASSET_CLASS_, in lower case.
| Value | Number | Meaning |
|---|---|---|
ASSET_CLASS_UNSPECIFIED |
0 | Not known. Only a stub minted from a deployment's miss may have no class; activating it requires one. |
ASSET_CLASS_EQUITY |
1 | equity: a share of ownership. |
ASSET_CLASS_DEBT |
2 | debt: somebody owes the holder, as with a bond. |
ASSET_CLASS_FUND |
3 | fund: a share of a pool, such as an ETF or a mutual fund. |
ASSET_CLASS_DERIVATIVE |
4 | derivative: a contract whose value comes from something else, such as an option or a future. |
ASSET_CLASS_CRYPTO_ASSET |
5 | crypto_asset. |
ASSET_CLASS_EVENT_CONTRACT |
6 | event_contract: pays on whether an event happens. |
ASSET_CLASS_CASH |
7 | cash: a holding of a currency's cash instrument. |
What kind of instrument within a class (an ETF within fund, an option within derivative) is its instrument type, which the interface does not carry yet.
HoldingSide¶
Which side of an instrument a holding is on.
| Value | Number | Meaning |
|---|---|---|
HOLDING_SIDE_UNSPECIFIED |
0 | Not said. Refused by the street store. |
HOLDING_SIDE_LONG |
1 | Long. The quantity is zero or more. |
HOLDING_SIDE_SHORT |
2 | Short. The quantity is zero or less. |
SyncState¶
Why a connection's data is, or is not, current. Each asks something different of a person.
| Value | Number | Meaning |
|---|---|---|
SYNC_STATE_UNSPECIFIED |
0 | Not said. Shown as what connection_healthy says. |
SYNC_STATE_CURRENT |
1 | Current. Nothing to do. |
SYNC_STATE_STALE |
2 | Still serving, but older than it should be; holdings_as_of_ns says since when. Usually the rail's to recover. |
SYNC_STATE_NEEDS_SIGN_IN |
3 | A person must sign in again at the venue before it serves anything new. |
SYNC_STATE_DISABLED |
4 | The connection is disabled and serves only what it last read. Somebody re-enables it. |
SYNC_STATE_DELAYED_BY_DESIGN |
5 | Late on purpose, such as by a business day. Expected; nothing to do. |
SYNC_STATE_HOLDINGS_UNAVAILABLE |
6 | The venue does not provide holdings through this connection. Waiting changes nothing. |
StatementFigures¶
A statement's figures for one margin segment, meridian.StatementFigures(...), keyword only. Each is as the venue reported it and None where it reported none, which is not zero; none is derived.
| Field | Type | Meaning |
|---|---|---|
segment |
str |
The segment as the venue names it, verbatim, such as Interactive Brokers' "securities" and "commodities", or an FCM's class. Empty, the default, for the account as a whole. |
buying_power |
Money or None |
The buying power. |
margin_requirement |
Money or None |
The margin requirement. |
maintenance_excess |
Money or None |
The maintenance excess. Negative is a deficit. |
initial_margin |
Money or None |
The initial margin. |
variation_margin |
Money or None |
The variation margin. |
net_liquidation |
Money or None |
A brokerage's own total account value, as it reports it. Never a sum of the holdings. |
collateral |
sequence of ReportedCollateral |
The collateral held under this segment. |
ReportedCollateral¶
One collateral balance under a margin segment, meridian.ReportedCollateral(...), keyword only, each field as the venue reports it and unset where it does not. A balance moves nothing: posted collateral the custodian also lists as a holding is a holding row as well, and collateral received under a security interest is never a holding.
| Field | Type | Meaning |
|---|---|---|
direction |
CollateralDirection, str or None |
Posted by the account or received by it. Refused when not said. |
instrument_id |
str |
The instrument, resolved as a holding's is: an instrument, the deployment's placeholder, or the currency's cash instrument for cash. |
unresolved_identifiers |
sequence of Identifier |
The identifiers the plugin held, when the resolve was ambiguous. Exactly one of these two. |
quantity |
Decimal or int |
The quantity. Required. |
value |
Money or None |
Its value. |
haircut |
Decimal, int or None |
A fraction of the value: Decimal("0.15") is 15%, a venue's percentage written as its fraction. |
value_after_haircut |
Money or None |
Its value after the haircut. |
held_at |
str |
Where it is held, as the venue names it: the FCM, the dealer, a third-party custodian. Empty where it does not say. |
reusable |
bool or None |
Whether the receiver may reuse it, as the agreement states and the venue reports it; None where it does not say. Received collateral is never a holding, reusable or not. |
CollateralDirection¶
| Value | Number | Meaning |
|---|---|---|
COLLATERAL_DIRECTION_UNSPECIFIED |
0 | Not said. Refused: collateral is posted or received. |
COLLATERAL_DIRECTION_POSTED |
1 | posted: posted by the account. |
COLLATERAL_DIRECTION_RECEIVED |
2 | received: received by it. |
ReportedLot¶
One lot of a holding, as the custodian lists it, meridian.ReportedLot(...), keyword only.
| Field | Type | Meaning |
|---|---|---|
quantity |
Decimal or int |
Signed as the holding's quantity: a short holding's lots are short, their quantities negative. Required. |
cost |
Money or None |
The lot's total cost, with its sign as the venue reports it, never flipped to match. None where not reported. |
acquired_date |
str |
When it was acquired, an ISO 8601 date. Empty where not reported. |
CustodialPosition¶
What the custodian says an account holds of an instrument, on one side. It is the custodian's belief, read from its statements, and not what the deployment calculates from its own activity.
| Field | Type | Meaning |
|---|---|---|
account_id |
str |
The account. |
instrument_id |
str |
An instrument, or the deployment's LCL- placeholder awaiting identity, which the platform's INS- identifier replaces when it arrives. |
side |
HoldingSide |
Long or short. |
quantity |
Decimal message |
The trade-date quantity, signed to match side. |
settle_date_quantity |
Decimal message |
The settle-date quantity, where the custodian reported one. |
market_value |
Money message |
Unset where the custodian reported no value, which is not zero. |
also_counted_in_cash |
bool |
Its value is also in the account's cash holding as the custodian reports it. |
cost_basis, average_cost, lots, margin_requirement |
as on record_holding |
As the custodian reported them on the row that last stated the position, unset or empty where it reported none. |
available_quantity, not_available_quantity, available_basis, encumbrances |
as on record_holding |
The same. |
last_statement_id, as_of_date, updated_at_ns |
str, str, int |
The statement that last stated it, and when. |
last_change |
JournalRef |
Where its last change sits in the store's record, which their role classes' on_<event> methods reads to catch up. A handler is handed none. |
removed |
bool |
Removed, as when a placeholder's replacement moved it: answered only to a read given since, and heard once. |
UnresolvedHolding¶
A holding the deployment received but could not name.
| Field | Type | Meaning |
|---|---|---|
holding_id |
str |
The recorded row. |
account_id |
str |
The account. |
identifiers |
sequence of Identifier |
What the plugin held. |
quantity |
Decimal message |
Signed, as the row stated it: negative is a short row. |
market_value |
Money message |
Unset where the custodian reported no value. |
source, as_of_date |
str |
As on its statement. |
escalated |
bool |
Whether the miss has already been raised, so nobody having looked at it is told apart from its being with an administrator. |
StatementRecordedEvent¶
A completed statement, as the street store announced it when its last row landed. The statement_recorded handler of their role classes' on_<event> methods is handed one, and list_statements answers them.
| Field | Type | Meaning |
|---|---|---|
statement_id |
str |
The statement. |
account_id |
str |
The account it is of: its external account's, or, from a plugin that named none, its rows'. |
external_account_id, institution |
str |
As the statement named them. Empty from a plugin that named none. |
source, as_of_date |
str |
As the statement named them. |
rows_received, rows_resolved, rows_unresolved |
int |
Its counts. The unresolved count is the one an operator watches. |
figures |
sequence of StatementFigures |
Its figures as recorded, one set per segment. |
currency_assumed |
bool |
As the statement said. |
security_interest |
optional bool |
As the statement said; unset where it did not say. |
recorded_at_ns |
int |
When it was completed. |
journal, cause |
JournalRef, ChangeCause |
Where its completion sits in the store's record, and who caused it. A handler is handed cause as Heard.cause, and no journal. |
CustodialActivity¶
One activity on an account as the custodian states it, meridian.CustodialActivity(...), the SDK's form: a number as a Decimal, an amount as a Money, the kind as an enum's value or name, each converted and refused naming its path (activity.units), as a parameter is. Each field's meaning and bounds are in the data dictionary, the street's CustodialActivity.
| Field | Type | Meaning |
|---|---|---|
external_activity_id |
str |
The custodian's own identifier for the activity, never a time or a random value: with the source and the account, the street's key for it. Required. |
kind |
ActivityKind, str or None |
What happened, converted from the custodian's type. None where the type converts to none of the kinds, and then kind_as_reported carries it. |
kind_as_reported |
AsReported or None |
The custodian's type, meridian.edge.as_reported(scheme, code, text), set only when kind is not known. For a person to map; nothing reads it. |
instrument_id |
str |
The instrument, resolved at the edge as a holding's is: the deployment's record, or the currency's cash instrument. Empty where the activity concerns none, or the custodian's code did not resolve. |
instrument_as_reported |
AsReported or None |
The custodian's code for the instrument, set only when it did not resolve: a plan's own fund code nobody has linked to an instrument, say. |
trade_date, settlement_date |
str |
ISO 8601: when it was traded or took effect, and when it settles or settled. The trade date is required; the settlement date is empty where the custodian does not state it. |
units |
Decimal, int or None |
The units of the instrument it moved, signed by what it did to the account: positive added units (a purchase, a reinvestment, the units a split added, a transfer in), negative removed them (a sale, a fee taken in units, a transfer out). None where it moved none, such as a cash dividend: never zero. |
price |
Money or None |
The price per unit, as stated. None where the custodian states none: never worked out from the amount and the units. |
amount |
Money or None |
The cash it moved, signed by what it did to the account's cash: positive in (a sale, a dividend, a contribution), negative out (a purchase, a fee, a withdrawal). None where it moved none, such as a split: never zero. |
description |
str |
The custodian's own words, for a person. Nothing branches on it. |
raw_record |
RawRecordRef |
The raw record it was converted from, role.plugin.raw_record(key). Required. |
provenance |
sequence of Provenance |
One for each value the plugin closed rather than read: an instrument a named person linked (meridian.edge.supplied("instrument_id", person)), a settlement date derived by a named rule. |
Activity is never netted or deduplicated against holdings: a sweep fund's purchases are reported as the custodian lists them.
ActivityKind¶
What an activity was, in the platform's own words, never a custodian's.
| Value | Number | Meaning |
|---|---|---|
ACTIVITY_KIND_UNSPECIFIED |
0 | Not known: the custodian's type converts to none of these, and travels beside it as reported (kind_as_reported). |
ACTIVITY_KIND_PURCHASE |
1 | Units bought. |
ACTIVITY_KIND_SALE |
2 | Units sold. |
ACTIVITY_KIND_REINVESTMENT |
3 | Income the custodian reinvested in units, as a money market fund's monthly dividend is. |
ACTIVITY_KIND_DIVIDEND |
4 | A dividend paid in cash. |
ACTIVITY_KIND_INTEREST |
5 | Interest paid in cash. |
ACTIVITY_KIND_FEE |
6 | A fee, in cash or in units. |
ACTIVITY_KIND_TAX |
7 | A tax withheld or paid. |
ACTIVITY_KIND_SPLIT |
8 | A split: the units it added or removed. |
ACTIVITY_KIND_CORPORATE_ACTION |
9 | Another corporate action, as the custodian states it. |
ACTIVITY_KIND_TRANSFER_IN |
10 | Units or cash moved in from another account. |
ACTIVITY_KIND_TRANSFER_OUT |
11 | Units or cash moved out to another account. |
ACTIVITY_KIND_CONTRIBUTION |
12 | Cash paid into the account. |
ACTIVITY_KIND_WITHDRAWAL |
13 | Cash taken out of the account. |
ACTIVITY_KIND_JOURNAL |
14 | A movement between the account's own positions or sub-accounts, as the custodian journals it. |
ActivityRecordedEvent¶
An activity, as the street store announced it when it was recorded (W2.12), and each item of list_activities. The activity_recorded handler of their role classes' on_<event> methods is handed one.
| Field | Type | Meaning |
|---|---|---|
activity_id |
str |
The street's identifier for it. |
account_id, external_account_id, source |
str |
The account it is on, as the sidecar stamped it, and as the source knows it; the source's scheme. |
activity |
CustodialActivity |
The activity whole, as the custody plugin sent it. |
recorded_at_ns |
int |
When the street recorded it: the deployment's clock, never back-dated. A backfilled activity's own time is its trade_date. |
journal, cause |
JournalRef, ChangeCause |
Its record in the street's partition, chained per account with the activities before it, and who caused it. A handler is handed cause as Heard.cause, and no journal. |
ActivityReResolution¶
One re-resolution of an activity, as the street keeps it beside the activity as first recorded, and each item of list_activities' re_resolutions.
| Field | Type | Meaning |
|---|---|---|
activity_id, account_id |
str |
The activity it sits beside, and the account it is recorded against. |
instrument_id |
str |
The instrument the activity now resolves to; empty where it is unresolved again. |
provenance |
Provenance |
How: supplied by the named person who set the link, or derived by a named rule. |
resolved_at_ns |
int |
When what resolves it was made, as the plugin sent it. |
recorded_at_ns |
int |
When the street recorded it: the deployment's clock, never back-dated. |
journal |
JournalRef |
Its own number in the street's partition, chained per account with the re-resolutions before it. |
ActivityReResolvedEvent¶
A re-resolution, as the street store announced it when it was recorded (W2.16). The activity_re_resolved handler of their role classes' on_<event> methods is handed one, caught up after a gap from list_activities' re_resolutions.
| Field | Type | Meaning |
|---|---|---|
account_id |
str |
The account it is on. |
re_resolution |
ActivityReResolution |
The re-resolution whole. |
cause, journal |
ChangeCause, JournalRef |
Who caused it, and its number. A handler is handed cause as Heard.cause, and no journal. |
SyncStatusRecordedEvent¶
A sync status the street store heard and kept (W2.13), and each item of list_sync_statuses. The sync_status_recorded handler of their role classes' on_<event> methods is handed one.
| Field | Type | Meaning |
|---|---|---|
status |
SyncStatusEvent |
As the custody plugin published it (report_sync_status), its state and history_from among it; its account as the sidecar stamped it, empty when the external account is not linked, and then delivered to no plugin. |
recorded_at_ns |
int |
When the street recorded it. |
journal, cause |
JournalRef, ChangeCause |
Its record in the street's partition, chained per account, and the custody plugin whose sync status it was. |
Watermark¶
A point in a store's record: partitions, each a partition and its sequence. A read answers the one it was read at, as as_of, and takes one, as since, to answer what changed after it. A plugin passes back what a read answered, and reads nothing into it.
AccountRecord¶
One of the firm's accounts. See Accounts.
| Field | Type | Meaning |
|---|---|---|
account_id |
str |
ACC- followed by 26 letters and digits. |
name |
str |
The account's name. |
state |
AccountState |
ACCOUNT_STATE_OPEN or ACCOUNT_STATE_CLOSED. Closed, not deleted. |
created_at_ns |
int |
When it was created. |
custodian |
str |
Where it is held. Free text; may be empty. |
account_type |
str |
What it is. Free text; may be empty. |
owner |
str |
One ownership or grouping label. Free text; may be empty. |
note |
str |
Anything else. Free text; may be empty. |
InstrumentRecord¶
An instrument's record, as resolve_instrument answers it.
| Field | Type | Meaning |
|---|---|---|
instrument_id |
str |
INS-, minted only by the platform, or the deployment's LCL- placeholder. |
identifiers |
sequence of Identifier |
Its full identifier set. |
asset_class |
AssetClass |
Its asset class. |
currency |
str |
ISO 4217. |
exchange_mic |
str |
Its listing venue, ISO 10383; empty where there is none. Deprecated for listing_venue_id, and read until every record carries a venue ID. |
listing_venue_id |
str |
The venue it is listed on, a venue master ID (VEN-), a segment's venue where the listing is on one; empty where it is listed on none or its venue is not yet known. |
description |
str |
Its name. |
lifecycle_state |
InstrumentLifecycleState |
DEFINE (its attributes may be incomplete), ACTIVE or DECOMMISSIONED. |
version, valid_from_ns, record_time_ns |
int |
The record's version, when its mapping became true, and when the store recorded it. |
instrument_type |
InstrumentType |
Its type within its class, where known: INSTRUMENT_TYPE_MONEY_MARKET_FUND or INSTRUMENT_TYPE_BINARY_EVENT_CONTRACT. |
binary_event_contract |
BinaryEventContract |
A binary event contract's payout, a Money naming its cash instrument, and closes_at_ns, when trading closes (0 where none is stated). Unset for any other type. |
Each of its identifiers carries its window on the record, valid_from_ns and valid_until_ns (0 while it is on the record), filled by the instrument store: one that left the record is kept, its window closed.
AvailableBasis¶
What a holding's available quantity is on, as the source says.
| Value | Number | Meaning |
|---|---|---|
AVAILABLE_BASIS_UNSPECIFIED |
0 | The source does not say. |
AVAILABLE_BASIS_SETTLED |
1 | settled. |
AVAILABLE_BASIS_TRADED |
2 | traded. |
AVAILABLE_BASIS_CONTRACTUAL |
3 | contractual. |
AVAILABLE_BASIS_ORDER_NETTED |
4 | order_netted: a venue's figure net of its open orders, such as Alpaca's qty_available. The order reservation is never an encumbrance. |
ReportedEncumbrance¶
One sub-balance of a holding the source reports as encumbered, meridian.ReportedEncumbrance(...), keyword only, as the source reports it.
| Field | Type | Meaning |
|---|---|---|
kind |
EncumbranceKind, str or None |
Why it cannot move. Refused when not said. |
quantity |
Decimal or int |
Signed as the holding's quantity. Required. One larger than the holding is recorded as reported. |
available |
bool or None |
Whether the source reports it available. None where it does not say: the kind does not imply it. |
source_code |
str |
The source's own code or label, verbatim, such as "PLED". Required for OTHER. |
pledgee |
str |
To whom it is pledged, posted or lent, as reported. |
held_at |
str |
The safekeeping place or third party holding it, as reported. |
segment |
str |
The margin segment it is under, where the source names one. |
detail |
str |
The source's narrative. |
EncumbranceKind¶
Why some of a holding cannot move.
| Value | Number | Meaning |
|---|---|---|
ENCUMBRANCE_KIND_UNSPECIFIED |
0 | Not said. Refused. |
ENCUMBRANCE_KIND_PLEDGED |
1 | pledged: pledged in place to a pledgee. |
ENCUMBRANCE_KIND_POSTED |
2 | posted: delivered to a third party as collateral. |
ENCUMBRANCE_KIND_ON_LOAN |
3 | on_loan: lent. |
ENCUMBRANCE_KIND_BLOCKED |
4 | blocked: blocked for a stated purpose. |
ENCUMBRANCE_KIND_RESTRICTED |
5 | restricted: movable only under conditions or with documents. |
ENCUMBRANCE_KIND_IN_TRANSIT |
6 | in_transit: between depositories, agents or registers. |
ENCUMBRANCE_KIND_OTHER |
7 | other: a sub-balance the plugin cannot map; its source_code is required. |
ENCUMBRANCE_KIND_PENDING |
8 | The street's only, as reported: the book refuses it. |
ENCUMBRANCE_KIND_REHYPOTHECATED |
9 | The street's only: used by the broker under a right of use, which reduces nothing. The book refuses it. |
ENCUMBRANCE_KIND_BORROWED |
10 | The street's only: borrowed, with a return obligation. The book refuses it. |
Book entry result¶
Every command of the book answers after its entry commits, with the same fields: RecordOpeningBalanceResult, RecordBreakResult, RecordAccountFiguresResult, RecordEncumbrancesResult, HandleBreakResult, ResolveBreakResult and CloseBreaksAsClearedResult. A repeat, by its message identifier or its idempotency key, is answered with the first's.
| Field | Type | Meaning |
|---|---|---|
entry |
EntryMeta |
The entry. |
journal |
JournalRef |
Its place in the account's partition: the number of the first change it made. |
positions |
sequence of BookPosition |
Each position it changed, as it stands after it. |
breaks |
sequence of Break |
Each break it changed. |
figures |
sequence of AccountFigures |
Each figures record it changed. |
attributes |
AccountAttributes |
The account's attributes, where it changed them: an opening balance and its reversal set and clear the standing one. |
EntryMeta¶
What a journal entry records.
| Field | Type | Meaning |
|---|---|---|
entry_id |
str |
Minted by the book. |
kind |
str |
opening-balance, placeholder-moved, figures-recorded, break-recorded, break-handled, break-resolved, break-closed, adjustment, reversal, attribute-set or encumbrances-recorded: an open list, which a reader takes as data. |
actor |
Actor |
Who made it, set by the book from what the sidecar stamped: person, with the person's subject, or system, with the instance_id of the plugin that reported a finding as itself, empty for the book's own act; or service_account, with the service account's subject (its SA- ID) and its owner_subject when it acted. |
event_time_ns, received_at_ns |
int |
The time on the message that caused it, and when the book received it. When it committed is its cause's committed_at_ns. |
effective_date |
str |
The ISO 8601 business date it stands for. |
control_sequence |
int |
The control partition's sequence in force. |
reference_versions |
sequence of ReferenceVersion |
Each instrument it names, with the version of its record in force when it was recorded. |
reason |
str |
The person's reason, on a justified act. |
break_ids |
sequence of str |
The breaks it records, handles, resolves or closes. |
idempotency_key |
str |
The key it was sent with, where it was sent one. |
BookPosition¶
A position in the book.
| Field | Type | Meaning |
|---|---|---|
account_id, instrument_id, side |
str, str, HoldingSide |
Whose, of what, and which side. |
trade_date_quantity |
Decimal message |
The settled quantity plus what is pending: by construction. On a position an older opening balance opened with some of it not stated, that too. |
settled_quantity |
Decimal message, optional |
Set on every position the book records now. Unset only while some of the quantity is in the not-stated bucket an older opening balance opened: unknown, never zero. |
not_stated_quantity |
Decimal message |
Retired: zero on every position the book records now. What an older opening balance's source did not say was settled or pending. |
pending |
sequence of PendingSettlement |
What is pending, by value date. |
lots |
sequence of Lot |
Its open lots, whose open quantities sum to its trade-date quantity; cash has none. |
opened_from |
sequence of OpeningSource |
Its opening balance's sources. |
effective_date |
str |
The business date of its last change. |
last_change |
JournalRef |
Where its last change sits in the book's record. |
removed |
bool |
Removed, after the book moved it from a placeholder onto its instrument: answered only to a read given since, and heard once. |
placeholder |
bool |
Held under a placeholder instrument, until the book follows its replacement. |
encumbrances |
sequence of Encumbrance |
What of it cannot move, as last recorded from a statement. |
free_quantity |
Decimal message, optional |
Derived, never reported: the quantity on free_basis less the encumbrances. Unset while that quantity is unknown. |
free_basis |
FreeBasis |
FREE_BASIS_SETTLED, the only basis in this release. |
Lot¶
One of a position's lots, the book's own record.
| Field | Type | Meaning |
|---|---|---|
lot_id |
str |
Minted by the book. |
open_quantity, original_quantity |
Decimal message |
What is open of it, and what it opened with. |
terms |
LotTerms |
As opened, with each basis adjustment applied. |
opened_by, relieved_by, adjusted_by |
JournalRef, sequences of JournalRef |
The entries that opened, relieved and adjusted it. |
Encumbrance¶
One encumbrance of a position, as the book holds it, meridian.Encumbrance(...) when sent.
| Field | Type | Meaning |
|---|---|---|
kind |
EncumbranceKind, str or None |
PLEDGED to OTHER only. |
quantity |
Decimal or int |
Signed as the position's quantity. Required. |
pledgee, held_at |
str |
To whom, and where, as the statement states them. |
agreement |
MarginAgreementRef or None |
The margin agreement, where the source names one. |
source_code |
str |
The source's code, verbatim; required for OTHER. |
detail |
str |
The source's narrative. |
source |
StreetRecordRef or None |
The statement it was recorded from. |
since_date, set_by |
str, JournalRef |
Set by the book: the business date it was first recorded under its kind, pledgee, location and agreement, and the change that last set it. |
PositionEncumbrances¶
One position's encumbrances as a statement states them, meridian.PositionEncumbrances(instrument_id=..., side=..., encumbrances=[...]): the whole set, empty when the statement reports none.
OpeningSource¶
A source an opening balance was composed from, meridian.OpeningSource(...), keyword only.
| Field | Type | Meaning |
|---|---|---|
kind |
OpeningSourceKind, str or None |
custodian or prior_system. |
name |
str |
The custodian or system as the deployment knows it: the external account's institution, or the prior system's name. |
as_of_date |
str |
The ISO 8601 date the source's figures are as of. |
basis |
PositionBasis, str or None |
Whether it reports trade_date or settle_date positions. |
street_records |
sequence of StreetRecordRef |
The street records it was composed from, by value. |
OpeningPosition¶
One position of an opening balance, meridian.OpeningPosition(...), keyword only.
| Field | Type | Meaning |
|---|---|---|
instrument_id |
str |
An instrument, a placeholder, or a currency's cash instrument. |
side |
HoldingSide, str or None |
Long or short. |
trade_date_quantity |
Decimal or int |
Required. |
settled_quantity |
Decimal, int or None |
Required by the book: where the source states none, a person supplies it. None is refused as positions[n].settled_quantity. |
pending |
sequence of PendingSettlement |
Its pending settlements, each with its value date. With the settled quantity they account for the whole trade-date quantity, or the book refuses it as positions[n].pending. |
lots |
sequence of OpeningLot |
As reported and completed by a person, each meridian.OpeningLot(quantity=..., terms=LotTerms(...)) with its quantity, and its terms' cost and acquired_date; they must sum to the trade-date quantity. Required but on cash, which sends none. |
PendingSettlement¶
Quantity pending on a value date, meridian.PendingSettlement(...).
| Field | Type | Meaning |
|---|---|---|
value_date |
str |
ISO 8601, which may be years out. Required at an opening balance. Empty on a position only for "date not stated", from an older opening balance or an adjustment the street gave no date for. |
quantity |
Decimal or int |
Required. |
state |
PendingState or None |
Where the source reports a fail: failing, fail_reason as reported, and expected_date, when it is now expected. |
LotTerms¶
A lot's terms, meridian.LotTerms(...), each unset where not known and never derived one from another. A lot the book opens, at an opening balance or by an adjustment, carries its cost and acquired_date, or the book refuses it; a lot an older opening balance opened may lack them.
| Field | Type | Meaning |
|---|---|---|
unit_cost, cost |
Money or None |
Its cost per unit, and in all. |
acquired_date |
str |
When it was acquired. |
holding_period_start |
str |
Where its holding period starts, apart from acquisition; empty is the acquired date. |
settlement_date |
str |
When it settled. |
source |
LotSource, str or None |
opening_balance or adjustment. |
StreetRecordRef¶
A street record named by value, never a key the book follows: statement_id, change (the custodial position's change, a JournalRef, where one was compared or used) and as_of_date, the custodian's.
PositionKey¶
A position a break concerns, meridian.PositionKey(instrument_id=..., side=...).
FigureKey¶
An account-level figure a break concerns: agreement, a MarginAgreementRef; figure, by its field's name in the data dictionary; and instrument_id, for a collateral balance.
MarginAgreementRef¶
A margin agreement. In this release its one arm is statement_segment, a StatementSegmentRef: the statement's external_account_id, its segment as the venue names it (empty for the account as a whole), and its counterparty, the external account's institution as reported.
BreakCategory¶
| Value | Number | Meaning |
|---|---|---|
BREAK_CATEGORY_UNSPECIFIED |
0 | Not said. |
BREAK_CATEGORY_TRADE_DATE_QUANTITY |
1 | trade_date_quantity. |
BREAK_CATEGORY_SETTLED_QUANTITY |
2 | settled_quantity. |
BREAK_CATEGORY_COST_OR_LOTS |
3 | cost_or_lots. |
BREAK_CATEGORY_SETTLED_AGAINST_PENDING |
4 | settled_against_pending. |
BREAK_CATEGORY_BOOK_ONLY |
5 | book_only: a position on the book's side only. |
BREAK_CATEGORY_STREET_ONLY |
6 | street_only: a position on the street's side only. |
BREAK_CATEGORY_FIGURE |
7 | figure: a figure the book holds a value of its own for, such as the street's available and not available against the book's position, or an encumbrance against the book's. |
BreakDifference¶
One differing field, meridian.BreakDifference(field=..., book=..., street=...): field, by its name in the data dictionary ("settled_quantity", "lots[2].terms.cost"), and each side a meridian.BreakValue of one of quantity, amount or text, or None where it is absent on that side.
BreakState¶
BREAK_STATE_OPEN (1), BREAK_STATE_RESOLVED (2) or BREAK_STATE_CLOSED (3); open, resolved or closed in a string.
BreakCause¶
The item found to cause a break, linked by value, meridian.BreakCause(...).
| Field | Type | Meaning |
|---|---|---|
category |
BreakCauseCategory, str or None |
unbooked_trade, settlement_timing, cost_or_price, corporate_action, fail, custodian_error, unknown, or income_reinvested, income the custodian reinvested in units that the book has not booked, such as a money market fund's monthly dividend. |
street_record, book_entry, pending_settlement, event_reference, none_found, activity |
one of these | The item: a street record, a book entry, a pending settlement (meridian.PendingSettlementRef), a corporate action's reference as reported, none_found=True, or the custodian's activity that explains it, an ActivityRef. |
note |
str |
A note. |
ActivityRef¶
An activity the street recorded, named by value, meridian.ActivityRef(activity_id=..., change=..., trade_date=...): the street's activity_id, its record in the street's partition (change, the journal of its ActivityRecordedEvent), and its trade_date as the custodian stated it. The book records it as given and follows no key to the street, as it does a street record's.
# each: an ActivityRecordedEvent that list_activities answered
meridian.BreakCause(
category="income_reinvested",
activity=meridian.ActivityRef(
activity_id=each.activity_id, change=each.journal, trade_date=each.activity.trade_date,
),
note="the custodian reinvested income in 3.27 units",
)
BreakHandling¶
A break's handling: owner_subject, a user the deployment knows; escalation_level, the operations plugin's own levels, to which core gives no meaning; and due_date.
Break¶
A break, as the book holds it.
| Field | Type | Meaning |
|---|---|---|
break_id, account_id |
str |
Minted by the book; the account. |
position or figure |
PositionKey or FigureKey |
What it concerns. |
category, differences |
as on record_break |
|
book_watermark, street |
Watermark, StreetRecordRef |
What was compared. |
first_seen_date, last_seen_date |
str |
Business dates. Its age is derived from them, never stored. |
state |
BreakState |
Open, resolved or closed. |
candidate_causes, confirmed_cause |
sequence of BreakCause, BreakCause |
What the matching found, and what a person confirmed. |
handling |
BreakHandling |
Its owner, escalation level and due date. |
resolution |
BreakResolution |
How it ended: entries that resolved it, or the explanation it was closed with, or cleared_at, the statement where it cleared; with its actor and reason. |
recorded_by |
Actor |
Who recorded it. |
last_change |
JournalRef |
Where its last change sits. |
AgreementFigures¶
One agreement's figures to record, meridian.AgreementFigures(...): agreement, a MarginAgreementRef; figures, a StatementFigures as the street recorded them, its segment the agreement's; and position_values, on the set with no segment only, each a meridian.ReportedPositionValue of instrument_id, side, and the custodian's market_value and margin_requirement, labelled as the custodian's and never a position's own.
AccountFigures¶
The record: one per account, agreement and business date, with account_id, business_date, agreement, figures, position_values, source (the statement, a StreetRecordRef) and last_change.
AccountAttributes¶
An account's attributes in the book.
| Field | Type | Meaning |
|---|---|---|
account_id |
str |
The account. |
base_currency_code |
str |
ISO 4217. |
lot_relief_default |
LotReliefMethod |
What a sale relieves lots by when it names no method: FIRST_IN_FIRST_OUT, LAST_IN_FIRST_OUT, HIGHEST_COST, LOWEST_COST or AVERAGE_COST. |
last_change |
JournalRef |
Where its last change sits. |
opening_balance |
OpeningBalance, unset while none stands |
The standing opening balance: its entry_id, as_of_date (D0), sources, recorded_by, journal and the person's reason. |
Adjustment¶
An adjustment that resolves a break, meridian.Adjustment(...).
| Field | Type | Meaning |
|---|---|---|
effective_date |
str |
After the opening balance's date. |
lines |
sequence of meridian.MovementLine |
Each an instrument_id and side, a bucket (settled, or pending with its value_date, which may be empty where the street gave none), a signed quantity added to the position, and the lot_id it adds to or relieves, or opens_lot, the LotTerms of a lot it opens, with its cost and acquired_date. |
basis_adjustments |
sequence of meridian.BasisAdjustment |
Each a lot_id, and one of cost_change, added to a known cost, or stated_cost, the cost of a lot an older opening balance opened with its cost unknown, the only such lots; and holding_period_start, where it moves. |
event_reference |
str |
A corporate action's reference, as reported, where it records one, or the street's activity_id where the adjustment was proposed from the custodian's activity. |
Reversal¶
Reversal(entry_id=...): the entry it reverses, whose lines the book negates at that entry's effective date.
ResolvedByEntries¶
ResolvedByEntries(entry_ids=[...]): entries already recorded that resolve the breaks.
Price¶
A price of one kind for one subject, meridian.Price(...): a frozen dataclass, keyword only, converted and refused as a call's own parameters are. What a read answers is the generated message of the same name.
| Field | Type | Meaning |
|---|---|---|
meta |
ObservationMeta |
Its envelope. |
kind |
PriceKind |
Which price. |
price |
Money |
The price of one unit of the subject. An FX rate is the price of one currency's cash instrument in another. |
basis |
PriceBasis |
per_unit, the one basis there is. |
Bar¶
Open, high, low and close over an interval, meridian.Bar(...): a frozen dataclass, keyword only.
| Field | Type | Meaning |
|---|---|---|
meta |
ObservationMeta |
Its envelope; the interval is its valid time, and a daily bar names its business date. |
open, high, low, close |
Money |
In one asset, refused otherwise. |
volume |
Decimal or int |
Units of the instrument, never negative. |
vwap |
Money or None |
None where the source gives none. |
trade_count |
int or None |
None where the source gives none. |
Trade¶
One trade as its source reported it, meridian.Trade(...): a frozen dataclass, keyword only, converted and refused as a call's own parameters are. What a read answers is the generated message of the same name.
| Field | Type | Meaning |
|---|---|---|
meta |
ObservationMeta |
Its envelope: valid from its event time, valid_until_ns 0, no business date. |
price |
Money |
Its price per unit, in the asset it traded in; for an event contract, what one contract cost in the asset it pays out in. |
quantity |
Decimal or int |
The quantity traded, more than zero. |
attributes |
TradeAttributes or None |
The platform's trade attributes, converted from the source's condition codes. |
aggressor |
Aggressor or None |
The side the source says took liquidity: a taker's side as sent, a maker's inverted. Unset where the source says nothing. |
source_sequence |
int |
The number the source gave the trade in its own feed. |
cancelled |
bool |
True in a version saying the source withdrew it. |
TradeAttributes¶
What a trade may count for, meridian.TradeAttributes(...): consolidated and market_centre, each an Eligibility for the consolidated view and its own market centre's; and characteristics, at most 16 TradeCharacteristics. A code the plugin cannot convert goes, as reported, in the envelope's unconverted, its eligibilities left unspecified.
Eligibility¶
Whether a trade may set each statistic of a bar, not whether it did: high_low, open, close and volume, each an Eligible: ELIGIBLE_ELIGIBLE, ELIGIBLE_NOT_ELIGIBLE, or unspecified where it is not known. In a string, "eligible" or "not_eligible".
TradeCharacteristic¶
In a string, spelled as its name without TRADE_CHARACTERISTIC_, in lower case ("odd_lot").
| Value | Meaning |
|---|---|
OPENING_AUCTION, CLOSING_AUCTION |
Printed by the venue's opening or closing auction. |
OTHER_AUCTION |
Printed by another auction: a reopening after a halt, an intraday auction. |
ODD_LOT |
Smaller than the instrument's round lot. |
EXTENDED_HOURS |
Outside the venue's regular session. |
OUT_OF_SEQUENCE |
Reported out of its time order. |
LATE_REPORT |
Reported later than its venue's rules require. |
AVERAGE_PRICE |
Priced as an average over several executions. |
NON_REGULAR_SETTLEMENT |
Settling other than on the regular cycle: cash, next day, seller's option. |
INTERMARKET_SWEEP |
Part of an order sweeping several venues at once. |
DERIVATIVELY_PRICED |
Priced from another instrument or a benchmark. |
PRIOR_REFERENCE_PRICE |
Priced at a reference price from earlier in the day. |
CONTINGENT |
Executed contingent on another trade. |
CROSS |
A cross of two orders by one participant. |
Aggressor¶
AGGRESSOR_BUY or AGGRESSOR_SELL, the side that took liquidity; unspecified where the source does not say. In a string, "buy" or "sell".
Quote¶
The best bid and offer, on a venue or consolidated, meridian.Quote(...): a frozen dataclass, keyword only.
| Field | Type | Meaning |
|---|---|---|
meta |
ObservationMeta |
Its envelope: valid from its time, no business date. |
bid, ask |
Money or None |
The best price a buyer offered and a seller asked, both in one asset; None for an empty side. |
bid_quantity, ask_quantity |
Decimal, int or None |
The quantity at each, more than zero. |
characteristics |
sequence of QuoteCharacteristic |
At most 4: "indicative" (not firm) or "halted" (trading in the subject is halted). |
ObservationMeta¶
The envelope every lake row carries as its first field, meridian.ObservationMeta(...): a frozen dataclass, keyword only.
| Field | Type | Filled | Meaning |
|---|---|---|---|
row_key |
str |
by the plugin | Made from its raw record, so a repeat is the same row; a changed value under it is the next version. |
subjects |
sequence of SubjectRef |
by the plugin | 1 to 8 of the deployment's instruments, resolved first. |
source |
Source |
by the plugin, partly stamped | The dataset and venue; the instance and version stamped. |
valid_from_ns, valid_until_ns |
int |
by the plugin | When the value was in force, the end exclusive; 0 for an instant or a value in force until the next. A day still forming ends after now. |
business_date |
datetime.date or str |
by the plugin | A daily value's business date, in the dataset's day; empty for one that is not daily. |
source_times |
sequence of SourceTime |
by the plugin | The source's own times, each a kind (event, consolidated, reported, vendor_received, published) once, and at_ns. |
raw |
RawRecordRef |
by the plugin | The raw record it was converted from, role.plugin.raw_record(key). |
unconverted |
sequence of AsReported |
by the plugin | A value that failed conversion, as reported, such as a venue's code the deployment does not hold. |
closed_day |
DateCheck or None |
by the lake | On a daily row dated on a closed day of its dataset's calendar, the date, each calendar with its version, why (a weekend, a named holiday, or outside coverage) and the holiday's name. Unset otherwise. |
sent_at_ns |
int |
stamped | The envelope's publication time. |
recorded_at_ns, version, sequence, previous_sequence |
int |
by the lake | When it was recorded, its version under the row key from 1, its sequence in the dataset, and the previous sequence of the same subject. |
SubjectRef¶
One entity a row is about: entity_id, the deployment's instrument ID.
Source¶
Where a row came from.
| Field | Meaning |
|---|---|
dataset |
The dataset's ID, the instance, a colon and its key, alpaca-1:daily; one the instance's catalogue declares. |
venue_id |
The venue it originated on, a venue master ID; empty for the consolidated view, or a venue not yet held, whose code is then in unconverted. |
instance, plugin_version |
Stamped by the sidecar. |
SourceChoice¶
Which sources a read takes, one of: default=True (or no choice), the deployment's source priority, falling through where one is silent, not covering or not entitled; named, the datasets named; side_by_side=True, every entitled dataset, each its own row.
PriceKind¶
In a string, spelled as its name without PRICE_KIND_, in lower case.
| Value | Meaning |
|---|---|
PRICE_KIND_CLOSE |
The official close for the business date, consolidated or the venue's. |
PRICE_KIND_LAST |
The last eligible trade's price at the valid time. |
PRICE_KIND_NAV |
A fund's net asset value per share, for the business date. |
PRICE_KIND_SETTLEMENT |
A contract's settlement price for the business date. |
PRICE_KIND_BID, PRICE_KIND_ASK, PRICE_KIND_MID |
At the valid time, or the business date's closing quote. |
Unanswered¶
What a lake read did not answer: subject, dataset, field (a field stripped, by its dictionary entry; empty for the whole row) and reason, an UnansweredReason.
UnansweredReason¶
In a string, spelled as its name without UNANSWERED_REASON_, in lower case.
| Value | Meaning |
|---|---|
UNANSWERED_REASON_NOT_ENTITLED |
The plugin is not entitled to the dataset, or the field. |
UNANSWERED_REASON_NOT_COVERED |
No dataset covers the subject. |
UNANSWERED_REASON_ASKED_SOURCE |
Wanted of the data plugin serving it; the rows follow when recorded. |
UNANSWERED_REASON_SOURCE_SILENT |
The dataset recorded nothing for the subject within its cadence. |
UNANSWERED_REASON_UNRESOLVED |
The subject is not one the deployment's instruments resolve. |
UNANSWERED_REASON_BEYOND_HISTORY |
Older than the history the dataset reaches, or the lake keeps. |
UNANSWERED_REASON_NOT_KEPT |
Its licence forbids keeping it, and it was served, not kept. |
DatasetRef¶
A dataset as a lake answer names it, once: dataset, instance, vendor, aggregator, and its catalogue entry as declared, declaration (DatasetDeclaration); and unconverted_count and miss_count, the values its plugin left unconverted and the identifiers and venues it reported missing; and closed_day_count and outside_coverage_count, its daily rows flagged on a closed day of its calendar, and those outside the calendar's coverage, counted apart. declared_delay_ns, the delay its catalogue declares (0 for real time); stale_after_ns, its plugin admin's stale_after for it from the Dataset thresholds setting (0 for none); and in a listing, liveness, the latest DatasetLiveness the lake keeps per venue.
Outcome¶
Added in SDK 0.27.0. An event contract's outcome, meridian.Outcome(...), a frozen dataclass, keyword only. See An event contract's outcome.
| Field | Meaning |
|---|---|
meta |
Its ObservationMeta: one row key per contract, the contract's instrument its subject, valid from the determination, no business date |
determination |
OutcomeDetermination: pays, pays_nothing or pays_part |
stage |
OutcomeStage: proposed, determined, disputed or final; a change is the next version |
settlement_value |
A Money per contract in the payout's asset, always set |
settled_at_ns |
When the venue paid out; 0 until then |
determination_as_reported |
The venue's own word, an AsReported |
EventGroup¶
An event group at one version, as
report_event_group and
list_event_groups answer it and
event_group_changed delivers it:
| Field | Meaning |
|---|---|
event_group_id |
EVG- and a ULID, the platform's; or the deployment's own LCL- ID |
venue_id, venue_event_ref |
The venue and its reference for the event |
title |
The venue's words |
member_instrument_ids |
The members, sorted |
mutually_exclusive, exhaustive |
Each an EventGroupFlag: EVENT_GROUP_FLAG_TRUE, _FALSE or _NOT_STATED |
series_id |
The venue's series, or empty |
version, valid_from_ns, record_time_ns |
Its version, when it took effect and when it was kept |
provisional |
True for the deployment's own LCL- group |
sequence |
Its place in the store's sequence of event groups, which after_sequence reads after |
VenueRecord¶
A venue as the deployment holds it, from the platform's venue master: venue_id (VEN-), name, country_code, kind (VenueKind: exchange, alternative_trading_system, crypto_exchange, dealer_network, reporting_facility), identifiers (its MIC under iso10383 and vendors' codes as symbol, each dated), operating_venue_id, time_zone, lifecycle_state, version, valid_from_ns and record_time_ns. See Venues.
The gRPC service¶
For reference, the plugin-facing service in meridian/plugin/v1/operations.proto, which the sidecar serves on loopback:
service PluginOperations {
rpc ReportExternalAccounts(ReportExternalAccountsParams) returns (Published);
rpc ReportSyncStatus(ReportSyncStatusParams) returns (Published);
rpc RecordHoldingsStatement(RecordHoldingsStatementParams) returns (RecordHoldingsStatementResult);
rpc RecordHolding(RecordHoldingParams) returns (RecordHoldingResult);
rpc ListCustodialPositions(ListCustodialPositionsParams) returns (ListCustodialPositionsResult);
rpc ListStatements(ListStatementsParams) returns (ListStatementsResult);
rpc ResolveIdentifier(ResolveIdentifierParams) returns (ResolveIdentifierResult);
rpc ReportMissingInstrument(ReportMissingInstrumentParams) returns (Published);
rpc LinkExternalAccount(LinkExternalAccountParams) returns (LinkExternalAccountResult);
rpc ReadAccountsForLinking(ReadAccountsForLinkingParams) returns (ReadAccountsForLinkingResult);
rpc ResolveInstrument(ResolveInstrumentParams) returns (ResolveInstrumentResult);
rpc RecordOpeningBalance(RecordOpeningBalanceParams) returns (RecordOpeningBalanceResult);
rpc RecordBreak(RecordBreakParams) returns (RecordBreakResult);
rpc RecordAccountFigures(RecordAccountFiguresParams) returns (RecordAccountFiguresResult);
rpc RecordEncumbrances(RecordEncumbrancesParams) returns (RecordEncumbrancesResult);
rpc HandleBreak(HandleBreakParams) returns (HandleBreakResult);
rpc ResolveBreak(ResolveBreakParams) returns (ResolveBreakResult);
rpc CloseBreaksAsCleared(CloseBreaksAsClearedParams) returns (CloseBreaksAsClearedResult);
rpc ListPositions(ListPositionsParams) returns (ListPositionsResult);
rpc ListBreaks(ListBreaksParams) returns (ListBreaksResult);
rpc ListAccountFigures(ListAccountFiguresParams) returns (ListAccountFiguresResult);
rpc ListAccountAttributes(ListAccountAttributesParams) returns (ListAccountAttributesResult);
rpc Receive(ReceiveRequest) returns (stream Delivery);
}
Each …Params message keeps the field numbers of the domain message it stands for and drops the fields the sidecar stamps, so its encoding is the domain message's. acting_for is field 1000 on the eleven operations that take it, a meridian.v1.CallerAssertion. The SDK decodes it from the base64url Meridian-Caller header you pass. A number is a Decimal message, high and low halves of a 128-bit integer and a scale of 0 to 18, and an amount a Money message, a Decimal and a currency_code. Identifier, MissReason and the other types are plugin-facing mirrors of the domain types. Receive is a stream: each item a Delivery, a row's message beside what is known of it, or a Lost where the sidecar dropped deliveries. The SDK's their role classes' on_<event> methods reads it, and catches up from the store where it missed something.