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 |