Files
fidc-backtest-engine/docs/factor-decision-phase-contract.md
T

3.7 KiB

Factor Decision Phases

Status: broker foundation implemented; factor compiler, evaluator and runtime-plan integration are not complete. Do not advertise this as a fully working stock-pool buy-condition feature.

Separate Contracts

Phase Meaning Must Not Do
Selection Build and rank the candidate universe at the strategy decision clock Pretend this also guards every later top-up
Buy permission Decide whether this decision may create new buy exposure for a symbol Convert a denied buy into a sell or silently drop a holding from a full target snapshot
Exit/reduction Produce the explicitly configured exit or partial target Normalize remaining targets upward without an explicit strategy rule
Execution risk Apply actual execution-date price, ST, suspension, lifecycle, liquidity and cost constraints Substitute decision-date risk facts for next-open execution facts
Existing orders Continue the already submitted order under its execution risk and lifetime contract Implicitly cancel or rewrite it merely because a later decision has a new buy denial

Broker Primitive

StrategyDecision.buy_denials is a symbol-to-reason map sampled by the strategy layer, not a factor evaluator. Merged decisions retain denials. The broker installs it only while processing that decision and restores the prior context afterward; it is never shared through DataSet caches.

New positive buy quantities and target-buy planning respect the map after standard market/risk checks. Sells remain permitted. The actual execution price determines whether a value/portfolio target requires buying: a target below the signal-day holding value can become a buy after a lower next open, so signal-day direction alone is insufficient.

Existing resting orders are not automatically canceled by this primitive. A buy amendment is denied if it increases total quantity or raises the limit price, even if the other dimension decreases. Reductions in both dimensions remain allowed after normal validation. A rejected amendment emits an update-rejection process event without replacing the original order state or queue priority. Full runtime-plan integration still requires testing.

Required Integration

  1. Split selection and buy-role output in the stock-pool compiler instead of folding both into stock_filter.
  2. Evaluate buy expressions at the declared decision clock using typed field availability, units and frozen data identity. Missing data must retain its own diagnostic, not silently become a false trading signal.
  3. Populate denials for every symbol a decision can buy, including portfolio targets, retained-target reentry and top-ups. Do not infer execution direction from signal-day value.
  4. Preserve/consume constraints in Paper/Live strategy-plan conversion. No consumer may silently discard a nonempty denial map.
  5. Carry the tested amendment policy through runtime-plan conversion; validate source-date and execution-date risk independently.
  6. Verify same-bundle baseline parity when no buy constraint is configured, then test explicit buy failures across share, value, target and algorithmic orders.

Current Evidence

On 177, broker tests verify blocked target top-ups, permitted sells, context restoration, existing pending-order preservation, a next-open target direction flip, and risk-increasing/reducing amendments with unchanged state on rejection. Full fidc-core tests passed: 453 unit tests and 122 integration tests, with 8 manual benchmarks ignored. The backtest runner previously compiled against the changed API.

The candidate is not deployed. The current OmniQuant compiler still needs the above integration, and no production readiness claim follows from these low-level tests.