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.
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
|
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.