Skip to content

Universes

Filtered universes: a universe described by a condition on the data rather than by a list of names. See Universe.

universe

Building a universe by filtering, rather than by listing.

from beacon import universe
from beacon.expressions import data

members = universe.where((data.reference.region == "North America")
                         & (data.market.market_cap > 1e9),
                         fetcher)

These are the same expressions that drive index rules, so there is one way of naming a datapoint and it works everywhere.

Frozen and live are different objects

A universe saved as a list of identifiers is a fact about a moment. It does not change when the data does, which is what you want for a published index whose membership was fixed at a review, and it cannot be refreshed, because nothing records how it was chosen.

A universe saved as an expression is a question. Re-evaluating it next month gives a different answer, which is what you want for "every US name above a billion", and it can never tell you what it contained last month, because it does not store that.

Neither is more correct. What would be wrong is a universe that looks like one and behaves like the other. So build records the date it resolved at (as_of) and a mode (LIVE or FROZEN) saying which of the two the result means, and resolve_document answers a stored document accordingly: a live one re-evaluates its filter, anything else returns the identifiers it stored.

Resolution is point-in-time

where(expression, fetcher, date) answers as of date, through the same resolver an index rule uses. A universe built "as of last March" contains what was knowable last March, including names that have since been delisted, and excluding ones that had not yet listed. With no date, a filter resolves at the last date of the loaded data.

FilteredUniverse dataclass

FilteredUniverse(
    expression: Expression,
    identifiers: list[str],
    as_of: Timestamp,
    mode: str = LIVE,
    candidates: int = 0,
)

A universe and the question that produced it.

Carries both the expression and the membership it resolved to, so a caller can save either, and mode says which of the two the document means.

is_live property

is_live: bool

Whether re-evaluating is meant to change the answer.

as_document

as_document() -> dict[str, Any]

The parts a stored universe keeps.

where

where(
    expression: Expression,
    fetcher: DataFetcher,
    date: Timestamp | str | None = None,
    identifiers: list[str] | None = None,
    on_missing: bool = False,
) -> list[str]

The instruments satisfying an expression, as of a date.

Parameters:

Name Type Description Default
expression Expression

The filter.

required
fetcher DataFetcher

The data to resolve against.

required
date Timestamp | str | None

When to stand. Defaults to the end of the loaded data, not to today, because a store loaded from a file has a last date and answering against a calendar the data does not reach would report every name as having no value.

None
identifiers list[str] | None

Candidates. Defaults to everything the store covers.

None
on_missing bool

Whether a name with no value for a field is included.

False

Returns:

Type Description
list[str]

list[str]: Matching identifiers, in the order the candidates were

list[str]

given, so two runs over the same data produce the same list.

build

build(
    expression: Expression,
    fetcher: DataFetcher,
    date: Timestamp | str | None = None,
    mode: str = LIVE,
    on_missing: bool = False,
) -> FilteredUniverse

Resolve an expression and keep the question alongside the answer.

Parameters:

Name Type Description Default
expression Expression

The filter.

required
fetcher DataFetcher

The data.

required
date Timestamp | str | None

When to stand.

None
mode str

LIVE to re-evaluate on read, FROZEN to keep the membership.

LIVE
on_missing bool

Whether uncovered names are included.

False

Returns:

Name Type Description
FilteredUniverse FilteredUniverse

Expression, members, and which of the two counts.

resolve_document

resolve_document(
    document: dict[str, Any],
    fetcher: DataFetcher,
    date: Timestamp | str | None = None,
) -> list[str]

The members of a stored universe.

A frozen document answers with what it stored; a live one re-evaluates its filter. That branch is the whole distinction, and putting it here means one place decides rather than every caller remembering.