Panel and Graph Architecture Refactor Plan
Goal
Separate data from logic:
some_input = Panel.from_domain(dataframe, domain, name="some_input")
some_factor = rank(zscore(some_input), name="some_factor")
some_factor.compute()
factor_panel = some_factor.output
Public Boundary
from bagelquant_core import Graph, Panel
from bagelquant_core.composer import composer
from bagelquant_core.transformer import transformer
Panelis the explicit data input and output object.Graphstores lazy logic chains.- Decorated transformer and composer functions build graphs.
Graph.compute()evaluates graphs and materializes output panels.
Completed Refactor
Panel Data Boundary
- Users create raw inputs with
Panel.from_domain(dataframe, domain, name=...). - Execution results are
Panelobjects. - Panels validate numeric two-dimensional data.
- Panels copy input data and return defensive copies through
Panel.data.
Function-Style Operations
- Built-ins are plain functions such as
rank(...),zscore(...), anddiv(...). - Users create custom operations with
@transformerand@composer. - Adding operations does not require editing
Graph.
Lazy Graph Logic
- Factors, predictions, and portfolio weights are graphs.
- Graphs collect dependencies, validate DAG structure, and expose specs.
- A graph output is available through
Graph.outputafter execution.
Runtime Cache
- The internal execution runtime caches computed panels during a run.
- Computing a downstream graph populates outputs for evaluated intermediate graphs.
- Shared DAG nodes are evaluated once per runtime invocation.
- Already-aligned input panels reuse their stored hashes.
Future Work
- Add stable serialization and versioning for operation identifiers.
- Add persisted caches and explicit invalidation policies.
- Add operation modules for neutralization, portfolio construction, backtesting, and analytics.