Add score and event_type to trade blotter output

FilledTrade now carries event_type and score from the Candidate.
These fields are written to trade_blotter.parquet and displayed in
paper backtest trade logs.

Previously score showed as 0.00 for all trades because the field
wasn't propagated from Candidate → FilledTrade → Parquet.

Score=0.00 is valid for trades from engines with score_threshold_override=0.0
(e.g. guidance_unknown_orderly) where engine gates, not score, determine entry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
main
I Luk Kim 5 months ago
parent 07bcfbe51d
commit 529477727f

@ -84,10 +84,14 @@ def write_trade_blotter(
"event_id": t.event_id,
"symbol": t.symbol,
"event_date": t.event_date.isoformat() if t.event_date else None,
"event_type": t.event_type,
"score": t.score,
"timing_class": t.timing_class,
"engine_id": t.engine_id,
"entry_timing_policy": t.entry_timing_policy,
"shadow_only": t.shadow_only,
"parent_position_id": t.parent_position_id,
"is_add_on": t.is_add_on,
"entry_date": t.entry_date.isoformat(),
"exit_date": t.exit_date.isoformat(),
"entry_price": t.entry_price,
@ -155,6 +159,8 @@ def write_position_timeline(
"engine_id": t.engine_id,
"entry_timing_policy": t.entry_timing_policy,
"shadow_only": t.shadow_only,
"parent_position_id": t.parent_position_id,
"is_add_on": t.is_add_on,
"entry_date": t.entry_date.isoformat(),
"exit_date": t.exit_date.isoformat(),
"entry_price": t.entry_price,
@ -179,6 +185,8 @@ def write_position_timeline(
"engine_id": p.plan.engine_id,
"entry_timing_policy": p.plan.entry_timing_policy,
"shadow_only": p.plan.shadow_only,
"parent_position_id": p.parent_position_id,
"is_add_on": p.is_add_on,
"entry_date": p.entry_date.isoformat(),
"exit_date": None,
"entry_price": p.entry_price,

@ -121,6 +121,8 @@ class FilledTrade(BaseModel):
event_id: str
symbol: str
event_date: dt.date | None = None
event_type: str = ""
score: float = 0.0
timing_class: str = "unknown"
engine_id: str = "default"
entry_timing_policy: str = "next_open"
@ -337,6 +339,7 @@ class StrategyEngineConfig(BaseModel):
engine_id: str
event_types: list[str] = Field(default_factory=list)
entry_conventions: list[str] | None = None
allowed_macro_regimes: list[str] | None = None
event_directions: list[str] | None = None
guidance_statuses: list[str] | None = None
filing_time_buckets: list[str] | None = None

@ -450,6 +450,8 @@ def _build_filled_trade_partial(
event_id=position.plan.candidate.event_id,
symbol=position.plan.candidate.symbol,
event_date=position.plan.event_date or position.plan.candidate.event_date,
event_type=position.plan.candidate.event_type or "",
score=position.plan.candidate.score or 0.0,
timing_class=position.plan.timing_class,
engine_id=position.plan.engine_id,
entry_timing_policy=position.plan.entry_timing_policy,
@ -511,6 +513,8 @@ def _build_filled_trade(
event_id=position.plan.candidate.event_id,
symbol=position.plan.candidate.symbol,
event_date=position.plan.event_date or position.plan.candidate.event_date,
event_type=position.plan.candidate.event_type or "",
score=position.plan.candidate.score or 0.0,
timing_class=position.plan.timing_class,
engine_id=position.plan.engine_id,
entry_timing_policy=position.plan.entry_timing_policy,

Loading…
Cancel
Save