Skip to content

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:

  1. It builds the domain message.
  2. It stamps the fields only the sidecar knows truthfully.
  3. It checks the grant.
  4. 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
from decimal import Decimal
import meridian

Decimal("12.5")                    # sent as 125 at scale 1
Decimal("0.000000000000000001")    # sent as 1 at scale 18
Decimal("0.0000000000000000001")   # ValueError: 19 decimal places
meridian.Money(Decimal("34218.75"), "USD")

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 with NotGranted, naming the session. The person must hold write on a role of the plugin whose grants include the command, the account among that role's write accounts: otherwise it is refused with NotGranted, 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_for that person, with their reason, or the book refuses them with REFUSAL_REASON_ACTOR_REQUIRED or REFUSAL_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 them acting_for its 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= or figure=, a resolution's adjustment=, reversal=, entries= or explanation=, a basis adjustment's cost_change= or stated_cost=, a cause's item. Two at once raise ValueError naming 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_date is the date the positions reflect.
  • read_at_ns is 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:

  • TypeError or ValueError for an amount or a number, one inside figures named 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 beside figures, in the sidecar's words: the sidecar refuses each as invalid too.
  • invalid for an empty external_account_id, and NotLinked for one not linked.
  • NotGranted when the linked account is outside the plugin's write scope, or when the person in acting_for may not write it.
  • not vouched for for an acting_for that is not accepted.
  • handler error from 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 handler or timeout from the street store.
  • NotGranted without the custody role.
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_id when resolve_identifier found it: an instrument, perhaps the deployment's own LCL- record, minted for an identifier set nothing matched;
  • unresolved_identifiers when 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:

  • TypeError or ValueError for a number or an amount, one inside lots named by its path (lots[0].cost).
  • invalid for an empty external_account_id, and NotLinked, a CallFailed of kind refused, 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.
  • NotGranted when the linked account is outside the plugin's write scope, as a closed account is, or when the person in acting_for may not write it.
  • not vouched for for an acting_for that is not accepted.
  • handler error from 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 of instrument_id and unresolved_identifiers, a statement it has not opened, or an account other than its statement's.
  • no handler or timeout from 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): found is True, and minted is True on the resolve that minted the deployment's record. A later resolve of the same identifiers matches that record, with minted False. Record the holding against it; the instrument store reports the miss itself. A source stating less mints nothing: found is False and miss_reason is MISS_REASON_NOT_FOUND, and the holding is recorded with unresolved_identifiers.
  • More than one matched. The result is a miss rather than a pick: found is False and miss_reason is MISS_REASON_AMBIGUOUS. Record the holding with unresolved_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]

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:

  • NotGranted without an acting_for, or with one from a session not opened by Manage; for a new_account_name from an admin who is not a deployment admin; or for an external account this plugin did not report, an empty one included.
  • not vouched for for an acting_for that is not accepted.
  • handler error from the conductor for a link it refuses, with its reason: both account_id and new_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.
  • CommandRefused with REFUSAL_REASON_ACCOUNT_NOT_LINKABLE for an account_id a deployment admin has not granted the plugin's instance. A new account made by linking is granted to the instance that made it.
  • no handler or timeout from the conductor.
  • NotGranted without the custody role.
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_REQUIRED with no person, REFUSAL_REASON_REASON_REQUIRED with no reason, REFUSAL_REASON_OPENING_BALANCE_RECORDED while one stands, REFUSAL_REASON_INCOMPLETE for a field the book requires left out, each in fields (positions[0].settled_quantity, positions[1].lots[0].terms.cost), REFUSAL_REASON_LOTS_UNBALANCED for lots that do not sum to their position, REFUSAL_REASON_IDEMPOTENCY_CONFLICT for a key used by a different command.
  • TypeError or ValueError for a number, an amount or an enum, named by its path (positions[0].lots[1].terms.cost).
  • NotGranted for an account outside the write scope, a person who may not write it, or a session not opened by Open. not vouched for for an acting_for that is not accepted.
  • handler error from the book for anything else it refuses, such as a position that states no side, with its reason. no handler or timeout from the book.
  • NotGranted without the operations role.
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_STATE for a break that is not open, REFUSAL_REASON_INCOMPLETE for 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_BALANCE for an entry effective on or before the opening balance's date, REFUSAL_REASON_LOTS_UNBALANCED for an entry that would leave a position's open lots not summing to it, REFUSAL_REASON_LATER_ENTRIES_STAND for a reversal of the opening balance while a later entry moves the account's positions, REFUSAL_REASON_IDEMPOTENCY_CONFLICT.
  • ValueError for more than one of the four, and TypeError or ValueError for a number or an amount, named by its path.
  • 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.
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:

last = await role.list_trades(subjects=streamed, latest_recorded=True)

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.

latest = await role.list_quotes(subjects=held)      # BTC in USD and in USDC on one venue: both

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.

async def record_outcomes(self, *, outcomes: Sequence[Outcome] = ()) -> RecordOutcomesResult
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).

async def list_datasets(self) -> ListDatasetsResult
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.

async def list_source_priorities(self) -> ListSourcePrioritiesResult
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 entry and its journal reference: an order's commands answer the order; a placement's, the placement; a report, whichever records it changed (placement, execution, order, charge) or, where the book could not place it, the unplaced fact; and a change, its change_request_id. It is answered only after its entry commits.
  • Every command but a fact report acts for someone: pass acting_for=request.caller.header for a person, or call it from an act reached for the role's service account. One with nobody behind it is refused REFUSAL_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 the oms's, placements the ems's, fills the connectivity plugin's. A connectivity plugin's record_order or create_placement is 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_execution naming no placement), which the ems accepts (accept_execution) or answers DK (dont_know_execution).
  • Idempotency. A command naming an idempotency_key is applied once for it; the same key on another command is refused REFUSAL_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 CommandRefused with 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.

async def read_agent_orders_demo_only(self) -> ReadAgentOrdersDemoOnlyResult
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.

async def run_job(self, *, job: Job | None = None) -> RunJobResult
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.

async def list_measure_definitions(self) -> ListMeasureDefinitionsResult
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.

async def list_price_batches(self, *, after_sequence: int = 0) -> ListPriceBatchesResult
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.

async def list_finished_jobs(self, *, after_sequence: int = 0) -> ListFinishedJobsResult
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.

async def read_job_answer(self, *, job_id: str = "") -> ReadJobAnswerResult
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.

async def read_stale_reference_actions_permitted(self) -> ReadStaleReferenceActionsPermittedResult
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_order takes a fixed-income limit, price_basis with limit_yield or limit_spread_bps and the benchmark_instrument_id a spread is over; a single option or future order states its position_effect.
  • report_execution takes a fixed-income fill: price_basis and yield beside the dollar price per 100 of face, which price always 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 fields contra_party_type, parties, capacity, no_remuneration, affiliate_back_to_back, special_price with its special_price_reason, weighted_average_price, primary_market, list_offering_price_takedown, traded_flat, stipulated, portfolio_trade and treasury_trade_modifier.
  • Price, Trade and Quote take a PriceBasis of percent of par, yield or spread (with benchmark_instrument_id), and a capped size (Trade.quantity_capped, Quote.bid_size_capped).
  • list_trades, list_quotes and list_statistics take an expiration window, expiration_from and expiration_to, and fields, the dictionary entries a page shows, a field not asked coming back unset; list_series takes paths, the template paths a page draws; a want (ObservationsWantedEvent) carries series_keys, all_series and the expiration window.
  • read_job_answer is read a page at a time, page_size and cursor, answering next_cursor.
  • record_derived_series is held by data as well as signal.
  • A quality assessment names its data type, a derived value in money is money_value, DatasetRef counts its valid, suspicious and invalid rows, and a quarantined dataset is answered UNANSWERED_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.