Skip to content

Schemas

The shapes the server sends and accepts. Each type links to its own entry.

ActiveRiskPayload

How tracking error against a benchmark divides among active positions.

Contributions sum to tracking_error exactly, the same identity the total decomposition satisfies — on active weights rather than holdings.

Field Type Required Description
benchmark string yes Index the comparison is against.
contributions_not_held map of string to number no Contributions from benchmark constituents the index does not hold. They have no row in the weights table but are often the largest active positions there are, so omitting them would hide the biggest sources of tracking error.
covered_weight number yes Share of gross active weight the model covers. Gross because active weights sum to roughly zero, so a plain sum would say nothing about coverage.
tracking_error number yes Annualised volatility of the active position.
uncovered array of string no Names with no estimate, from either side.
window_end string or null no Last date of the run's own level series, YYYY-MM-DD, on the same terms as window_start, which is the other end: a bound given to the price fetch, unchanged by what the store actually held.
window_start string or null no First date of the run's own level series, YYYY-MM-DD — the span the price fetch behind this estimate was given, not the dates prices came back on. It does not narrow: when the store covers less, the covariance is estimated from fewer observations and this still reports the run's span, so it is a bound rather than a measurement. Null when the run carries no level series. window_end is the other end.

AllNode

Every operand must pass: expressions.core.All.

Field Type Required Description
node "all" yes Discriminator. Always 'all'.
operands array of ExpressionNode yes The expressions that must all pass.

AnyNode

At least one operand must pass: expressions.core.Any_.

Field Type Required Description
node "any" yes Discriminator. Always 'any'.
operands array of ExpressionNode yes The expressions, any of which may pass.

AssetView

Response of GET /beacon/{index_id}/assets/{identifier}.

Field Type Required Description
beta number yes
correlation number yes
excess_return number yes
identifier string yes
index_id string yes
index_return number yes
observations integer yes
price SeriesPayload yes
raw_weight_history map of string to number no The same dates -> the weight before capping. Added alongside weight_history rather than replacing it, so the drilldown can show what the cap did to this name over time without breaking a client reading only the applied series.
rebalances_held integer yes
total_return number yes
tracking_error number yes
weight_history map of string to number yes Rebalance date -> this name's applied weight. Only the rebalances it was actually in.

AttributionView

Response of GET /beacon/{index_id}/attribution.

Contributions are Carino-linked, so they sum to the compounded total return rather than approximately to it. residual is reported regardless and should sit at machine epsilon; anything larger means an assumption broke upstream, which is worth surfacing rather than rounding away.

Field Type Required Description
cap_drag number or null no Capped return minus uncapped. Null on an uncapped index: reporting 0.0 would claim capping happened and made no difference.
contributions array of ContributionPayload yes
cost_drag number or null no Direct effect of transaction costs. Null at zero cost.
end string yes Last date a contribution was computed for, in the same full ISO-8601 form as start. Resolved: the latest date the run covers at or before the requested end, which requested_end echoes. start is the other end.
index_id string yes
periods integer yes
reconciles boolean yes
requested_end string or null no The window's last date as asked for, YYYY-MM-DD, on the same terms as requested_start, which is the other end: the end query echoed unchanged, or the run's own last date when none was given. end is the resolved counterpart.
requested_start string or null no The window's first date as asked for, YYYY-MM-DD: the start query echoed back unchanged, or the run's own first date when the query was omitted, which is what the window then defaulted to. It does not resolve — no data moves it — so it is the field to label a range with. start is the resolved counterpart and is a trading day later. Null only when the query was omitted and the run carries no level series to default from. requested_end is the other end.
residual number yes
start string yes First date a contribution was computed for, as a full ISO-8601 timestamp. Resolved, and one trading day later than the window's own first date: a period's return is earned by the weight held at its start, so the first date in the window has no complete period behind it and is dropped. requested_start carries the window that was asked for, in YYYY-MM-DD; this is not that date. end is the other end.
total_return number yes

BacktestJobStatus

A backtest:{index_id} job. result is the run payload.

Field Type Required Description
error ErrorDetail or null no Failure reason, when status is failed; null otherwise. The same {code, message, detail} a non-2xx response carries, and the same schema — so a failed job branches on error.code exactly as an HTTP error does (BN-199). It was a bare string until then, which left the job path the one place a deliberate refusal and a crash looked alike. A job that failed before this carries UNCLASSIFIED_FAILURE: its message was recorded, its code was not, and the migration does not guess one.
job_id string yes
kind string yes What the job is, e.g. 'backtest'.
message string no Latest progress message. Default: "".
progress number yes Fraction complete, 0.0 to 1.0.
result BacktestRunResult or null no Present only once the job has succeeded; null otherwise.
status string yes pending, running, succeeded, failed or cancelled. The last three are terminal.

BacktestMetrics

Headline metrics from a backtest run.

Tracking figures are null when the run had no target index to compare to.

Field Type Required Description
annualised_return number yes Fraction, not percent: 0.0523 means 5.23%.
max_drawdown number yes Fraction, not percent: 0.0523 means 5.23%.
sharpe_ratio number yes
total_return number yes Fraction, not percent: 0.0523 means 5.23%.
tracking_difference number or null no
tracking_error number or null no
volatility number yes Fraction, not percent: 0.0523 means 5.23%.

BacktestRecordCollection

Response of GET /beacon/backtests.

An envelope rather than the bare array this used to return (BN-174). The rows could not carry the skip count, and a listing that leaves documents out without saying how many is making the same class of false statement as a listing that 500s: the client is told something complete that is not.

Field Type Required Description
backtests array of BacktestRecordRow yes
skipped integer no Stored documents the server could not read, and so left out of this listing. Non-zero means the collection is incomplete: the fault is logged server-side, and each skipped document answers 404 on its own route. Default: 0.
skipped_causes SkippedCauses no The same documents as skipped, by cause, so the listing can say what to do about them. Its three counts sum to skipped.

BacktestRecordRow

One stored backtest record, as a listing knows it (BN-162).

The row is deliberately thin — the id to fetch the record by, and when it was captured. Names come from the index catalogue the client already holds, and everything else from /beacon/{index_id}/record.

Field Type Required Description
index_id string yes
run_at string or null no ISO-8601 UTC capture time; null on records written before they were stamped.

BacktestRequest

Body of POST /beacon/{index_id}/backtest.

Field Type Required Description
benchmark BenchmarkRef or null no Optional external benchmark. The tracked index is always reported separately; this adds a second comparison.
end string or null no End date, YYYY-MM-DD.
initial_capital number no Default: 1000000.0.
start string or null no Start date, YYYY-MM-DD. Defaults to the index base date.
transaction_cost_bps number no Cost per trade in basis points of notional. Default: 0.0.

BacktestResultSummary

Serialised view of a BacktestResult, in the shape of its books.

The nested shape mirrors the library object (BN-155): one home per fact, and the new data — positions, daily index weights — has a natural place instead of being bolted flat beside old names. Books the run did not have (no benchmark given, no index calculated) are null rather than empty, so a client can tell "not measured" from "measured and empty". Since BN-164 index is a container of two books, {target, optimised}, matching the library's IndexBooks.

Field Type Required Description
benchmark BookPayload or null no
index IndexBooksPayload no
metrics BacktestMetrics yes
portfolio PortfolioBookPayload yes
price_gaps array of PriceGapPayload no Days a holding or a target name had no bar on a session its index's calendar says was open, and was therefore marked at a carried-forward price. Empty on a run with complete data — a market holiday is not a gap, since nothing is missing on a day nothing traded. A non-empty list is the signal that some marks are stale quotes rather than that day's market, which is otherwise invisible in the NAV.
rebalance_pricing array of RebalancePricingPayload no What each rebalance priced from, in date order. date and priced_from differ only where the schedule landed on a day the market was shut, so the run states which session its trades were struck at rather than leaving it inferable from the weight snapshots.
run_at string or null no When this record was captured, ISO-8601 UTC with an offset — wall-clock at the moment the finished run was serialised, within a second of the backtest completing. Not a market date, and not the period the backtest covered: that span is the index of portfolio.nav. BacktestRecordRow.run_at on GET /beacon/backtests is the same stamp. Null only on records written before BN-162 began stamping them.
unfilled array of UnfilledOrderPayload no

BacktestRunResult

Result payload of a completed backtest job.

Every series here derives from the same NAV, rebased to 100: returns is the level's percentage change, drawdown is the level against its running peak, and annual_returns compound back to the total. A client that recomputes any of them lands on these numbers exactly.

Field Type Required Description
annual_returns map of string to number yes Calendar year -> return. Compounds to total_return.
benchmark RelativeMetricsPayload or null no Comparison against the requested external benchmark, if one was given. Null otherwise; metrics.tracking_error still reports replication accuracy against the tracked index either way.
drawdown SeriesPayload yes Level against its running peak; 0 at a new high.
index_level SeriesPayload yes The tracked index, rebased to 100 on the same axis. Named benchmark_level before BN-155; renamed because the tracked index and the benchmark of record are different comparators, and this series is the former.
initial_capital number no Capital the simulation started with. Default: 0.0.
level SeriesPayload yes Portfolio value, rebased to 100.
metrics BacktestMetrics yes
price_gaps array of PriceGapPayload no Days a holding or a target name had no bar on a session its index's calendar says was open, and was therefore marked at a carried-forward price. Empty on a run with complete data — a market holiday is not a gap, since nothing is missing on a day nothing traded. A non-empty list is the signal that some marks are stale quotes rather than that day's market, which is otherwise invisible in the NAV.
rebalance_pricing array of RebalancePricingPayload no What each rebalance priced from, in date order. date and priced_from differ only where the schedule landed on a day the market was shut, so the run states which session its trades were struck at rather than leaving it inferable from the weight snapshots.
rebalances array of RebalanceSnapshot no Composition at each rebalance. Everything the view endpoints say about weights, attribution and individual names is derived from these, so a run is readable without recalculating the index. Daily weights are deliberately absent: they are reconstructed from these and the prices, and storing one per name per day would multiply the payload by the number of trading days to save an inexpensive calculation.
returns SeriesPayload yes Period returns of level.
total_costs number no Transaction costs paid across the run, for the cost drag. Default: 0.0.

BatchReferenceResponse

Response of GET /data/reference.

Entries are in the order the request named them, one per identifier, so a table can render straight down the list without re-sorting against what it asked for.

Field Type Required Description
as_of string or null no Point-in-time date applied, if one was requested.
entries array of ReferenceEntry yes

BenchmarkRef

What to compare a backtest against.

