quantlab.portfolio.base.PortfolioConstructor#
- class quantlab.portfolio.base.PortfolioConstructor(config)[source]#
Bases:
_Configured,ABCBase class of every rule that turns one bar’s scores into target weights.
Subclass it, set
config_clsto a dataclass of the rule’s parameters and implementconstruct; overridebindto check the label specs and read what the rule needs from them, anddeclared_inputswhen it reads a return window, factor panels or a factor risk model’s exposures.decidemakes the one-bar decision on a contextDecisionInputsassembles.get_configandfrom_configserialise the rule as its config’s fields plus the class’s import path under"name", which a backtest’sconfig.jsonrecords.- Parameters:
- configdataclass instance
An instance of
config_cls.
- Raises:
- TypeError
If
configis not aconfig_clsinstance.
Examples
>>> from quantlab.portfolio.config import TopNConfig >>> from quantlab.portfolio.predefined.top_n import TopNConstructor >>> rule = TopNConstructor(TopNConfig(direction="long_only", top_n=2)) >>> isinstance(rule, PortfolioConstructor), rule.config.top_n (True, 2)
- axis_factors()[source]#
The declared factor outputs the rule reads on symbols it has no prediction for.
A run decides on the symbols with a prediction on some bar of its window, the only ones a rule can buy, plus the symbols with a value of one of these outputs on some bar (
DecisionInputs.decision_symbols): a benchmark’s or the market’s weights, which the rule reads on symbols it never holds. None by default.Examples
>>> rule.axis_factors() ()
- bind(labels)[source]#
Check the label specs and read from them what the rule needs.
Called once when a backtest is constructed, before any data is read or model trained, with the specs of the predictor’s labels; and by
DecisionInputs.from_runwith the specs a run’s prediction panel records. A rule reading a label’s span resolves it here. The specs are the only metadata a rule may read about a prediction. The default accepts any specs.- Parameters:
- labelsSequence[LabelSpec]
One spec per prediction variable, in the predictor’s order.
- Raises:
- ValueError
If the rule cannot use the labels.
Examples
>>> rule.bind([LabelSpec(name="ret_5", scale="raw", delay=1, span=5)]) is None True
- abstractmethod construct(context)[source]#
Return the weights to hold after the context’s bar.
- Parameters:
- contextPortfolioContext
What is known at the bar.
- Returns:
- xr.DataArray
One weight per symbol of
context.symbols, onsymbol: finite, 0.0 where nothing is held, gross exposure at most one; or all NaN to hold the current position.
- Raises:
- PortfolioConstructionError
If the bar cannot be decided (the loop then holds it).
Examples
>>> rule.construct(context).values # CCC is locked at 0.6 array([0.2, 0.2, 0.6])
- decide(context)[source]#
Decide one bar: run
construct, check its row and hold a bar it cannot solve.The one-bar decision, shared by
DecisionInputs.weightsand event-driven executors. APortfolioConstructionErrorfromconstructbecomes a hold (all-NaN weights) carrying the error’s message, with a warning. A row that breaks the weights contract is a bug in the rule, not a hold, and raises.decideis not meant to be overridden: a rule implementsconstruct.- Parameters:
- contextPortfolioContext
The bar’s context, from
DecisionInputsor built by hand.
- Returns:
- Decision
The weights on
context.symbols(all NaN to hold), the failure message orNone, and the row’s events.
- Raises:
- ValueError
If
constructreturns weights on other symbols than the context’s, a row mixing NaN and finite values, a changed locked position (held, not tradable) or weight on a symbol neither tradable nor held.
Examples
>>> decision = rule.decide(context) >>> decision.weights.values, decision.failure, decision.events (array([0.2, 0.2, 0.6]), None, {})
- declared_inputs()[source]#
What the rule reads at each bar besides its predictions and holdings.
DecisionInputsbuilds each context from it: the return window and the prices behind it, the factors’ values and the risk model’s exposures. None of them by default; a rule holding a covariance estimator declares the estimator’s, merged with its own (InputDeclaration.merged).Examples
>>> rule.declared_inputs() InputDeclaration(lookback_bars=0, history_bars=1, factors=(), risk_model=None)
- keeps_every_symbol()[source]#
Whether a run keeps every symbol of its price axis rather than those it decides on.
True when a decision reads symbols beyond those with a prediction and those of
axis_factors, as a covariance estimated over every symbol the context holds does (CovarianceEstimator.pools_symbols). False by default.Examples
>>> rule.keeps_every_symbol() False
- ranking_label(names)[source]#
Return the predicted label the rule ranks the symbols by.
A run’s attribution ranks its universe and score groups by it. The default is the first label; a rule reading one label by name answers with that label.
- Parameters:
- namesSequence[str]
The predicted labels, in the predictor’s order.
- Returns:
- str
Examples
>>> rule.ranking_label(["ret_5", "ret_1"]) 'ret_5'