@@ -1519,6 +1519,15 @@ def log_decision(
15191519 logger .warning (f"[{ request_id } ] Failed to log decision: { e } " )
15201520
15211521
1522+ def log_signal_decision (request_id : str , decision : str , reason : str , ** fields ) -> None :
1523+ """Emit one concise decision line for accepted webhook signals."""
1524+ parts = [f"[{ request_id } ] SIGNAL DECISION: decision={ decision } " , f"reason={ reason } " ]
1525+ for key , value in fields .items ():
1526+ if value is not None :
1527+ parts .append (f"{ key } ={ value } " )
1528+ logger .info (" | " .join (parts ))
1529+
1530+
15221531def is_phase2_trade (trade : dict ) -> bool :
15231532 """
15241533 Prüft ob ein Trade ein Phase-2 Trade ist.
@@ -3337,6 +3346,37 @@ async def get_state():
33373346 "mode" : get_trading_mode_str (),
33383347 }
33393348
3349+
3350+ @app .get ("/debug/config" )
3351+ async def debug_config ():
3352+ """Runtime config/state for troubleshooting. Hidden when debug endpoints are disabled."""
3353+ if not getattr (settings , "DEBUG_ENDPOINTS_ENABLED" , False ):
3354+ raise HTTPException (status_code = 404 , detail = "Not Found" )
3355+
3356+ adapter = _get_market_data_adapter (app )
3357+ subs = getattr (adapter , "_subs" , set ()) if adapter else set ()
3358+ try :
3359+ active_subscriptions = len (subs )
3360+ except Exception :
3361+ active_subscriptions = 0
3362+
3363+ trading_info = get_trading_mode_info ()
3364+ return {
3365+ "ok" : True ,
3366+ "trading_mode" : trading_info ["trading_mode_effective" ],
3367+ "dry_run" : bool (getattr (settings , "DRY_RUN" , False )),
3368+ "paper_mode" : is_paper_trading (),
3369+ "execution_enabled" : bool (getattr (settings , "EXECUTION_ENABLED" , False )),
3370+ "market_data_ws_enabled" : bool (getattr (settings , "MARKET_DATA_WS_ENABLED" , False )),
3371+ "market_data_rtds_enabled" : bool (getattr (settings , "MARKET_DATA_RTDS_ENABLED" , False )),
3372+ "min_confidence" : int (getattr (settings , "MIN_CONFIDENCE" , 0 )),
3373+ "allow_conf_4" : bool (getattr (settings , "ALLOW_CONF_4" , False )),
3374+ "kill_switch_enabled" : bool (trading_info .get ("kill_switch_enabled" , False )),
3375+ "live_allowed_now" : bool (trading_info .get ("live_allowed_now" , False )),
3376+ "active_subscriptions" : active_subscriptions ,
3377+ "adapter_initialized" : adapter is not None ,
3378+ }
3379+
33403380@app .post ("/test" )
33413381def test ():
33423382 return {"ok" : True , "test" : "simple endpoint works" }
@@ -4233,6 +4273,7 @@ def webhook(payload: WebhookPayload):
42334273 if settings .REQUIRE_RAWCONF :
42344274 _blocked_conf_missing += 1
42354275 logger .info (f"[{ request_id } ] BLOCKED: rawConf missing (REQUIRE_RAWCONF=True)" )
4276+ log_signal_decision (request_id , "SKIP" , "rawconf_missing" )
42364277 try :
42374278 if confirmed_conf_key :
42384279 cleared = _confirmation_store .clear (confirmed_conf_key )
@@ -4251,6 +4292,7 @@ def webhook(payload: WebhookPayload):
42514292 else :
42524293 _blocked_conf_missing += 1
42534294 logger .info (f"[{ request_id } ] BLOCKED: rawConf missing (MISSING_RAWCONF_ACTION=block)" )
4295+ log_signal_decision (request_id , "SKIP" , "rawconf_missing" )
42544296 try :
42554297 if confirmed_conf_key :
42564298 cleared = _confirmation_store .clear (confirmed_conf_key )
@@ -4269,6 +4311,7 @@ def webhook(payload: WebhookPayload):
42694311 global _blocked_conf_low
42704312 _blocked_conf_low += 1
42714313 logger .info (f"[{ request_id } ] BLOCKED: rawConf={ raw_conf } < MIN_CONFIDENCE={ settings .MIN_CONFIDENCE } " )
4314+ log_signal_decision (request_id , "SKIP" , "rawconf_low" , raw_conf = raw_conf )
42724315 try :
42734316 if confirmed_conf_key :
42744317 cleared = _confirmation_store .clear (confirmed_conf_key )
@@ -4289,6 +4332,7 @@ def webhook(payload: WebhookPayload):
42894332 global _blocked_conf_high
42904333 _blocked_conf_high += 1
42914334 logger .info (f"[{ request_id } ] BLOCKED: rawConf={ raw_conf } > MAX_CONFIDENCE={ settings .MAX_CONFIDENCE } " )
4335+ log_signal_decision (request_id , "SKIP" , "rawconf_high" , raw_conf = raw_conf )
42924336 try :
42934337 if confirmed_conf_key :
42944338 cleared = _confirmation_store .clear (confirmed_conf_key )
@@ -4527,6 +4571,7 @@ def webhook(payload: WebhookPayload):
45274571
45284572 if not exposure_check .allowed :
45294573 logger .warning (f"[{ request_id } ] TRADE SKIPPED: { exposure_check .reason } " )
4574+ log_signal_decision (request_id , "SKIP" , "max_exposure" , detail = exposure_check .reason )
45304575 return {
45314576 "ok" : True ,
45324577 "ignored" : True ,
@@ -4547,6 +4592,7 @@ def webhook(payload: WebhookPayload):
45474592
45484593 if not direction_allowed :
45494594 logger .warning (f"[{ request_id } ] TRADE SKIPPED: { direction_reason } " )
4595+ log_signal_decision (request_id , "SKIP" , "direction_limit" , detail = direction_reason )
45504596 return {
45514597 "ok" : True ,
45524598 "ignored" : True ,
@@ -5095,6 +5141,7 @@ def webhook(payload: WebhookPayload):
50955141 # in Datei loggen (entry_price is guaranteed to be set at this point)
50965142 append_jsonl (settings .PAPER_LOG_PATH , would_order )
50975143 logger .info (f"[{ request_id } ] PAPER LOGGED TO: { settings .PAPER_LOG_PATH } " )
5144+ log_signal_decision (request_id , "ENTER" , "paper_trade_logged" , action = action , token_id = (chosen_token [:18 ] + "..." ) if chosen_token else None )
50985145 logger .debug (f"[{ request_id } ] PAPER ORDER: { would_order } " )
50995146 # debug instrumentation H4 - paper trade logged
51005147 try :
@@ -5119,6 +5166,7 @@ def webhook(payload: WebhookPayload):
51195166 )
51205167 else :
51215168 logger .warning (f"[{ request_id } ] NO PAPER ORDER (missing token or action)" )
5169+ log_signal_decision (request_id , "SKIP" , "missing_token_or_action" , action = action , has_token = bool (chosen_token ))
51225170
51235171 clob_raw = None
51245172 if market :
0 commit comments