Distinct from the index being tracked. The tracked index measures replication accuracy; a benchmark measures relative performance against something the portfolio was never trying to replicate.

Field Type Required Description
id string yes Index id, or market-data identifier.
kind one of "index", "identifier" yes 'index' for a stored index definition, 'identifier' for a market-data series.
price_column string no Market-data column to read. Ignored when kind is 'index'. Default: "CLOSE".

BookPayload

One comparator's record on the wire.

Two different facts about weights, not two copies of one (BN-173): weights is the daily panel — what the book actually HELD each day, drift included — and rebalances is what each rebalance DECIDED. They agree only on a rebalance date; everywhere else prices have moved the held weights away from the decided ones. A client wanting decided weights reads rebalances rather than resampling the panel, which cannot answer what capping cost whatever it is resampled onto.

Field Type Required Description
calendar_coverage CalendarCoveragePayload or null no Set only when the index's calendar could not cover the whole requested range, in which case levels spans covered_start to covered_end rather than the dates asked for. Null on an ordinary run, and on a comparator supplied as a bare level series, which has no calendar of its own. A range the calendar could cover none of refuses instead, so it never arrives here.
levels SeriesPayload yes
rebalances array of RebalanceSnapshot no What each rebalance decided — applied weights, their uncapped counterparts and the announcement date — in date order; most recent MAX_REBALANCES at most. The same rows the run payload publishes, kept here because the record is what survives the job result. Empty for a comparator supplied as a bare level series, which decided nothing.
rebalances_total integer no Rebalances the index actually had; larger than the rows served when the list was truncated. Default: 0.
weights TableFrame yes Daily weights, dates by identifier; most recent MAX_WEIGHT_DATES dates at most. Empty for a comparator supplied as a bare level series.
weights_dates_total integer yes Dates the book's daily weights panel actually covers — a count, not a date. Larger than the rows in weights whenever the panel was truncated to its most recent MAX_WEIGHT_DATES, and 0 for a comparator supplied as a bare level series. rebalances_total says the same thing for rebalances.

CalendarCoveragePayload

The window asked for beside the one the calendar could offer (BN-198).

Present only when the calendar narrowed the run, so its presence is the signal. A window the calendar covers nothing of never reaches a result at all — that refuses, because an empty index is a failure wearing a success.

Field Type Required Description
calendar string yes MIC of the calendar that narrowed the range.
covered_end string yes Last date the calendar could speak for, ISO 8601.
covered_start string yes First date the calendar could speak for, ISO 8601. The index has no level before this.
requested_end string yes Last date the run asked for, ISO 8601.
requested_start string yes First date the run asked for, ISO 8601. Not the date it produced — see covered_start.
trimmed_end boolean yes Whether the calendar's published sessions stop before requested_end. A different remedy from trimmed_start: the sessions do not exist yet rather than not at all.
trimmed_start boolean yes Whether the calendar's history does not reach back to requested_start. Published so a client never compares dates to find out; the remedy is a different calendar or a later base date.

CalendarList

Response of GET /indices/calendars.

IndexDocument.calendar is required (BN-180), so a client that cannot see the accepted set has two bad options: hard-code a hundred-odd MICs, or ship a free-text box that now fails a 422 on a mandatory field. This publishes what the engine accepts, the way /indices/rule-types and /optimise/constraint-types do — read from exchange_calendars at request time, never a hand-kept copy, so the wire set cannot drift from the set the calculation schedules on.

Field Type Required Description
calendars array of CalendarOption yes Every exchange MIC this server can schedule against, sorted by code, each with what a picker needs to render it. Around a hundred entries; served whole rather than paged, because a picker wants all of them and the payload is a few kilobytes.
default string yes The calendar code to preselect. The same value stored documents without a calendar were migrated to, so it is a reasonable default for a new index rather than an arbitrary one — but it is a suggestion for the form, not a server-side fallback: IndexDocument.calendar has no default and omitting it is a 422.

CalendarOption

One selectable trading calendar, as GET /indices/calendars serves it.

Every field is derived from exchange_calendars at request time except name, which is curated and falls back to the code. Nothing here is a hand-kept table of the calendar set itself, so the options a client offers cannot drift from the calendars the schedule accepts.

Field Type Required Description
code string yes The exchange MIC, e.g. 'XNYS'. This is the value to send as IndexDocument.calendar; everything else on this row is for display.
name string yes Display name, e.g. 'New York Stock Exchange'. Curated for the major venues only and falls back to code for the rest — exchange_calendars carries no friendly names, so a partial list that degrades to the MIC is the honest option. A row where name equals code is an uncurated calendar, not a broken one.
region string yes Derived, not curated: the first segment of the calendar's own IANA timezone, so 'Europe/Oslo' gives 'Europe'. A noun as the tz database spells it — group headings are the client's wording, since 'Atlantic' and 'Pacific' have no distinct adjective and a mapping to one would be the hand-kept table this field exists to avoid. Two calendars sit on bare UTC and so report 'UTC', which is not a region; that is deliberate rather than a gap, and whether it becomes an 'Other' heading is the client's call.
tz string yes The calendar's full IANA timezone, e.g. 'America/New_York'. Carried because region throws away the rest of it, and a client showing session times needs the whole zone.

CarryDecomposition

Carry split into the pieces a person can reason about.

Each part is the price effect of one rate acting alone. They do not sum to the total exactly, because carry compounds rather than adds; the residual is reported rather than spread across the parts, which would make each of them slightly wrong in order to hide that the split is approximate.

Field Type Required Description
borrow number yes
dividend number yes Negative: dividends reduce the forward.
financing number yes
residual number yes Total minus the three parts — the compounding the decomposition cannot attribute.
total number yes Fair value minus spot.

ChangelogEntryView

One release of the engine.

Field Type Required Description
date string or null yes Release date, YYYY-MM-DD. Null for Unreleased.
sections array of ChangelogSectionView yes What changed, grouped by kind of change. Empty for an Unreleased entry with nothing in it yet.
version string yes e.g. '0.1.0', or 'Unreleased'.

ChangelogResponse

Response of GET /changelog.

Field Type Required Description
entries array of ChangelogEntryView yes Newest first, leaving out any with no changes listed. With since, only the releases after that version.
version string yes The running engine's version, the same value /health reports.

ChangelogSectionView

One heading under a release and its items.

Field Type Required Description
heading string yes Added, Changed, Fixed, Removed, Deprecated or Security.
items array of string yes One change each, as markdown.

CompareEntry

One index within a comparison, on the shared window.

Field Type Required Description
index_id string yes
level SeriesPayload yes Rebased to 100 on the first shared date, so lines start together and the comparison is of shape, not scale.
total_return number yes

CompareView

Response of GET /beacon/compare.

Field Type Required Description
end string yes Last date every index covers, YYYY-MM-DD. Resolved by the same intersection as start, which is the other end: one index whose run stops early pulls this back for all of them.
entries array of CompareEntry yes
index_ids array of string yes
observations integer yes Dates every index covers. Fewer than any one of them carries alone whenever their spans differ.
start string yes First date every index in index_ids covers, YYYY-MM-DD — the intersection of their level series, not the earliest start among them. Resolved: one index whose history begins later moves this forward for all of them, which is why each entry's level is rebased from here. Nothing was requested — GET /beacon/compare takes only ids — so there is no window to echo. end is the other end of the same shared span.

ComparisonNode

A field, an operator and a value: expressions.core.Comparison.

Field Type Required Description
comparison one of "gt", "ge", "lt", "le", "eq", "ne", "in", "between" yes How the field is compared to the value, spelled as the stored document spells it: gt, ge, lt, le, eq, ne, in, between.
field FieldNode yes The datapoint being compared.
node "comparison" yes Discriminator. Always 'comparison'.
value any yes

ConcentrationPayload

How concentrated a weight vector is.

Field Type Required Description
constituents integer yes
effective_assets number yes 1/HHI: how many equally weighted names would be as concentrated. Lower than the raw count whenever weights are uneven.
herfindahl number yes Sum of squared weights.
largest number yes Largest single weight.
top_weights map of string to number yes Combined weight of the largest N, keyed by N.

ConstituentRow

One constituent's row in the weights table.

Everything a row needs is here, so the table renders from one response rather than joining three. The two weights are the point: raw_weight is what the weighting scheme produced, weight is what survived the cap, and the difference is what capping moved.

Field Type Required Description
active_risk_contribution number or null no This name's share of tracking error. Can be negative: an underweight that hedges an overweight genuinely reduces tracking error, and hiding that behind an absolute value would misreport what the index is doing.
active_weight number or null no Weight minus the benchmark's, when a benchmark was given. Negative is an underweight.
capped boolean no Whether this name was held at the cap on this rebalance. Default: false.
delta_since_rebalance number or null no Held weight minus target weight, for this name, as of as_of. Null when as_of is the rebalance date itself: the weights were just set, so nothing has drifted and a zero would claim a measurement rather than its absence.
identifier string yes
raw_weight number yes Weight before capping. Equal to weight on an uncapped index, and the only way to see what the cap cost.
risk_contribution number or null no This name's share of the index's annualised volatility, in the same units. Populated only when risk=true was requested; null also when the risk model has no estimate for this constituent, which risk.uncovered lists.
shares_outstanding number or null no The company's shares outstanding on this date, from market data. Deliberately NOT the number of shares the index holds — that is a different figure needing a divisor and a notional, and naming this one shares would let the two be confused silently.
weight number yes Applied weight, after any cap.

ConstraintRow

One constraint, in the shape a client's editor holds it.

Maps 1:1 to a class in beacon.optimise.constraints: the row a user edits, the JSON that is stored and the object the solver receives are the same thing in three representations, so a rule cannot change meaning in translation.

Field Type Required Description
id string no Stable row id. Carried back on any binding constraint so a client can highlight the row that bound. Default: "".
params object no Constructor arguments for that class, by name.
type string yes Constraint class, e.g. 'PositionBounds'.

ConstraintSet

A named list of constraints.

Field Type Required Description
constraints array of ConstraintRow no
id string yes Stable identifier, used in the URL.
name string yes Display name.

ConstraintSetCollection

Response of GET /optimise/constraint-sets.

Field Type Required Description
constraint_sets array of ConstraintSet yes
skipped integer no Stored documents the server could not read, and so left out of this listing. Non-zero means the collection is incomplete: the fault is logged server-side, and each skipped document answers 404 on its own route. Default: 0.
skipped_causes SkippedCauses no The same documents as skipped, by cause, so the listing can say what to do about them. Its three counts sum to skipped.

ConstraintTypes

Response of GET /optimise/constraint-types.

