fix(agents): tighten hypothesis prompt + normalize max_drawdown

Run reale phase1-real-001 ha rivelato due problemi:

1. 67% parse_error perche' qwen3 nestava indicatori non supportati
   (es. "(sma (indicator realized_vol 30) 150)"). Il prompt SYSTEM
   ora esplicita le regole strette: indicator non e' annidabile,
   sma/rsi/etc. esistono solo come 1o argomento di indicator,
   crossover/crossunder accetta espressioni-serie come (feature close)
   o (indicator sma N).

2. max_drawdown calcolato su equity assoluta (P&L in unita' BTC) +1.0
   produceva drawdown nominali enormi (>89000) per strategie con
   posizioni perdenti su BTC a $96k. Normalizziamo dividendo per il
   notional iniziale (close[0]), cosi' max_dd diventa drawdown
   relativo al wealth iniziale.

Test suite resta 122 PASSED, ruff e mypy clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-10 11:23:50 +02:00
parent 6a201c7e49
commit 15a4138bbd
2 changed files with 23 additions and 6 deletions
+6 -4
View File
@@ -72,10 +72,12 @@ class FalsificationAgent:
periods_per_year=8760, periods_per_year=8760,
sharpe_var=1.0, sharpe_var=1.0,
) )
# +1.0 sull'equity curve evita divisione per zero in max_drawdown / # Normalizza l'equity sul prezzo iniziale (notional di una position size 1).
# total_return: l'engine produce equity in valore assoluto partendo da # L'engine produce equity in unita' di P&L assoluto partendo da 0; per
# 0, ma le metriche sono definite su serie strettamente positive. # max_drawdown e total_return serve una serie strettamente positiva
equity_pos = result.equity_curve + 1.0 # interpretabile come "wealth ratio" rispetto al notional iniziale.
notional = float(ohlcv["close"].iloc[0])
equity_pos = (result.equity_curve / notional) + 1.0
return FalsificationReport( return FalsificationReport(
sharpe=sr, sharpe=sr,
dsr=dsr, dsr=dsr,
+17 -2
View File
@@ -43,9 +43,23 @@ con i seguenti verbi disponibili:
Comparatori: gt, lt, eq Comparatori: gt, lt, eq
Dati: feature, indicator, crossover, crossunder Dati: feature, indicator, crossover, crossunder
Indicatori disponibili: sma <length>, rsi <length>, atr <length>, macd, realized_vol <window>. Indicatori disponibili (calcolati implicitamente sul prezzo close):
sma <length>, rsi <length>, atr <length>, macd, realized_vol <window>.
Feature disponibili: open, high, low, close, volume. Feature disponibili: open, high, low, close, volume.
REGOLE STRETTE DI SINTASSI:
- (indicator <name> <args...>) restituisce una serie numerica. Es.
(indicator rsi 14), (indicator sma 50), (indicator macd 12 26 9).
- (feature <name>) restituisce la colonna OHLCV. Es. (feature close).
- Gli indicatori NON sono annidabili: NON puoi scrivere
(sma (indicator realized_vol 30) 150) o (indicator rsi (feature high) 14).
Le funzioni sma/rsi/etc. ESISTONO SOLO come argomenti di indicator,
non sono verbi indipendenti.
- Costanti numeriche (es. 70.0, 30, 0.02) sono valide come 2° operando di gt/lt/eq.
- crossover/crossunder accettano due espressioni-serie:
(crossover (feature close) (indicator sma 20)) — corretto.
(crossover (sma close 20) (sma close 50)) — ERRATO (sma non è verbo).
Le regole sono valutate in ordine; la prima che matcha vince per ogni timestamp. Le regole sono valutate in ordine; la prima che matcha vince per ogni timestamp.
La default action se nessuna regola matcha è 'flat'. La default action se nessuna regola matcha è 'flat'.
@@ -55,7 +69,8 @@ senza spiegazioni. Esempio formato:
```lisp ```lisp
(strategy (strategy
(when (gt (indicator rsi 14) 70.0) (entry-short)) (when (gt (indicator rsi 14) 70.0) (entry-short))
(when (lt (indicator rsi 14) 30.0) (entry-long))) (when (lt (indicator rsi 14) 30.0) (entry-long))
(when (crossover (feature close) (indicator sma 50)) (entry-long)))
``` ```
""" """