@ -295,23 +295,38 @@ class PaperTradingEngine:
)
if engines :
# Residual reserve: engines that set residual_reserve_selected=True
# prevent later engines from picking the same event_id/symbol.
# Matches BacktestRunner._select_candidates_for_date().
reserved_event_ids : set [ str ] = {
ss . event_id for ss in strategy_states_after_exits . values ( )
}
reserved_symbols : set [ str ] = {
p . symbol for p in alpaca_positions_after_exits
if p . symbol in strategy_states_after_exits
}
for engine_cfg in engines :
prelimit = self . _config . signal . max_candidates_per_day
if self . _attention_service . engine_requires_attention ( engine_cfg ) :
prelimit = max ( prelimit * 5 , prelimit )
engine_candidates = select_candidates (
raw_rows = candidate_rows ,
universe_config = self . _config . universe ,
signal_config = self . _config . signal ,
event_type_profiles = self . _config . event_type_profiles or { } ,
strategy_engine = engine_cfg ,
excluded_event_ids = {
ss . event_id
for ss in strategy_states_after_exits . values ( )
} ,
excluded_symbols = { p . symbol for p in alpaca_positions_after_exits if p . symbol in strategy_states_after_exits } ,
truncate_to = prelimit ,
excluded_event_ids = reserved_event_ids ,
excluded_symbols = reserved_symbols ,
)
# Attention filtering (matches BacktestRunner)
engine_candidates = self . _attention_service . apply_filters (
engine_candidates , engine_cfg , self . _config . signal ,
)
# Residual reserve for next engine
if engine_cfg . residual_reserve_selected and engine_candidates :
reserved_event_ids . update ( c . event_id for c in engine_candidates )
reserved_symbols . update ( c . symbol . upper ( ) for c in engine_candidates )
engine_risk_used = engine_daily_risk_used . get ( engine_cfg . engine_id , 0.0 )
for candidate in engine_candidates :
@ -945,21 +960,30 @@ class PaperTradingEngine:
)
engine_list = engines if engines else [ None ]
reserved_event_ids : set [ str ] = { ss . event_id for ss in strategy_states . values ( ) }
reserved_symbols : set [ str ] = { p . symbol for p in alpaca_positions if p . symbol in strategy_states }
for engine_cfg in engine_list :
if engine_cfg is not None :
prelimit = self . _config . signal . max_candidates_per_day
if self . _attention_service . engine_requires_attention ( engine_cfg ) :
prelimit = max ( prelimit * 5 , prelimit )
engine_candidates = select_candidates (
raw_rows = candidate_rows ,
universe_config = self . _config . universe ,
signal_config = self . _config . signal ,
event_type_profiles = self . _config . event_type_profiles or { } ,
strategy_engine = engine_cfg ,
excluded_event_ids = { ss . event_id for ss in strategy_states . values ( ) } ,
excluded_symbols = { p . symbol for p in alpaca_positions if p . symbol in strategy_states } ,
truncate_to = prelimit ,
excluded_event_ids = reserved_event_ids ,
excluded_symbols = reserved_symbols ,
)
# Attention filtering (matches BacktestRunner)
engine_candidates = self . _attention_service . apply_filters (
engine_candidates , engine_cfg , self . _config . signal ,
)
if engine_cfg . residual_reserve_selected and engine_candidates :
reserved_event_ids . update ( c . event_id for c in engine_candidates )
reserved_symbols . update ( c . symbol . upper ( ) for c in engine_candidates )
engine_risk_used = engine_daily_risk_used . get ( engine_cfg . engine_id , 0.0 )
else :
engine_candidates = select_candidates (
@ -967,8 +991,8 @@ class PaperTradingEngine:
universe_config = self . _config . universe ,
signal_config = self . _config . signal ,
event_type_profiles = self . _config . event_type_profiles or { } ,
excluded_event_ids = { ss. event_i d for ss in strategy _stat es. valu es( ) } ,
excluded_symbols = { p . symbol for p in alpaca_positions if p . symbol in strategy_states } ,
excluded_event_ids = re ser ved_event_id s,
excluded_symbols = reserved_symbols ,
)
engine_risk_used = 0.0
@ -1296,6 +1320,24 @@ class PaperTradingEngine:
if len ( closes ) > = sma_period :
macro [ f " { key_prefix } _sma_ { sma_period } " ] = sum ( closes [ - sma_period : ] ) / sma_period
# Fetch FRED macro data (VIX, HY spread) for regime sizing
# Matches SnapshotStore._fetch_macro() which loads MacroObservation from DB
try :
from libs . oracle_client import FredService , OracleClient as _OC
async with _OC ( base_url = self . _detector . _oracle_url ) as fred_client :
fred_svc = FredService ( fred_client )
for series_id in ( " VIXCLS " , " BAMLH0A0HYM2 " ) :
try :
resp = await fred_svc . get_observations ( series_id , start = start . isoformat ( ) , end = date . isoformat ( ) )
if resp . observations :
latest = [ o for o in resp . observations if o . value is not None ]
if latest :
macro [ series_id ] = latest [ - 1 ] . value
except Exception :
pass
except Exception :
pass
return macro
except Exception as exc :