Served so a client builds its editor from the same source the solver reads, rather than from a copy that drifts.

Field Type Required Description
specs array of TypeSpec no The same constraint types in the richer shape /indices/rule-types uses, so one client component can render both editors.
types map of string to array of string yes Constraint type -> the parameters it accepts. Kept for clients written against the original shape; specs carries the same set with everything needed to render it.

ContributionPayload

One constituent's share of the index return.

Field Type Required Description
asset_id string yes
average_weight number yes
contribution number yes
total_return number yes

CorporateAction

One corporate action.

kind is the authoritative answer to what value means, and the reason a client needs no list of type strings. Reading type and inferring cash or ratio from a hardcoded list works until a type the client has never seen arrives, at which point it renders as whichever the list defaults to — confidently, and wrongly.

Field Type Required Description
ex_date string yes Ex-date, ISO 8601.
kind one of "cash", "ratio", "structural" yes What value means. 'cash' is an amount per share and adds up; 'ratio' is a share-count multiplier and compounds; 'structural' (rights issue, spin-off, merger) carries no directly aggregable value and should not be rendered as a quantity in either column.
pay_date string (date) or null no Payment date, ISO 8601, where the source knows it. Null means unknown — omit the field in the UI rather than dashing it, since a dash reads as 'there is none'.
status one of "announced", "paid", "cancelled" or null no Lifecycle state, where the source knows it. Null means unknown, not 'not yet announced'.
type string yes Action type, e.g. DIVIDEND or SPLIT. A closed set the engine validates on load, but branch on kind rather than on this: new types are added, and a client that matches type strings breaks silently when one is.
value number yes Cash amount per share for cash actions; a share-count multiplier for ratio actions. What it means depends on kind, so the two are never summed together.

CorporateActionsResponse

Response of GET /data/corporate-actions/{identifier}.

Carries the raw history and the two aggregates that need the whole series to compute, so a client asking "what did this pay" does not have to reimplement the trailing window and get its boundary subtly wrong.

Field Type Required Description
actions array of CorporateAction no
cumulative_split_ratio number no Compounded share-count multiplier across the returned window. 1.0 when there were no splits. Default: 1.0.
identifier string yes
trailing_dividend number no Ordinary dividends per share over the twelve calendar months ending at the as-of date. Default: 0.0.
trailing_dividend_yield number or null no Trailing dividend over the close on the as-of date. Null when no price is available — a missing price is a reason to say nothing rather than to guess.

CoverageResponse

Response of GET /data/coverage.

Field Type Required Description
cache_size_bytes integer or null no Total bytes on disk for the whole store. Null when no store backs this process.
datasets array of DatasetCoverage yes
identifiers_union integer no Distinct identifiers across every dataset. Not the sum of the per-dataset counts: a name present in both market and reference data would otherwise be counted twice, and 'assets covered' would exceed the universe. Default: 0.

DatasetCoverage

What the loaded data actually spans, for one dataset.

Field Type Required Description
cache_age number or null no Seconds since this dataset was last loaded or synced. Null when the dataset is not loaded at all, which is a different statement from 'loaded and never refreshed'.
cache_size_bytes integer or null no Bytes the backing store occupies on disk. Null when the data did not come from a store, in which case it has no size to report rather than a size of zero.
configured boolean yes Whether this dataset is loaded.
dataset string yes 'market' or 'reference'.
end string or null no Latest date held, ISO 8601.
field_count integer no Data columns this dataset holds, excluding the identifier and date keys. Default: 0.
frequency string no How often this dataset is expected to change: 'daily', 'static' or 'event'. The engine's definition of what stale means, so a client renders staleness from this rather than from thresholds of its own. Default: "static".
identifiers integer yes Distinct identifiers present.
last_refreshed string or null no When this dataset was last loaded or synced, ISO 8601. Carried alongside the age because an age is only meaningful at the instant it was read, and a client holding a response for a minute needs the timestamp.
source string or null no Where the data was loaded from, e.g. 'synthetic', 'yfinance', 'local'. Null when a fetcher was assembled in-process and nothing recorded a provenance.
stale_after_seconds number or null no Age beyond which this dataset should read as stale. Published so the mapping from frequency to a duration lives in one place; null means the question does not apply, as for static data.
start string or null no Earliest date held, ISO 8601.

DataSourceStatus

Whether this process has a data source, and how much it covers.

Field Type Required Description
configured boolean yes True when a DataFetcher is attached.
identifiers integer yes Distinct identifiers in market data.

DeletedIndex

One index a delete removed, and what went with it.

Field Type Required Description
backtest_record_deleted boolean yes Whether a stored backtest record went with it.
backtest_results_deleted integer yes How many job records and persisted run results were forgotten with it.
derived_from string or null no The index this one was derived from, when it went as an optimised child. Null for the index the request named.
index_id string yes The index that was removed.

DerivationPayload

How an optimised index is derived from the index it was built on.

The whole of an optimised index's methodology: the source it reallocates, what the solve minimises, and what the answer must satisfy. No weights — neither the parent's nor the solved ones — because definitions are rules and weights are calculated.

Field Type Required Description
constraints array of ConstraintRow no What the solved weights must satisfy — exactly the rows /optimise/constraint-sets stores, so one editor serves both. Empty leaves the solver's own full-investment default.
objective string no What the solve minimises. Accepted values: min_tracking_error. A plain string rather than an enum so a risk-model objective can be added without a wire break; an unknown value is refused with a finding naming the accepted set. Default: "min_tracking_error".
source_index_id string yes Id of the index this one optimises. Immutable after creation: re-pointing a derivation is a new index, not an edit, so an update that changes it is refused.

DriftPayload

How far weights moved between two rebalances.

Field Type Required Description
maximum number yes Largest single move.
since string yes The rebalance drifted from.
total_absolute number yes Sum of absolute weight changes.
turnover number yes Half the total: the one-way trading needed to return to target, since every overweight funds an underweight.
worst string yes Constituent that moved most.

ErrorDetail

The body of an error envelope.

Field Type Required Description
code string yes Stable machine-readable code; safe to branch on.
detail object or null no Structured context, e.g. the offending field or rule. An UNEXPECTED_CALCULATION_FAILURE additionally carries 'original_type': the class name of the exception that failed, so a crash can be told apart from a refusal without reading a server log.
message string yes Human-readable summary.

ErrorEnvelope

Every non-2xx response uses this shape.

Field Type Required Description
error ErrorDetail yes

ExposuresView

Response of GET /optimise/runs/{run_id}/exposures.

Factors are the ones derivable from price and share count — size, momentum, volatility — plus a market intercept. Value and quality are absent rather than approximated: a momentum factor built from prices is the real thing, a value factor faked without book values would not be.

Field Type Required Description
active_exposures array of FactorExposure yes
factors array of string yes
index_exposures array of FactorExposure yes
optimal_exposures array of FactorExposure yes
r_squared number yes Read against a floor of roughly k/n rather than against zero: fitting k factors to an n-asset cross-section explains about that much by construction.
risk RiskDecomposition yes
run_id string yes

ExpressionNode

One node of a serialised expression, discriminated on node.

The grammar a screen is written in: a field, a comparison over one, or a boolean composition of either. Recursive — all, any and not carry nodes of this same union — so an arbitrarily nested screen is one type.

A RootModel rather than a bare union so the union is a named schema in this document: a recursive $ref needs a name to point at, and so does ParameterSpec.ref.

Type: FieldNode or ComparisonNode or AllNode or AnyNode or NotNode

FactorExposure

One factor loading.

Field Type Required Description
exposure number yes
factor string yes

FeatureBatchEntry

One instrument in a batch feature response.

Field Type Required Description
features array of FeatureValue yes
identifier string yes

FeatureBatchResponse

Response of GET /data/features.

Field Type Required Description
as_of string yes The cutoff the features were read at, YYYY-MM-DD: the date query echoed back unchanged, or the last date the loaded market data carries when none was given. Never resolved back — a request for a weekend stays a weekend — because each feature independently takes the latest row published on or before it. What was actually read is each entries[].features[].date, the announcement date of the row that answered, which is usually earlier than this and differs from feature to feature. FeatureResponse.as_of is the same field on the single-instrument endpoint.
entries array of FeatureBatchEntry yes

FeatureCatalogue

Response of GET /data/features/catalogue.

What a client populates its controls from. Derived from the loaded data rather than a fixed vocabulary, so a dataset somebody loads tomorrow becomes a filter without a code change.

Field Type Required Description
fields array of string yes Every field across every dataset. Names collide where two datasets carry the same one, which is why the per-type lists above exist.
types array of FeatureTypeCoverage yes

FeatureImport

Body of POST /data/features.

Field Type Required Description
rows array of FeatureRow yes Field-value rows. Merged into whatever is already loaded; a row matching an existing identifier, date, type and field replaces it.

FeatureImportResult

What an import did.

Field Type Required Description
accepted integer yes
identifiers integer yes
types array of string yes Datasets the import touched.

FeatureResponse

Response of GET /data/features/{identifier}.

Field Type Required Description
as_of string yes The cutoff the features were read at, YYYY-MM-DD: the date query echoed back unchanged, or the last date the loaded market data carries when none was given. Never resolved back — a request for a weekend stays a weekend — because each feature independently takes the latest row published on or before it. What was actually read is each features[].date, the announcement date of the row that answered, which is usually earlier than this and differs from feature to feature. FeatureBatchResponse.as_of is the same field on the batch endpoint.
features array of FeatureValue yes
identifier string yes

FeatureRow

One row of an import.

Field Type Required Description
date string (date) yes Calendar date, YYYY-MM-DD.
detail string or null no
field string yes
identifier string yes
type string yes
value number yes

FeatureTypeCoverage

One feature dataset, and how much of it is present.

Field Type Required Description
fields array of string yes
identifiers integer yes Instruments this dataset covers.
rows integer yes
type string yes

FeatureValue

One field and what it was worth.

Field Type Required Description
date string or null no When the value became knowable — the announcement date, not the period it describes.
detail string or null no Free-form context the dataset carried.
field string yes
type string or null no Which dataset it came from.
value number or null yes Null when nothing was knowable on the date: no coverage, nothing published yet, or nothing recent enough.

FieldCatalogue

Response of GET /data/fields.

Every datapoint an expression can name, from one place, so a client builds one field picker rather than one per dataset. Derived from the loaded store, so a column or dataset nobody declared still appears.

Field Type Required Description
fields array of FieldDescriptor yes
namespaces array of string yes

FieldDescriptor

One datapoint a client can offer as a filter.

