build(agent): new-agents-4#58ba63 iteration

This commit is contained in:
agent-58ba63c88b4c9625 2026-04-20 16:13:15 +02:00
parent c519cc58c6
commit 68c5a8454d
4 changed files with 103 additions and 4 deletions

View File

@ -17,6 +17,7 @@ __all__ = [
"OptionsFeedAdapter", "OptionsFeedAdapter",
"ExecutionEngine", "ExecutionEngine",
"Backtester", "Backtester",
"RealTimeEngine",
] ]
from .dsl import Asset, MarketSignal, StrategyDelta, PlanDelta from .dsl import Asset, MarketSignal, StrategyDelta, PlanDelta
@ -25,3 +26,4 @@ from .adapters.equity_feed import EquityFeedAdapter
from .adapters.options_feed import OptionsFeedAdapter from .adapters.options_feed import OptionsFeedAdapter
from .execution import ExecutionEngine from .execution import ExecutionEngine
from .backtester import Backtester from .backtester import Backtester
from .rt_engine import RealTimeEngine

View File

@ -3,7 +3,7 @@ from __future__ import annotations
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Iterator from typing import Iterator
from ..dsl import MarketSignal from ..dsl import MarketSignal, Asset
class EquityFeedAdapter: class EquityFeedAdapter:
@ -17,10 +17,18 @@ class EquityFeedAdapter:
self.venues = venues or ["VENUE-A", "VENUE-B"] self.venues = venues or ["VENUE-A", "VENUE-B"]
def stream_signals(self) -> Iterator[MarketSignal]: def stream_signals(self) -> Iterator[MarketSignal]:
"""Yield deterministic MarketSignal objects compatible with deltaforge.dsl.MarketSignal.
Each signal carries the canonical Asset description as expected by the DSL.
"""
base = {"AAPL": 150.0, "MSFT": 300.0} base = {"AAPL": 150.0, "MSFT": 300.0}
t = datetime.utcnow() t = datetime.utcnow()
for i in range(4): for i in range(4):
for v_i, venue in enumerate(self.venues): for v_i, venue in enumerate(self.venues):
for sym in self.symbols: for sym in self.symbols:
price = base.get(sym, 100.0) * (1 + (i * 0.001) + (v_i * 0.0005)) price = base.get(sym, 100.0) * (1 + (i * 0.001) + (v_i * 0.0005))
yield MarketSignal(asset_symbol=sym, venue=venue, price=float(price), timestamp=t + timedelta(seconds=i)) asset = Asset(symbol=sym, type="equity")
ts = float((t + timedelta(seconds=i)).timestamp())
venue_code = 0.0 if venue == "VENUE-A" else 1.0
sig = MarketSignal(asset=asset, price=float(price), timestamp=ts, meta={"venue": venue_code})
yield sig

View File

@ -3,7 +3,7 @@ from __future__ import annotations
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Iterator from typing import Iterator
from ..dsl import MarketSignal from ..dsl import MarketSignal, Asset
class OptionsFeedAdapter: class OptionsFeedAdapter:
@ -23,4 +23,7 @@ class OptionsFeedAdapter:
for a in self.assets: for a in self.assets:
symbol = a.get("symbol") symbol = a.get("symbol")
price = 5.0 * (1 + i * 0.01) price = 5.0 * (1 + i * 0.01)
yield MarketSignal(asset_symbol=symbol, venue=venue, price=price, timestamp=t + timedelta(seconds=i)) asset = Asset(symbol=symbol, type=a.get("type", "call"))
ts = float((t + timedelta(seconds=i)).timestamp())
venue_code = 0.0 if venue == "VENUE-A" else 1.0
yield MarketSignal(asset=asset, price=float(price), timestamp=ts, meta={"venue": venue_code})

86
deltaforge/rt_engine.py Normal file
View File

@ -0,0 +1,86 @@
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,
}