deltaforge-real-time-cross-.../deltaforge/rt_engine.py

87 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from typing import List
from .adapters.equity_feed import EquityFeedAdapter
from .adapters.options_feed import OptionsFeedAdapter
from .core import Curator
from .coordinator import Coordinator
from .execution import ExecutionEngine
from .backtester import Backtester
from .dsl import MarketSignal, PlanDelta, StrategyDelta, Asset
class RealTimeEngine:
"""Minimal real-time cross-asset engine (MVP).
Streams signals from equity and options adapters, synthesizes a plan via the
curator, coordinates cross-venue coherence, and executes the plan. Also runs a
deterministic replay for testing purposes.
"""
def __init__(self,
equity_symbols: List[str] | None = None,
option_assets: List[dict] | None = None,
venues: List[str] | None = None,
sample_window: int = 4):
self.equity_symbols = equity_symbols or ["AAPL", "MSFT"]
self.option_assets = option_assets or [{"symbol": "AAPL", "type": "call"}, {"symbol": "MSFT", "type": "put"}]
self.venues = venues or ["VENUE-A", "VENUE-B"]
self.sample_window = sample_window
# Adapters
self.equity_adapter = EquityFeedAdapter(symbols=self.equity_symbols, venues=self.venues)
self.option_adapter = OptionsFeedAdapter(assets=self.option_assets, venues=self.venues)
# Lightweight components
self.curator = Curator()
self.coordinator = Coordinator()
self.engine = ExecutionEngine()
self.bt = Backtester(initial_cash=100000.0)
def _collect_signals(self) -> List[MarketSignal]:
signals: List[MarketSignal] = []
eq_iter = self.equity_adapter.stream_signals()
opt_iter = self.option_adapter.stream_signals()
for _ in range(self.sample_window):
try:
s = next(eq_iter)
signals.append(s)
except StopIteration:
pass
try:
s = next(opt_iter)
signals.append(s)
except StopIteration:
pass
return signals
def run_cycle(self) -> dict:
"""Run a single deterministic cycle: collect signals, synthesize and coordinate a plan, and execute."""
signals = self._collect_signals()
# Build simple objectives from signals
objectives: List[StrategyDelta] = []
for idx, sig in enumerate(signals):
asset = sig.asset
hedges = 0.5 # simple heuristic placeholder
objectives.append(StrategyDelta(id=f"rt-{idx}", assets=[asset], hedge_ratio=hedges, target_pnl=0.0, constraints=[]))
# Curate a plan from signals (optional in MVP) we keep this lightweight
plan_curated: PlanDelta = self.curator.synthesize_plan(signals, objectives)
# Cross-venue coordination step (ADMM-lite)
plan = self.coordinator.coordinate(signals, author="rt-engine")
# Execute plan (routing and PnL proxy)
exec_result = self.engine.execute(plan)
# Backtest replay for deterministic evaluation
replay = self.bt.run(plan)
return {
"plan": plan,
"execution": exec_result,
"replay": replay,
}