Field Type Required Description
dataset string or null no Feature TYPE, for feature fields only.
derived boolean no Computed per request rather than stored. Screenable either way — a client should not have to care. Default: false.
name string yes
namespace string yes market, reference, actions or features.
path string yes How it is written, e.g. 'reference.sector' or 'features.fundamentals.revenue'.

FieldNode

A named datapoint: expressions.core.Field.

namespace is the surface the value comes from and dataset narrows a feature to one vendor's TYPE, so two sources can both ship a revenue without collision.

Field Type Required Description
dataset string or null no Narrows a feature to one dataset. Null on a reference or market field, which have no dataset to narrow.
name string yes The datapoint's name.
namespace string yes The surface the datapoint comes from: 'reference', 'market' or 'features'. GET /data/fields lists what each one holds.
node "field" yes Discriminator. Always 'field'.

Finding

One validation result, addressable to the rule that caused it.

Field Type Required Description
code string yes Stable machine-readable code.
message string yes Human-readable explanation.
path string yes Dotted path to the offending field.
rule_id string or null no Id of the rule responsible, when there is one.
severity string yes 'error' blocks saving; 'warning' does not.

FrontierPoint

One portfolio on the efficient frontier.

Field Type Required Description
binding array of string no
expected_return number or null no
heuristic boolean no Default: false.
sharpe_ratio number or null no
volatility number yes
weights map of string to number yes

FrontierView

Response of GET /optimise/runs/{run_id}/frontier.

Field Type Required Description
expected_returns map of string to number yes Annualised historical mean returns, per name. A poor forecast, and the honest one: it is the only return estimate derivable from the data the server holds. A caller with a real view should supply it.
minimum_variance FrontierPoint yes
monotonic boolean yes Whether risk rises with return across the grid. Always true for a correct solve, so a false here means a point did not reach optimality.
points array of FrontierPoint yes
risk_free_rate number yes
run_id string yes
tangency FrontierPoint yes

FuturesPriceRequest

Body of POST /derivatives/futures/price.

Stateless: every input the calculation needs is here, and nothing is read from or written to storage.

Field Type Required Description
borrow_cost number no Continuous borrow or financing spread. Default: 0.0.
contract_multiplier number no Index points per contract. Default: 1.0.
contracts number no Number of contracts. Default: 1.0.
curve map of string to number or null no Zero-rate pillars as {tenor_in_years: rate}. A flat curve and a scalar rate give identical answers, so supplying one changes nothing unless the curve has shape.
dividend_yield number no Continuous dividend yield. Default: 0.0.
dividends array of array of any or null no Discrete cash dividends as (years_to_ex, amount). When present these are used instead of the continuous yield: the two are different models of the same thing and applying both would double-count.
expiry string (date) or null no YYYY-MM-DD.
grid_rates array of number or null no Columns of the sensitivity grid.
grid_tenors array of number or null no Rows of the sensitivity grid, in years.
market_price number or null no Quoted price, for the basis and implied repo. Both are null without one rather than computed against the theoretical value, which would make them identically zero.
risk_free_rate number no Continuously compounded financing rate. Ignored when curve is supplied. Default: 0.0.
spot number yes Spot price of the underlying.
time_to_expiry number or null no Years to expiry. Dates win when both are given, being the less ambiguous statement.
valuation_date string (date) or null no YYYY-MM-DD.

FuturesPriceResponse

Response of POST /derivatives/futures/price.

Field Type Required Description
basis number or null no Market minus theoretical, when quoted.
carry CarryDecomposition yes
contract_value number yes Fair value times multiplier times contracts.
fair_value number yes
financing_rate number yes Rate used, read off the curve.
implied_repo number or null no Financing rate the quoted price implies, when quoted.
market_price number or null no
sensitivity TableFrame yes Fair value across a tenor x rate grid, centred on this contract.
time_to_expiry number yes Years the contract was priced over, ACT/365 — what the calculation used, which is not always what the request sent. Computed from valuation_date to expiry when both were given, dates being the less ambiguous statement; the request's own time_to_expiry is echoed back only when the dates were omitted. Nothing is resolved against market data — this endpoint reads none.

HealthResponse

Response of GET /health.

Field Type Required Description
cache_age number or null no Seconds since the market data was last loaded or synced. Null only when no data source is configured — there is then nothing whose age could be reported.
data_source DataSourceStatus yes
free_float_backfill_days integer or null no How many days a free float carries forward over days with no reported value. Beyond it a float-adjusted index refuses rather than weight the name by its full market cap. 0 uses only a value dated that day; the default is 90. A modelling choice: it decides which float a name is weighted by. Null when no data source is configured.
fx_policy string or null no How this installation reads an exchange rate on a day the pair printed none: CARRY_FORWARD uses the last rate in force, EXACT_DAY refuses unless the rate is dated that day. A modelling assumption rather than a preference — the same holding converts to different money under the two, and every conversion in the library obeys whichever is set. Null when no data source is configured, since nothing is being converted.
max_price_staleness_days integer or null no How long a name may go without trading before this installation drops it from an index and from a backtest's targets. Null means keep everything regardless, which is the default and what the library did before the setting existed. A modelling choice, not a preference: it changes index membership, so two runs either side of a change are different indices. Also null when no data source is configured.
status string yes 'ok' when the process is serving.
version string yes Installed py-beacon version.

IdentifierMatch

One identifier a search or enumeration returned.

Field Type Required Description
currency string or null no Denomination, when reference data has one.
datasets array of string no Which datasets actually cover this identifier: 'market', 'reference', 'corporate_actions'. This is what lets a client offer a reference-only name in a reference view and mark it unavailable for prices, rather than suggesting something the engine cannot then serve.
exchange string or null no Listing venue, when reference data has one.
identifier string yes The symbol itself.
name string or null no Display name, or null when reference data carries none. A row without a name is still a useful suggestion, so it is returned rather than dropped.

IdentifierSearchResponse

Response of GET /data/identifiers.

Search when q is given, enumeration when it is not.

Ranking is decided server-side and is part of the contract: exact identifier, identifier prefix, name prefix, identifier substring, name substring, alphabetical within each. Once limit is applied a client cannot re-rank what it was not sent.

Field Type Required Description
identifiers array of IdentifierMatch no
total integer no Matches before limit, so a client can say 'showing 20 of 340'. Default: 0.
truncated boolean no Whether the limit hid anything. Derivable from total, but explicit beats arithmetic at a call site. Default: false.
version string no Fingerprint of the data this was built from, also served as the ETag. Changes only when a dataset syncs, so a client can cache an enumeration and revalidate cheaply. Default: "".

IndexBooksPayload

The run's calculated indices on the wire (BN-164).

Mirrors the library's IndexBooks: target is the index being aimed at, pre-optimisation; optimised is the solved index's own calculation, null until an optimised run fills it.

Field Type Required Description
optimised BookPayload or null no
target BookPayload or null no

IndexCollection

Response of GET /indices.

Field Type Required Description
indices array of IndexDocument yes
skipped integer no Stored documents the server could not read, and so left out of this listing. Non-zero means the collection is incomplete: the fault is logged server-side, and each skipped document answers 404 on its own route. Default: 0.
skipped_causes SkippedCauses no The same documents as skipped, by cause, so the listing can say what to do about them. Its three counts sum to skipped.

IndexDeletion

Response of DELETE /indices/{index_id}.

Everything the delete removed, so a client reports the outcome from the response rather than from its own prediction of the blast radius. The named index comes first, then each optimised child in the order the cascade reached it.

Field Type Required Description
deleted array of DeletedIndex yes
index_id string yes The index the request named.

IndexDocument

A stored index definition, in one of its two faces.

A document carries either a rule pipeline (pipeline and universe) or a derivation — never both, never neither. derivation is the discriminator: present, the index is optimiser-derived and its methodology is the derivation; absent, it is a rule pipeline over a universe.

A synthesised pipeline for optimised documents was considered and rejected (design record, "Document schema"): it would be a methodology nobody wrote and nobody can meaningfully edit.

Field Type Required Description
base_date string yes Base date, YYYY-MM-DD.
base_value number yes Index level on the base date.
calendar string yes Exchange MIC backing trading-day arithmetic, e.g. 'XNYS'. Required since BN-180, and the one field on this model that changed from optional to required. It used to default to null, meaning Monday to Friday — which schedules rebalances on 1 January, 4 July and 25 December, days no exchange has a session for. Stored documents without one were migrated to 'XNYS' by schema version 2. GET /indices/calendars publishes every value this server accepts, read from the calendar package itself, so a client renders a closed list instead of guessing a MIC.
currency string yes Index currency.
derivation DerivationPayload or null no Present on an optimiser-derived index, null on a rule-driven one. Its presence is the discriminator a client branches on.
description string or null no
effective_lag_sessions integer no Sessions between a rebalance being announced and its weights taking effect. Stored now, honoured by the calculator in BN-126; until then it is declared and not applied, and 0 is the behaviour in force. Default: 0.
id string yes Stable identifier, used in the URL.
name string yes Display name.
pipeline PipelineSpec or null no The rule pipeline. Present on a rule-driven index, null on an optimiser-derived one.
publication_time string or null no When the level is published, e.g. '18:00 America/New_York'. Display metadata: it says when a figure is released and changes no figure, so nothing in the calculation reads it.
rebalance_day_rule string no Which day of a scheduled month the rebalance falls on: FIRST_BUSINESS_DAY, LAST_BUSINESS_DAY or THIRD_FRIDAY. A date landing on a holiday rolls back to the previous session. Default: "FIRST_BUSINESS_DAY".
rebalancing_frequency string yes MONTHLY, QUARTERLY, SEMI-ANNUAL or ANNUAL. The cadence; rebalance_day_rule decides which day of the month.
return_type one of "PRICE", "TOTAL_RETURN", "NET_TOTAL_RETURN" no How returns accumulate. PRICE ignores distributions; TOTAL_RETURN reinvests them across the index by shrinking the divisor; NET_TOTAL_RETURN does the same after withholding tax. PRICE is the default, so an index defined before this existed is unchanged. Default: "PRICE".
universe UniverseRef or null no The investable set. Present on a rule-driven index, null on an optimiser-derived one, which reallocates exactly the names its source published.
withholding_tax_rate number no Fraction of each distribution withheld, for a net index. A flat index-level rate rather than a per-country table: a table is only as good as the country field behind it, and an unpopulated one produces a number that looks precise and is not. Ignored unless return_type is NET_TOTAL_RETURN. Default: 0.0.

JobCollection

Response of GET /jobs.

Untyped results on purpose: a listing spans every kind at once, so the per-kind arms buy a client nothing it can use without reading kind anyway. GET /jobs/{job_id} is where the typed result lives.

Field Type Required Description
jobs array of JobStatus yes
skipped integer no Stored documents the server could not read, and so left out of this listing. Non-zero means the collection is incomplete: the fault is logged server-side, and each skipped document answers 404 on its own route. Default: 0.
skipped_causes SkippedCauses no The same documents as skipped, by cause, so the listing can say what to do about them. Its three counts sum to skipped.

JobStatus

State of one background job, with an untyped result.

The name and the shape are unchanged from before BN-172, deliberately: JobStatus is already a published schema a client generates from, so the generic arrived as a new base rather than by renaming this to JobStatus_Any_. Still the right answer for a listing, which mixes kinds, and the fallback arm of AnyJobStatus for a kind nothing models yet.

Field Type Required Description
error ErrorDetail or null no Failure reason, when status is failed; null otherwise. The same {code, message, detail} a non-2xx response carries, and the same schema — so a failed job branches on error.code exactly as an HTTP error does (BN-199). It was a bare string until then, which left the job path the one place a deliberate refusal and a crash looked alike. A job that failed before this carries UNCLASSIFIED_FAILURE: its message was recorded, its code was not, and the migration does not guess one.
job_id string yes
kind string yes What the job is, e.g. 'backtest'.
message string no Latest progress message. Default: "".
progress number yes Fraction complete, 0.0 to 1.0.
result any no Present only once the job has succeeded; null otherwise.
status string yes pending, running, succeeded, failed or cancelled. The last three are terminal.

NotNode

The negation of an expression: expressions.core.Not.

Field Type Required Description
node "not" yes Discriminator. Always 'not'.
operand ExpressionNode yes

OptimisationJobStatus

An optimise:{run_id} job. result is the solved portfolio.

Field Type Required Description
error ErrorDetail or null no Failure reason, when status is failed; null otherwise. The same {code, message, detail} a non-2xx response carries, and the same schema — so a failed job branches on error.code exactly as an HTTP error does (BN-199). It was a bare string until then, which left the job path the one place a deliberate refusal and a crash looked alike. A job that failed before this carries UNCLASSIFIED_FAILURE: its message was recorded, its code was not, and the migration does not guess one.
job_id string yes
kind string yes What the job is, e.g. 'backtest'.
message string no Latest progress message. Default: "".
progress number yes Fraction complete, 0.0 to 1.0.
result OptimisationRunResult or null no Present only once the job has succeeded; null otherwise.
status string yes pending, running, succeeded, failed or cancelled. The last three are terminal.

OptimisationRunRequest

Body of POST /optimise/runs.

Field Type Required Description
as_of string or null no Which rebalance to target, YYYY-MM-DD. Defaults to the latest.
constraint_set_id string yes Constraint set to solve under.
end string or null no End of that window.
index_id string yes Index whose weights are the target.
risk_free_rate number no Used for the frontier's tangency point. Default: 0.0.
start string or null no Start of the window the risk model is estimated over.

OptimisationRunResult

Result payload of a completed optimisation job.

Field Type Required Description
active_sum number yes Sum of the active weights. Zero under full investment: rearranging weight cannot create any.
binding array of map of string to string or null no Constraints the answer sits on, each traced back to the row that produced it where one can be identified. These are the rules that actually cost something.
constraint_set_id string yes
converged boolean yes
end string yes Last date the constituent price frame carries, YYYY-MM-DD, resolved on the same terms as start, which is the other end: earlier than the requested end whenever the store stops short of it.
heuristic boolean yes True when a non-convex constraint forced a restricted re-solve, so the answer is feasible but not proven optimal.
holdings integer yes
index_id string yes
iterations integer yes
objective number yes
run_id string yes
solver_message string yes
start string yes First date the constituent price frame actually carries, YYYY-MM-DD — the window the risk model behind this solve was estimated over. Resolved rather than echoed: the request's start is a bound on the fetch, and this is later than it whenever the store does not reach back that far. end is the other end.
tracking_error number yes
turnover number yes One-way, against the index weights.
weights array of WeightRow yes Every name, largest active position first.

OptimiseRequest

Body of POST /indices/{index_id}/optimise.

Everything the derived index needs that the parent cannot supply. The source is deliberately absent: provenance is server-truth, taken from the URL, so a client cannot assert a parentage the server did not create.

Field Type Required Description
constraints array of ConstraintRow no What the solved weights must satisfy. Validated through the same catalogue /optimise/constraint-sets uses, so a bad row is refused here naming the row.
description string or null no Optional description for the derived index. Null inherits nothing — the parent's description describes the parent.
id string yes Id for the new optimised index.
name string yes Display name for the new optimised index.
objective string no What the solve minimises. Accepted values: min_tracking_error. Default: "min_tracking_error".

OverviewView

Response of GET /beacon/{index_id}/overview.

Field Type Required Description
concentration ConcentrationPayload yes
end string yes Last date the stored run's level series covers, YYYY-MM-DD, in the same form as start. Resolved from the data: earlier than the end the backtest requested whenever the price store stops short of it. start is the other end.
index_id string yes
last_rebalance string yes
level SeriesPayload yes
metrics BacktestMetrics yes
name string yes
observations integer yes
rebalances integer yes
start string yes First date the stored run's level series covers, YYYY-MM-DD — the same form CompareView.start uses. Resolved from the data rather than requested: it is later than the index's base_date whenever the price store does not reach back that far, so labelling it as the base date shows a different figure from the one the definition carries. end is the other end of the same series; the window the backtest was asked for is not published here.

ParameterSpec

One parameter of a configurable type, described well enough to render.

Names, types, defaults and whether a parameter is required are read from the constructor, so they cannot drift from what the code accepts. Labels, ordering and choices are declared on the class, because a signature cannot carry them.

Field Type Required Description
choices array of string or null no The accepted values, when this is a closed set. Null means any value of type is allowed.
default any no Value used when omitted. Null both for 'no default' and for a default of None; required distinguishes them.
help string or null no One line of guidance for the field.
label string yes Human-readable field name.
name string yes Parameter name, as it must appear in params.
order integer yes Position in the form, ascending.
ref string or null no Component schema this parameter's value must conform to, e.g. 'ExpressionNode' — resolve it under components.schemas in this document. Null for a scalar parameter. type stays the coarse render hint, so a client that ignores this still renders a JSON editor.
required boolean yes Whether the constructor rejects the call without it.
type string yes Display type: number, integer, boolean, string or json. What control to render, not the Python annotation.

PipelineSpec

The grouped rule pipeline: Selection, Weighting, Treatment.

Field Type Required Description
selection array of RuleSpec no
treatment TreatmentSpec no
weighting WeightingSpec yes

PortfolioBookPayload

The portfolio's books on the wire.

No rebalances here, unlike the index books (BN-173): a portfolio makes no rebalance decision of its own — it trades toward one — so decided weights would be a field with nothing honest to put in it. Its own model rather than a shared base with BookPayload, which is what keeps that omission simple.

Field Type Required Description
cash SeriesPayload yes
initial_capital number yes
nav SeriesPayload yes The full NAV book, day-zero row included: it opens with initial capital on the eve of the first trading day. Metrics derive from the series without that row, and a client deriving its own period figures should do the same — a period holding only the day-zero row measures that row against itself and reads as a flat period rather than one that never traded.
portfolio_id string yes
positions TableFrame yes The positions panel, long-form; most recent MAX_POSITION_ROWS rows at most.
positions_total integer yes Rows in the whole positions panel.
transactions TableFrame yes
weights TableFrame yes Stored daily weights, dates by asset; most recent MAX_WEIGHT_DATES dates at most.
weights_dates_total integer yes Dates the weights panel actually covers; larger than the rows served when the panel was truncated.

PreviewAsset

Per-asset outcome of the derivation.

Two disjoint groups of fields, matching the two faces of a preview. The rule-provenance fields (excluded_by, excluded_at, uncapped_weight, capped) describe a walk down a pipeline and are null on a derived preview, which has no rules to attribute anything to. The derived fields (source_weight, solved_weight, weight_delta) describe a reallocation and are null on a rule-driven one. Neither group was overloaded to carry the other's meaning: a client reading excluded_by on a derived index would be reading an answer to a question nobody asked.

Field Type Required Description
capped boolean no Whether this name sits at the cap. Default: false.
excluded_at integer or null no Waterfall position where it dropped out.
excluded_by string or null no Id of the first rule that excluded it. Null when included, and always null on a derived preview.
identifier string yes
included boolean yes Whether it reached the final index.
solved_weight number or null no Derived preview only: what the optimiser allocated it — the 'after'. Equal to weight, and carried separately so the before/after/delta triple reads as one row without a client having to know which face it is on.
source_weight number or null no Derived preview only: what the parent index published for this name at the rebalance being previewed — the 'before'.
uncapped_weight number or null no Weight before capping, when the cap bound this name.
weight number or null no Final weight as a fraction: the capped pipeline weight on a rule-driven preview, the solved weight on a derived one. Null when the name is not held.
weight_delta number or null no Derived preview only: solved_weight minus source_weight. What the constraints did to this name.

PreviewConstraint

One constraint at the solved point: whether it bound, and its room.

Every constraint appears, not only the binding ones. A binding constraint's slack is zero by definition, so a report of only those is a list of zeros; what a reader actually wants beside "this cap bound" is "and the turnover budget had four points of room left".

Field Type Required Description
binding boolean yes Whether the solution sits on this constraint's boundary.
kind string yes 'eq' for an equality, 'ineq' for an inequality. An equality is always binding.
label string yes The constraint's own description of itself, e.g. 'maximum weight 60.0000% on AAA'.
slack number yes Signed room at the solution: zero sits exactly on the boundary, positive has room, negative would be a violation and is never returned. Measured in unit, not in a common currency — there is no shadow price here and slacks of different constraints are not comparable.
unit string yes What slack is measured in, declared by the constraint class and also published by /optimise/constraint-types. 'fraction' means a proportion — of the portfolio for a weight or turnover limit, of return for a return target — and formats as a percentage; 'count' is a whole number of names.

PreviewDocumentRequest

Body of POST /indices/preview, which previews a document as supplied.

The route for a draft. The by-id route reads what is stored, so while an editor holds unsaved changes its figures describe the old definition — with nothing on screen to say they are stale. This one previews exactly what was sent, so editing a rule updates the resolved figures without saving.

Field Type Required Description
as_of string or null no Date to evaluate the pipeline at, YYYY-MM-DD. Defaults to the document's base date.
document IndexDocument yes The definition to derive, saved or not.

PreviewRequest

Body of POST /indices/{id}/preview, which previews the saved index.

Field Type Required Description
as_of string or null no Date to evaluate the pipeline at, YYYY-MM-DD. Defaults to the index's base date.

PreviewResponse

Response of POST /indices/{id}/preview, in one of its two faces.

Exactly one of steps and solve is present, mirroring pipeline and derivation on the document the preview was built from: a rule-driven index answers with the waterfall, a derived one with the solve. solve is the discriminator, and it is the same discriminator the client already branches on one level up.

Everything outside the pair is common to both: the resolved weights, their total, and one row per name.

Field Type Required Description
as_of string yes The date the preview was asked for, YYYY-MM-DD, echoed back unchanged. What the data was actually read from is resolved_date, which is earlier whenever as_of fell on a day the market was shut.
assets array of PreviewAsset yes
cap number or null no Cap applied, as a fraction, if any. Always null on a derived preview, whose limits are constraints.
cap_redistributed number no Weight moved off capped names onto the rest. Default: 0.0.
index_id string yes
resolved_date string or null no The market session as_of resolved to, YYYY-MM-DD: the latest one the data carries on or before it. A request for a weekend or a holiday resolves back to the session before it, which is the composition the index actually held that day rather than an approximation of one. Equal to as_of on a day the data has, and null only when as_of falls outside the data's coverage altogether.
solve PreviewSolve or null no The optimisation at as_of. Null on a rule-driven index.
steps array of PreviewStep or null no The derivation waterfall, one rung per selection rule. Null on a derived index, which narrows nothing.
total_weight number yes Sum of the final weights; 1.0 for a non-empty index.
weights map of string to number yes Final weights as fractions, keyed by identifier.

PreviewSolve

What the optimiser did at one rebalance — the derived face of a preview.

A derivation has no waterfall: the solve moves every weight at once rather than eliminating names in steps, so there are no rungs to show. This is the honest analogue — which parent snapshot was solved, under what, and which rules cost something.

Field Type Required Description
binding array of string no Labels of the constraints the solution sits on — the headline answer to 'what did my constraints do?'. Each also appears in constraints with its slack.
constraints array of PreviewConstraint no Every constraint at the solution, binding or not.
objective string yes What the solve minimised.
rebalance_date string yes The parent snapshot this reports, YYYY-MM-DD: the latest one on or before as_of. A derivation solves only at its parent's rebalances, so an as_of between two of them previews the composition actually in force on that day.
source_index_id string yes The parent index whose published weights were solved.

PreviewStep

One rung of the derivation waterfall.

There is one of these per selection rule, in pipeline order, plus a first entry for the universe itself so the funnel starts from a stated total.

Field Type Required Description
excluded array of string no Identifiers this step removed. Empty for the universe row.
position integer yes 0 is the universe; rules follow in order.
remaining integer yes Constituents surviving after this step.
rule_id string or null no Rule responsible, or null for the universe row.
rule_type string or null no Rule class name.

PriceGapPayload

A day a name had no bar on a session that should have had one.

Field Type Required Description
asset_id string yes The name with no bar on that day.
date string yes The simulated day whose bar was missing, YYYY-MM-DD. A trading day out of the backtest, not a wall-clock stamp.
priced_from string yes The session the carried-forward price actually came from, YYYY-MM-DD; always earlier than date.

PricesResponse

Response of GET /data/prices/{identifier}.

Field Type Required Description
identifier string yes
interval string yes Resolution actually served: 'native', 'weekly' or 'monthly'.
prices TableFrame yes Date-indexed market data.

RebalancePricingPayload

The session one rebalance's trades were priced from.

Field Type Required Description
date string yes The rebalance date from the weight schedule, YYYY-MM-DD.
priced_from string yes The session its prices were read from, YYYY-MM-DD. Equal to date for an ordinary rebalance; earlier when the schedule landed on a day the market was shut, which is the case worth reading.

RebalanceSnapshot

The index's composition at one rebalance.

Both weight sets are carried. weights is what the index applied; uncapped_weights is what the weighting scheme produced before any cap. They are equal on an uncapped index, and the difference is the only way to answer what capping cost — a question that cannot be reconstructed from the applied weights alone.

Declared here, above the book payloads, because since BN-173 it is carried by both: the transient run payload publishes the snapshots as rebalances[], and the durable record publishes the same rows on each index book. One shape for one fact — a second model for the decided weights would be free to drift from this one.

Field Type Required Description
announced string or null no When this composition was published, if earlier than date. Null when the index has no effective-date lag and the two coincide, so its presence is itself the signal that a lag applies.
cap number or null no Maximum single weight, if one applies.
capped array of string no Constituents held at the cap on this date.
date string yes Date these weights took effect, YYYY-MM-DD. Snapshots are keyed by the effective date because that is when the composition is in force.
redistributed number no Weight moved off capped names onto the rest. Default: 0.0.
uncapped_weights map of string to number no Weights before capping. Equal to weights when no cap was applied.
weights map of string to number yes Applied weights, summing to 1.

ReferenceEntry

One identifier's row in a batch reference response.

Field Type Required Description
fields object no Requested reference columns and derived fields. A column the dataset holds but this identifier has no value for is present and null, which is a different statement from the identifier being absent.
found boolean yes Whether the reference dataset holds this identifier. False leaves fields empty rather than failing the batch, so one unknown name does not lose the other 511.
identifier string yes

ReferenceResponse

Response of GET /data/reference/{identifier}.

Fields are whatever columns the loaded reference data carries — the library does not impose a schema on it — so they are returned as a mapping rather than as named attributes.

Field Type Required Description
fields object yes Reference columns for this identifier, e.g. NAME, CURRENCY, EXCHANGE. Timestamps are ISO 8601 strings.
identifier string yes
universes array of UniverseMembership no Universes containing this instrument, so a client can answer 'where is this used?' without reading every universe and searching it.

RelativeMetricsPayload

Performance against a benchmark, over their shared window.

Field Type Required Description
benchmark_return number yes Fraction, not percent: 0.0523 means 5.23%.
beta number yes
correlation number yes
end string yes Last shared date, in the same full ISO-8601 form as start, which is the other end. Resolved by the same intersection: earlier than the backtest's own end whenever the benchmark series stops first.
excess_return number yes Portfolio minus benchmark; also the tracking difference.
level SeriesPayload yes The benchmark, rebased to 100 on the shared window.
observations integer yes Aligned dates used, which may be fewer than either series carried on its own.
reference BenchmarkRef yes
start string yes First date the portfolio and the benchmark share, as a full ISO-8601 timestamp. Resolved: the two level series are intersected before anything is measured, so this is later than the backtest's own start whenever the benchmark's history begins later. observations counts the shared dates and end is the other end; the window the backtest requested is not carried here.
total_return number yes Fraction, not percent: 0.0523 means 5.23%.
tracking_error number yes Annualised standard deviation of return differences.

RenderJobStatus

A render:{render_id} job. result describes the rendered document.

Field Type Required Description
error ErrorDetail or null no Failure reason, when status is failed; null otherwise. The same {code, message, detail} a non-2xx response carries, and the same schema — so a failed job branches on error.code exactly as an HTTP error does (BN-199). It was a bare string until then, which left the job path the one place a deliberate refusal and a crash looked alike. A job that failed before this carries UNCLASSIFIED_FAILURE: its message was recorded, its code was not, and the migration does not guess one.
job_id string yes
kind string yes What the job is, e.g. 'backtest'.
message string no Latest progress message. Default: "".
progress number yes Fraction complete, 0.0 to 1.0.
result RenderResult or null no Present only once the job has succeeded; null otherwise.
status string yes pending, running, succeeded, failed or cancelled. The last three are terminal.

RenderRequest

Body of POST /reports/render.

Field Type Required Description
index_id string or null no Required for a built-in template, which is generated from that index's latest completed backtest. Ignored for a stored template, which is rendered exactly as saved.
template_id string yes A stored template, or a built-in such as FACTSHEET-A4.

RenderResult

Result payload of a completed render job.

Field Type Required Description
blocks integer yes
bytes integer yes Size of the rendered document.
index_id string or null no
name string yes
render_id string yes Fetch the PDF from GET /reports/renders/{render_id}.
rendered_at string yes When the PDF was written, ISO-8601 UTC with an offset — wall-clock at render time. Not the as-of date of anything printed inside it: the figures come from the index's latest completed backtest, whose own dates this does not carry, so rendering the same template twice gives two rendered_at values over identical content.
template_id string yes

ReportTemplateCollection

Response of GET /reports/templates.

Field Type Required Description
built_in array of string no Templates generated from a run rather than stored. These can be rendered but not edited: they are code, not documents.
skipped integer no Stored documents the server could not read, and so left out of this listing. Non-zero means the collection is incomplete: the fault is logged server-side, and each skipped document answers 404 on its own route. Default: 0.
skipped_causes SkippedCauses no The same documents as skipped, by cause, so the listing can say what to do about them. Its three counts sum to skipped.
templates array of ReportTemplateDocument yes

ReportTemplateDocument

A stored report template, as JSON.

Blocks are kept as free-form mappings rather than a discriminated union so the wire shape stays exactly what beacon.report.blocks reads and writes. A second definition of the same thing here is a second definition to keep in step, and the block model already validates its own rows on the way in.

Field Type Required Description
blocks array of object no Content, drawn top to bottom. Each carries a kind, one of: bar_chart, chart, header, stat_grid, table, text.
name string yes Display name.
page object no Page setup: size, orientation, margin.
template_id string yes Stable identifier, used in the URL.

RiskDecomposition

Active risk split into factor and specific parts.

The two sum to the total exactly, because the covariance is defined as B F Bᵀ + D. Pair an arbitrary covariance with arbitrary loadings and there is a cross term; the identity belongs to this model and not to any pairing of a matrix with some exposures.

Field Type Required Description
contributions map of string to number yes Each factor's share of the factor variance. May be negative: a factor position that hedges another genuinely reduces risk.
factor_share number yes
factor_variance number yes
reconciles boolean yes
residual number yes Total minus the two parts. Zero up to float noise, by construction.
specific_variance number yes
total_variance number yes
tracking_error number yes

RiskDiagnosticsPayload

How an estimate was produced, and how far it can be trusted.

Field Type Required Description
assets integer yes
average_correlation number yes Mean off-diagonal correlation. The sanity check a person can actually do: a diversified equity universe sits around 0.3-0.6, and a figure far outside that says the window or the universe is not what someone thought.
condition_number number yes Largest eigenvalue over smallest. An optimiser inverts this matrix, and a large value means the inverse amplifies estimation error rather than reflecting it.
intensity number yes Weight placed on the structured target. 0 means the estimate is the raw sample covariance.
observations integer yes Periods used, after dropping incomplete rows.
positive_semi_definite boolean yes Computed from the eigenvalues, not asserted. A matrix that fails this can produce a negative portfolio variance, and a caller about to invert it needs to know.
repaired boolean yes
smallest_eigenvalue number yes
target string yes

RiskModelCollection

Response of GET /risk-models.

Field Type Required Description
risk_models array of RiskModelSummary yes

RiskModelJobStatus

A risk:{model_id} job. result is the estimated model.

Field Type Required Description
error ErrorDetail or null no Failure reason, when status is failed; null otherwise. The same {code, message, detail} a non-2xx response carries, and the same schema — so a failed job branches on error.code exactly as an HTTP error does (BN-199). It was a bare string until then, which left the job path the one place a deliberate refusal and a crash looked alike. A job that failed before this carries UNCLASSIFIED_FAILURE: its message was recorded, its code was not, and the migration does not guess one.
job_id string yes
kind string yes What the job is, e.g. 'backtest'.
message string no Latest progress message. Default: "".
progress number yes Fraction complete, 0.0 to 1.0.
result RiskModelView or null no Present only once the job has succeeded; null otherwise.
status string yes pending, running, succeeded, failed or cancelled. The last three are terminal.

RiskModelRequest

Body of POST /risk-models/{model_id}/estimate.

Field Type Required Description
end string or null no End of that window.
identifiers array of string no Names to estimate over. Empty uses the index named by index_id.
index_id string or null no Take the universe from this index's latest run instead of listing names.
intensity number or null no Weight on the target, in [0, 1]. Null uses the heuristic from the panel's shape; 0 gives the raw sample covariance, which on a short history across many names is mostly noise.
repair boolean no Clip negative eigenvalues if the result is not PSD. Off by default because shrinkage should make it unnecessary and clipping silently shifts the variances. Default: false.
start string or null no Start of the estimation window.
target string no Structured target to shrink toward: 'constant_correlation' or 'scaled_identity'. Default: "constant_correlation".

RiskModelSummary

One entry in GET /risk-models.

Field Type Required Description
assets integer yes
average_correlation number yes
model_id string yes
observations integer yes
positive_semi_definite boolean yes

RiskModelView

Response of GET /risk-models/{model_id}.

Field Type Required Description
asset_ids array of string yes
correlation TableFrame yes Symmetric with a unit diagonal, by construction.
covariance TableFrame yes Annualised.
diagnostics RiskDiagnosticsPayload yes
end string or null no The request's own end, echoed back unchanged on the same terms as start, which is the other bound. Null when the request omitted it.
model_id string yes
start string or null no The request's own start, echoed back unchanged — the bound the price fetch was given, not the first date prices were found on. Null when the request omitted it, which estimates over the whole stored history. No field here reports the dates the returns actually spanned; diagnostics.observations is the only measure of what survived. end is the other bound.
volatilities map of string to number yes Annualised standard deviation per asset — the square root of the covariance diagonal.

RiskPayload

How the index's volatility divides among its holdings.

Contributions sum to volatility exactly rather than approximately — the decomposition is an identity, so a client can show the parts and the whole without them disagreeing.

Field Type Required Description
covered_weight number yes Fraction of the index the figure speaks for. Below 1.0 when the model has no estimate for some constituent; the covered names keep their real weights rather than being renormalised, which would restate the portfolio.
uncovered array of string no Constituents with no estimate, usually for want of history. Listed rather than only counted, so a reader sees which names are missing.
volatility number yes Annualised volatility of the covered holdings, at the weights they are actually held.
window_end string or null no Last date of the run's own level series, YYYY-MM-DD, on the same terms as window_start, which is the other end: a bound given to the price fetch, unchanged by what the store actually held.
window_start string or null no First date of the run's own level series, YYYY-MM-DD — the span the price fetch behind this estimate was given, not the dates prices came back on. It does not narrow: when the store covers less, the covariance is estimated from fewer observations and this still reports the run's span, so it is a bound rather than a measurement. Null when the run carries no level series. window_end is the other end, and active_risk.window_start is this same window — both come from the run, not from a query.

RollResponse

Response of GET /derivatives/{index_id}/roll.

Both legs are priced theoretically off the same spot and curve, so this is the carry roll rather than a market one.

Field Type Required Description
annualised_roll number yes Positive in backwardation, negative in contango.
as_of string yes The session both legs were priced from, YYYY-MM-DD: the latest date with a close on or before the as_of query, or the last date the store carries when none was given. Resolved rather than echoed — a request landing on a weekend or a holiday answers from the session before it — and the date asked for is not published anywhere. Both expiries are measured from this date, so it also sets annualised_roll.
back_expiry string yes
back_price number yes
front_expiry string yes
front_price number yes
index_id string yes
roll_cost number yes Back minus front.
spot number yes

RuleSpec

One rule in the pipeline, addressable by its id.

Field Type Required Description
id string yes Client-assigned id, unique within the pipeline.
params object no Constructor arguments for the rule.
type string yes Rule class name, e.g. 'MarketCapRule'.

RuleTypes

Response of GET /indices/rule-types.

Everything a methodology editor needs to render a real form: which rules and schemes exist, what each takes, and how to label and order the fields. Without it RuleSpec.type is a free-text box and params a list of key/value pairs, so a misspelled parameter is only discovered on submit.

Field Type Required Description
selection array of TypeSpec yes Eligibility rules available for the selection stage.
weighting array of TypeSpec yes Weighting schemes available for the weighting stage.

SavedConstraintSet

Response of a successful save: the set plus any warnings.

Field Type Required Description
constraint_set ConstraintSet yes
findings array of Finding no Non-blocking warnings. Errors would have prevented the save.

SavedIndex

Response of a successful save: the document plus any warnings.

Field Type Required Description
findings array of Finding no Non-blocking warnings. Errors would have prevented the save.
index IndexDocument yes

ScheduleView

Response of GET /indices/{index_id}/schedule.

Derived, not stored: the next rebalance is a function of the schedule, the calendar and today, and storing it would leave a date that silently expires.

Field Type Required Description
as_of string yes Date the answer was computed from.
calendar string yes Exchange MIC the dates were computed on. Always present since BN-180 made the calendar required.
days_until integer or null no Calendar days from as_of to next_rebalance. Calendar days rather than sessions, because it is displayed as 'in 57 days' and a reader counts those on a wall calendar.
index_id string yes
next_rebalance string or null no Next rebalance date, ISO 8601. Null when none falls within the lookahead — which happens only for a schedule this server cannot project, not for a normal index.
rebalance_day_rule string yes
rebalancing_frequency string yes
recent array of string no Rebalances already passed, most recent last. Trimmed to the limit most recent; recent_total says how many there were.
recent_total integer no Rebalances between the base date and as_of — the length recent would have had before the limit trim, so equal to it when nothing was trimmed. A client reads these two together to tell 'these are all of them' from 'the last four of many'. Default: 0.
upcoming array of string no Scheduled rebalances after as_of, soonest first. Trimmed to the limit soonest; upcoming_total says how many were found.
upcoming_total integer no Rebalances the lookahead projection found after as_of — the length upcoming would have had before the limit trim, not the number that will ever occur. The projection runs a fixed few periods ahead and limit does not extend it, so this is a bound on what was computed, not on the schedule, which has no end. Default: 0.

SeriesPayload

A pandas Series on the wire.

Field Type Required Description
data array of any yes Values, aligned to index. NaN becomes null.
index array of any yes Row labels; timestamps are ISO 8601 strings.
name string or null no Series name, if it has one.

SkippedCauses

Why a listing left documents out, one count per cause (BN-201).

skipped could only say how many, and the one sentence a client could write over it -- "could not be read" -- invites restoring a file that may be perfectly fine. Each cause has its own remedy, so each has its own count and a description that names it.

Field Type Required Description
from_newer_build integer no Documents written by a newer py-beacon than the one serving this listing. Nothing is wrong with them: upgrading the engine will read them. The state two installs reach when the engine and the app are updated on different machines. Default: 0.
unparseable integer no Documents that are damaged: not valid JSON, or carrying a schema version nothing can migrate. The file itself is the problem -- restore it from a backup or remove it. Default: 0.
unrecognised integer no Documents that are valid JSON but that this engine's model does not accept -- the document and the engine disagree about its shape, usually a version gap the schema migrations do not cover. The server log names the field. Default: 0.

SyncJobResult

Result payload of a completed data sync.

The narrowest honest description of what the sync job returns (BN-172): IngestResult.summary() plus the two fields the job adds. Deliberately a count-and-identifier summary rather than the data — the rows went into the fetcher, and a client reads them back through the data endpoints.

Field Type Required Description
dataset string yes Which dataset was synced: market or reference.
errors map of string to string no Identifier to the reason it did not come back.
failed integer yes Identifiers that did not.
fetched integer yes Identifiers that returned data.
identifiers array of string no The identifiers that succeeded.
rows integer yes Market-data rows fetched.
rows_added integer yes Rows actually merged in, which is fewer than rows whenever the fetch overlapped data already held.

SyncJobStatus

A sync:{dataset} job. result summarises what was fetched.

Field Type Required Description
error ErrorDetail or null no Failure reason, when status is failed; null otherwise. The same {code, message, detail} a non-2xx response carries, and the same schema — so a failed job branches on error.code exactly as an HTTP error does (BN-199). It was a bare string until then, which left the job path the one place a deliberate refusal and a crash looked alike. A job that failed before this carries UNCLASSIFIED_FAILURE: its message was recorded, its code was not, and the migration does not guess one.
job_id string yes
kind string yes What the job is, e.g. 'backtest'.
message string no Latest progress message. Default: "".
progress number yes Fraction complete, 0.0 to 1.0.
result SyncJobResult or null no Present only once the job has succeeded; null otherwise.
status string yes pending, running, succeeded, failed or cancelled. The last three are terminal.

SyncRequest

Body of POST /data/coverage/{dataset}/sync.

Field Type Required Description
end string or null no Inclusive end date, YYYY-MM-DD.
identifiers array of string no What to fetch. Empty re-syncs everything already loaded, which is the common case: refresh what I have.
start string or null no Inclusive start date, YYYY-MM-DD.

TableFrame

A pandas DataFrame on the wire.

Row-oriented so column order is preserved and the payload stays compact.

Field Type Required Description
columns array of string yes Column names, in order.
data array of array of any yes Rows, each aligned to columns. NaN becomes null.
index array of any yes Row labels; timestamps are ISO 8601 strings.

TablePage

Response of GET /data/tables/{dataset}.

The stored data as it is, before any view shapes it. Paged because the default synthetic store holds 11.8M market rows — an unbounded dump is not something a client can render or an engine should assemble.

Field Type Required Description
dataset string yes
limit integer yes
offset integer yes
rows object yes The {index, columns, data} frame shape used elsewhere.
total integer yes Rows in the whole dataset, so a client can size its scrollbar without paging to the end to find out.

TermStructureEntry

One expiry in a term structure.

Field Type Required Description
expiry string yes
financing_rate number yes
theoretical number yes
time_to_expiry number yes Years from the response's as_of to expiry, ACT/365. Measured from the resolved session rather than the date asked for, so a request landing on a weekend or a holiday lengthens every tenor in the strip by however many days as_of resolved back.

TermStructureResponse

Response of GET /derivatives/{index_id}/term-structure.

Field Type Required Description
as_of string yes The session spot was read from, YYYY-MM-DD: the latest date with a close on or before the as_of query, or the last date the store carries when none was given. Resolved rather than echoed — a request landing on a weekend or a holiday answers from the session before it — and the date asked for is not published anywhere. Every entries[].time_to_expiry is measured from this date.
entries array of TermStructureEntry yes
index_id string yes
spot number yes

TreatmentSpec

The treatment group of the pipeline.

Field Type Required Description
corporate_actions string no How corporate actions affect the index. Only ADJUST_DIVISOR is supported. Default: "ADJUST_DIVISOR".

TrsAccrual

One financing period.

Field Type Required Description
accrual_fraction number yes ACT/360 day-count fraction.
amount number yes
days integer yes
end string yes Day this financing period ends, YYYY-MM-DD: one payment_frequency step after start, which is the other end, except in the final period, which is truncated to the trade's end_date. days counts calendar days between the two.
rate number yes Reference rate for the period: the fixing for the current one, the curve's forward for later ones.
start string yes First day of this financing period, YYYY-MM-DD. Derived from the request alone, never resolved against a calendar or market data: the schedule begins at last_reset_date — or start_date when no reset was given — and steps by payment_frequency. Business days are not observed, so a boundary can fall on a weekend. end is the other end.

TrsPriceRequest

Body of POST /derivatives/trs/price.

Field Type Required Description
currency string no Default: "USD".
curve map of string to number or null no Zero-rate pillars for projecting future periods. The current period always accrues at the rate already fixed at its reset.
dividend_yield number no Continuous dividend yield on the underlying, used only for the breakeven table, alongside futures_prices and time_to_expiry. present_value, both legs and fair_spread_bps ignore it: the total-return leg is spot against initial_price, and that ratio already carries whatever the underlying paid. Sending it without futures_prices changes nothing in the response. Default: 0.0.
end_date string (date) yes Calendar date, YYYY-MM-DD.
futures_prices array of number or null no Prices to compute breakeven spreads against.
initial_price number yes Level at inception or last reset.
last_reset_date string (date) or null no Defaults to the start date.
notional number yes
payment_frequency string no Default: "QUARTERLY".
reference_rate string no Name of the index. Default: "SOFR".
reference_rate_value number no Its current fixing, as a decimal. Default: 0.0.
reset_type string no UNFUNDED accrues reference + spread; FUNDED accrues only the spread, and therefore has no rate sensitivity at all. Default: "UNFUNDED".
spot number yes Underlying level today.
spread_bps number no Default: 0.0.
start_date string (date) yes Calendar date, YYYY-MM-DD.
time_to_expiry number or null no Needed for the breakeven table.
trade_id string no Identifier for the trade. Default: "TRS".
underlying_id string no Default: "INDEX".
valuation_date string (date) yes Calendar date, YYYY-MM-DD.

TrsPriceResponse

Response of POST /derivatives/trs/price.

Field Type Required Description
accrual_days integer yes
accrual_fraction number yes ACT/360, from the last reset.
breakeven array of map of string to number no Breakeven financing spread against each supplied futures price — what makes a swap and a future agree.
dv01 number yes Value change per +1bp. Negative for a receiver, who pays financing — the sign carries the information a magnitude would lose. Exactly zero on a funded swap, where only the spread accrues.
fair_spread_bps number or null no Spread at which the trade would be worth nothing today. Null when no time has accrued, where no spread could balance it.
financing_leg number yes
present_value number yes Total return leg minus accrued financing, from the receiver's side.
schedule array of TrsAccrual yes
total_return_leg number yes
trade_id string yes
valuation_date string (date) yes Calendar date, YYYY-MM-DD.

TypeSpec

One configurable type a client can offer.

Field Type Required Description
label string yes Human-readable name for the type.
name string yes Class name, as it must appear in type.
parameters array of ParameterSpec no
slack_unit string or null no For a constraint type, what its slack is measured in: 'fraction' or 'count'. Read off the constraint class, so the same answer reaches the constraint editor here and each row of a preview's solve.constraints. Null on a selection rule or weighting scheme, which have no slack.
summary string no One line describing what it does. Default: "".

UnfilledOrderPayload

A buy the simulation could not execute in full.

Field Type Required Description
asset_id string yes
date string yes The rebalance date on which the buy fell short, YYYY-MM-DD. A simulated trading day out of the backtest, not a wall-clock stamp: re-running the same backtest produces the same date. BacktestResultSummary.run_at is the wall-clock one.
filled_quantity number yes
price number yes
requested_quantity number yes
shortfall_value number yes

Universe

A named set of instrument identifiers.

Field Type Required Description
as_of string or null no The date a filter was last resolved at.
description string or null no Optional free text.
filter ExpressionNode or null no The expression this universe was built from, when it was built by filtering. Null for a curated list.
id string yes Stable identifier.
identifiers array of string no
mode string no 'frozen' means the stored identifiers are the membership; 'live' means the filter is re-evaluated on read, so the membership moves when the data does. A frozen universe records what it contained; a live one records how it was chosen. They are different objects and a caller needs to know which they have. Default: "frozen".
name string yes Display name.
source string no 'user' for one somebody created, 'seeded' for one the generator wrote. A seeded universe cannot be edited or deleted. Default: "user".

UniverseCollection

Response of GET /universes.

Field Type Required Description
skipped integer no Stored documents the server could not read, and so left out of this listing. Non-zero means the collection is incomplete: the fault is logged server-side, and each skipped document answers 404 on its own route. Default: 0.
skipped_causes SkippedCauses no The same documents as skipped, by cause, so the listing can say what to do about them. Its three counts sum to skipped.
universes array of Universe yes

UniverseCreate

Body of POST /universes.

No id: the server derives one from the name, so a client cannot create two universes whose ids differ only in punctuation and expect them to be distinct documents.

Field Type Required Description
description string or null no
filter ExpressionNode or null no A serialised expression to build the membership from, instead of naming it. Mutually exclusive with a non-empty identifiers.
identifiers array of string no Members. Every one must exist in the loaded reference data. Required unless a filter is given.
mode string no 'live' re-evaluates the filter on every read; 'frozen' keeps the membership it resolved to. Only meaningful with a filter. Default: "frozen".
name string yes Display name.

UniverseMembers

Response of GET /universes/{id}/members.

Field Type Required Description
identifiers array of string yes
universe_id string yes

UniverseMembership

One universe an instrument belongs to.

Field Type Required Description
id string yes Universe identifier, as used in the URL.
name string yes Display name.
source string yes 'seeded' for one the server wrote from the dataset, 'user' for one somebody made.

UniverseRef

Where an index's universe comes from.

Either a reference to a stored universe or a literal list. identifiers is always populated on read, so consumers never have to resolve it.

Field Type Required Description
identifiers array of string no Resolved instrument identifiers.
universe_id string or null no Id of a stored universe, if referenced.

UniverseUpsert

Body of PUT /universes/{id}.

Field Type Required Description
description string or null no
identifiers array of string no
name string yes Display name.

ValidationReport

Response of the validation endpoint, and of a rejected save.

Field Type Required Description
findings array of Finding yes
valid boolean yes False when any finding has severity 'error'.

Watchlist

A named set of instrument identifiers.

Field Type Required Description
id string yes Stable identifier, used in the URL.
identifiers array of string no Instrument identifiers, in user order.
name string yes Display name.

WatchlistCollection

Response of GET /data/watchlists.

Field Type Required Description
skipped integer no Stored documents the server could not read, and so left out of this listing. Non-zero means the collection is incomplete: the fault is logged server-side, and each skipped document answers 404 on its own route. Default: 0.
skipped_causes SkippedCauses no The same documents as skipped, by cause, so the listing can say what to do about them. Its three counts sum to skipped.
watchlists array of Watchlist yes

WatchlistUpsert

Body of PUT /data/watchlists/{id}.

The id comes from the URL, so it is not repeated here — accepting it in both places invites the two to disagree.

Field Type Required Description
identifiers array of string no Instrument identifiers, in user order.
name string yes Display name.

WeightingSpec

The weighting group of the pipeline.

Field Type Required Description
id string no Id used to address findings. Default: "weighting".
max_weight number or null no Cap on any single constituent's weight, as a fraction (0.1 is 10%). Applied after the scheme and iterated until nothing breaches it. Null means uncapped.
params object no Constructor arguments for the scheme.
scheme string yes Scheme class name, e.g. 'EqualWeighted'.

WeightRow

One name's index, optimal and active weight.

Field Type Required Description
active_weight number yes Optimal minus index. Sums to zero across the portfolio whenever both sides are fully invested.
asset_id string yes
index_weight number yes
optimal_weight number yes

WeightsView

Response of GET /beacon/{index_id}/weights.

Field Type Required Description
active_risk ActiveRiskPayload or null no The tracking-error decomposition, when a benchmark index was named alongside risk=true.
announced_date string (date) or null no When that composition was published, if earlier than rebalance_date. Null when the index has no lag.
as_of string yes Date asked about.
cap number or null no
cap_redistributed number no Default: 0.0.
capped array of string no
concentration ConcentrationPayload yes
drift DriftPayload or null no Movement since the previous rebalance. Null at the first, where there is nothing to have drifted from.
index_id string yes
rebalance_date string yes Rebalance in force on that date. An index holds the weights set at its last rebalance until the next one, so this is usually earlier than as_of.
risk RiskPayload or null no The volatility decomposition, when risk=true was requested. Null otherwise: estimating a covariance over every constituent is the pane's whole cost, and nobody should pay it without asking.
rows array of ConstituentRow no Per-constituent detail, heaviest first. Carries the same applied weights as weights, which is kept because charts and concentration maths want a mapping while a table wants ordered rows.
weights map of string to number yes