← FORGE

FORGE — Feature-Oriented Rule Generation Engine

FORGE è un sistema di ricerca quantitativa per la scoperta sistematica di regole di trading algoritmico da dati storici di mercato. A partire da una KPI Table (OHLCV + indicatori tecnici), FORGE identifica eventi booleani con struttura temporale stabile, ne misura il potere predittivo rispetto a un target economico derivato dai dati, e produce contratti formali pronti per la validazione operativa.

🇬🇧 English version


Cosa fa FORGE, in parole semplici

Se fai trading — o lavori con chi lo fa — probabilmente hai già sentito frasi tipo "ogni volta che succede X, il prezzo tende a salire." Individuare un pattern del genere è la parte facile. Quella difficile è capire se sia reale, o se sembri buono solo perché sono state provate abbastanza idee che una, per puro caso, doveva per forza sembrare buona. È esattamente la trappola che FORGE è costruito per evitare, in quattro passaggi:

  1. Cerca un pattern ripetibile nella storia di prezzi e indicatori — senza mai guardare cosa succede dopo, così il pattern non ha modo di "barare" conoscendo di nascosto il futuro.
  2. Verifica se quel pattern predice davvero qualcosa — il prezzo si muove in modo affidabile in una direzione, abbastanza spesso e abbastanza da contare?
  3. Simula il trading per davvero — commissioni reali, esecuzione realistica degli ordini, e test solo su dati che il pattern non ha mai visto mentre veniva scoperto.
  4. Verifica se regge anche altrove — su altri asset, non solo su quello su cui è stato scoperto.

Ogni pattern esce da questo processo con un verdetto onesto — funziona, è al limite, oppure non regge — più le ragioni specifiche dietro a quel verdetto, mai un punteggio a scatola chiusa. Nessun pattern viene mai aggiustato a posteriori per farlo sembrare migliore; una regola che non supera la soglia viene riportata così com'è, non rimaneggiata di nascosto finché non la supera.

Una cosa che FORGE deliberatamente non fa: piazzare ordini, o parlare con un exchange. È uno strumento di ricerca che ti dice quali idee vale la pena approfondire e passa il testimone con i dettagli operativi (quando entrare, quando uscire, quanto è forte l'evidenza) — trasformare questo in trading dal vivo è un passo separato e deliberato, affidato a qualunque sistema tu usi davvero per eseguire gli ordini.

Il resto di questo documento entra nel funzionamento tecnico, per chi vuole eseguire FORGE in prima persona.


Perché FORGE

La ricerca sistematica di edge di trading soffre di tre problemi ricorrenti:

FORGE affronta tutti e tre con un'architettura a pipeline rigidamente separata: ogni modulo risponde a una sola domanda e passa al successivo solo un artefatto formale. Nessun modulo può accedere ai dati del modulo successivo; nessuna soglia può essere ricalibrata dopo la scoperta.


Pipeline

KPI Table (OHLCV + indicatori tecnici)
    │
    ▼
┌──────────────────────────────────────────────────────────────────┐
│  Modulo 0 — Market Context                                       │
│  Classifica ogni barra per regime di mercato (5 livelli).        │
│  Output: KPI Table + colonne 'regime' e 'regime_stable'          │
└──────────────────────────────────────────────────────────────────┘
    │
    ▼
┌──────────────────────────────────────────────────────────────────┐
│  Modulo 1 — Event Discovery                                      │
│  Scopre eventi booleani dalla struttura temporale degli          │
│  indicatori. Non vede mai il forward return.                     │
│  Output: list[EventCandidate]                                    │
└──────────────────────────────────────────────────────────────────┘
    │
    ▼
┌──────────────────────────────────────────────────────────────────┐
│  Modulo 2 — Alpha Discovery                                      │
│  Deriva il target per evento, misura il potere predittivo IS,    │
│  conferma sull'OOS tail. Prima esposizione al forward return.    │
│  Output: list[AlphaContract]                                     │
└──────────────────────────────────────────────────────────────────┘
    │
    ▼
┌──────────────────────────────────────────────────────────────────┐
│  Modulo 3 — Rule Discovery                                       │
│  Backtest realistico con order mechanics, fee, walk-forward OOS. │
│  Output: EDGE / PARTIAL-EDGE / NON-EDGE + parametri operativi   │
└──────────────────────────────────────────────────────────────────┘
    │
    ▼
┌──────────────────────────────────────────────────────────────────┐
│  Modulo 4 — Rule Registry                                        │
│  Deduplicazione, backtest cross-ticker, classificazione genericity│
│  Output: tabella piatta + report HTML autocontenuto              │
└──────────────────────────────────────────────────────────────────┘

Invarianti fondamentali

Invariante Cosa previene
Modulo 1 non vede mai il forward return Look-ahead bias nella selezione degli eventi
Le soglie sono immutabili dopo la scoperta Ottimizzazione delle soglie sul campione di valutazione
Orizzonte, direzione e take-profit sono derivati dai dati per ogni evento Assunzioni economiche che pre-cuociono il risultato
Il verdetto operativo è vincolato al walk-forward OOS (Modulo 3); la conferma OOS di Alpha è registrata su ogni contratto Conferma a posteriori di una conclusione già decisa

Installazione

FORGE dipende unicamente da numpy e pandas. Nessuna dipendenza da scipy, statsmodels o librerie ML: tutte le primitive statistiche (Spearman, t-test, regressione OU, FDR Benjamini-Hochberg, funzione beta incompleta) sono implementate in puro numpy.

pip install forgedge

Quick start

import pandas as pd
from forgedge import forge

# KPI Table con OHLCV + indicatori tecnici (colonna 'close' richiesta)
kpi = pd.read_parquet("kpi_table.parquet")

# Pipeline completa: da KPI Table a regole validate in una singola chiamata
result = forge(kpi, ticker="BTCUSDC", timeframe="1H")

print(result.summary())                         # una riga per candidato + rule_verdict
for contract, response in result.edges():       # solo EDGE / PARTIAL-EDGE
    print(contract.alpha_id, response.verdict)
print(result.registry.summary())                # Modulo 4 — regole catalogate

Prima che tutto questo giri, forge() risolve ogni campo di configurazione non impostato rispetto al timeframe/schema della sessione e verifica l'intero bundle per contraddizioni interne — di default (strict=True) solleva subito ValueError se ne trova una che farebbe fallire ogni candidato per ragioni che non c'entrano nulla col segnale, invece di lasciare che la run finisca e produca un muro di rigetti inspiegati. strict=False declassa questo a un warning e gira comunque; forgedge.config_report(...) esegue lo stesso controllo in standalone, prima di impegnarsi in una run completa.

Su un timeframe daily o più lento la griglia di holding period di default viene sostituita automaticamente da una calibrata sul daily (la griglia standard è calibrata su barre ~orarie); passando un proprio AlphaConfig si mantiene il pieno controllo. Per una configurazione per-modulo coerente in frequenza usare forgedge.presets.forge_preset("balanced", timeframe="1D", asset=...). La griglia di ogni evento viene inoltre arricchita con orizzonti a 0.5×/1×/2× la finestra dominante del suo indicatore (AlphaConfig.horizon_enrichment — un'unione, mai una restrizione, con cap statistico perché le finestre di condizionamento lente non possano chiedere holding period non misurabili; le ipotesi aggiunte sono contate dal ledger e prezzate dal rotation null).

Di default forge() esegue anche il fast rotation null a livello di ricerca — la distribuzione nulla esatta del miglior eccesso standardizzato su ogni offset circolare, calcolata via FFT in ~secondi — e un verdetto EDGE pieno richiede in aggiunta di batterla (rotation_p <= 0.05): una regola che ha solo vinto la lotteria del multiple testing della propria sessione di discovery viene declassata a PARTIAL-EDGE. La superficie di ipotesi della sessione è registrata su ForgeResult.ledger; disattivabile con fast_null=False.

Gli split temporali sono purged: le barre in-sample la cui finestra forward attraversa il confine IS/OOS sono escluse da ogni misura di Alpha Discovery, e le finestre train del walk-forward terminano un worst-case trade span prima della finestra test (vedi forgedge.timebudget.TimeBudget — passandone uno a forge() tutti i moduli condividono un unico asse, con embargo opzionale).

Rule Discovery seleziona il punto operativo solo dentro le finestre train del walk-forward (RuleDiscoveryConfig.selection_mode="walk_forward", il default): i parametri pubblicati vengono dall'ultima finestra train (o dal consenso tra le finestre), e ogni metrica che alimenta il verdetto è calcolata sullo span di selezione — l'ultima finestra test non è mai letta da alcuna selezione. selection_mode="full_sample" ripristina il comportamento legacy full-table.

I verdetti sono power-aware: un potenziale EDGE/PARTIAL-EDGE la cui evidenza out-of-sample aggregata non può sostenerlo (troppi pochi trade test aggregati, o una minimum detectable expectancy sopra l'effetto dichiarato) viene emesso come INSUFFICIENT-DATA — non tradeable, ma conserva la sua ValidatedRule per la ri-valutazione su più dati. La valutazione legge solo il ledger concatenato delle finestre test, mai le singole finestre del walk-forward (corte by design). Disattivabile con SelectionCriteria(power_gate=False).

Sessioni multi-ticker con forge_multi:

from forgedge import forge_multi

frames = {"BTCUSDC": btc_kpi, "ETHUSDC": eth_kpi, "ADAUSDC": ada_kpi}
results, registry = forge_multi(frames, timeframe="1H")

# GENERIC: la regola si generalizza su ≥ 2/3 dei ticker testati
df = registry.flat_table()
print(df[["rule_id", "classification", "pf", "cross_ticker_score"]])

# Report HTML autocontenuto (SVG inline, nessuna CDN)
html = registry.html_report(timeframe="1H")
with open("report.html", "w") as f:
    f.write(html)

Monitoraggio delle regole pubblicate su candele fresche:

from forgedge import RuleSpec, rule_performance_report

# Una spec per ogni regola tradeable di un run forge() — is_end / verdict /
# expectancy OOS vengono compilati automaticamente dagli artefatti di sessione.
specs = RuleSpec.from_forge_result(result)

# Oppure passa direttamente il ForgeResult — stesso effetto.
html = rule_performance_report(result, candele_fresche)
with open("rules_report.html", "w") as f:
    f.write(html)

Ogni regola viene rieseguita in modo deterministico sulle candele fornite (lo stesso percorso EventCandidate.apply() usato da Rule Discovery) — le candele non devono essere la tabella di discovery, quindi è il modo naturale per monitorare le regole pubblicate su dati raccolti dopo la discovery. Il report mostra, per regola: equity vs buy & hold su doppio asse (scale indipendenti — confronta le forme, non le grandezze), un trend di attivazione mensile diviso in in-sample/out-of-sample, la distribuzione gain/loss, le KDE delle distribuzioni dei rendimenti — low/close/high, ognuno il rendimento forward sull'orizzonte di holding (target_h barre dopo la barra del segnale, ancorato al close di quella barra, orientato per direzione: la stessa grandezza da cui Alpha Discovery deriva il target e su cui Rule Discovery fa trading), base vs evento — uno scatter MAE→net (rischio intra-trade per queste regole senza stop), l'expectancy rolling (rilevatore di decadimento dell'edge), la performance per regime, gli ultimi trade e un badge "segnale attivo ora".


I tre concetti

FORGE struttura il processo di scoperta attorno a tre concetti formali che rispondono ciascuno a una domanda distinta e producono un artefatto distinto.

Evento — osservare il mercato senza bias

Un evento è una condizione booleana sulle barre storiche, scoperta dalla struttura temporale degli indicatori senza mai calcolare un forward return. Le soglie sono distribuzionali (percentili specifici per asset) e immutabili una volta fissate.

c = candidates[0]
print(c.expression)            # "rsi_14 < 31.2 AND spread_ema_9_25 < -0.0118"
signal = c.apply(new_kpi)      # pd.Series bool — deterministico, senza look-ahead

Il ConsistencyGate filtra gli eventi con struttura temporale instabile (attivazioni insufficienti, clustering stagionale, bassa frequenza mensile) prima che venga calcolato qualsiasi rendimento.

Alpha — misurare il potere predittivo

Un alpha è la risposta empirica alla domanda: dato che l'evento si è attivato, cosa succede statisticamente nelle prossime h barre? Orizzonte, direzione e take-profit (sell_pct) sono tutti derivati dai dati — mai assunti — scansionando |mean_advantage|/√h su una grid di orizzonti e prendendo il quantile MFE delle barre attive.

c = promoted[0]
dt = c.derived_target
print(f"{dt.direction} a h={dt.holding_period_h}h  sell_pct={dt.sell_pct:.4f}")
print(f"Grade {c.alpha_score.grade}  |  OOS lift: {c.oos_validation.lift:.4f}")

L'unico gate di rigetto rigido è la direzione indeterminata (nessun vantaggio finito su nessun orizzonte). Tutte le altre metriche statistiche (IC, Cohen's d, lift, FDR) contribuiscono al grade A–D senza bloccare la promozione.

Regola — tradare in modo realistico

Una regola è il verdetto operativo su un contratto alpha. Rule Discovery esegue un backtest realistico — uscita a take-profit, stop a orizzonte, commissioni per lato — valutato prima con un ingresso a mercato (quel verdetto è autoritativo), poi opzionalmente con un ingresso a limite adottato solo se supera condizioni out-of-sample rigorose — e valida la migliore configurazione di parametri su un walk-forward OOS rolling.

resp = RuleDiscovery(ed.df, contract, cand).run()
print(resp.verdict)                               # "EDGE", "PARTIAL-EDGE", "NON-EDGE"
if resp.is_edge:
    p = resp.validated_rule.params
    print(f"Entry: limit -{p.buy_drop_pct:.2%}  TP: +{p.sell_pct:.2%}  h={p.target_h}")
    print(f"IS PF: {resp.in_sample_summary.profit_factor:.2f}"
          f"  WF consistency: {resp.walk_forward.consistency:.0%}")

Panoramica dei moduli

Modulo Domanda cui risponde Output principale
0 — Market Context In che regime si trova questa barra? Colonna regime (5 livelli), regime_stable
1 — Event Discovery Questa configurazione dell'indicatore è stabile e ripetibile? EventCandidate — soglie immutabili, apply()
2 — Alpha Discovery L'evento predice un rendimento orientato? AlphaContract — target derivato, grade A–D
3 — Rule Discovery Questo alpha è profittevole con order mechanics reali? RuleDiscoveryResponse — verdetto EDGE, ValidatedRule
4 — Rule Registry Questa regola si generalizza su altri ticker? Tabella piatta, report HTML — GENERIC / PARTIAL / SPECIFIC

Stato implementazione

Modulo Stato
0 — Market Context ✅ Implementato
1 — Event Discovery ✅ Implementato
2 — Alpha Discovery ✅ Implementato
3 — Rule Discovery ✅ Implementato
4 — Rule Registry 🚧 WIP

Documentazione

Inizia dal manuale — docs/manuale-it.md è un'unica guida completa, verificata con esempi, che copre l'installazione fino all'architettura di produzione, il troubleshooting, best practice/anti-pattern, una FAQ e un glossario. Ogni cosa al suo interno è stata verificata contro il sorgente attuale e, dove è citato un numero, contro una run reale. Tutto quello sotto è materiale di riferimento più stretto e complementare.

File Contenuto
docs/manuale-it.md Il manuale completo, verificato con esempi — dall'installazione alla produzione, l'API di ogni modulo, troubleshooting, FAQ
concepts_it.md Guida concettuale: evento, alpha e regola — dal mercato al segnale
how_to_use_it.md Guida pratica alla pipeline end-to-end per produzione
modulo_0_it.md Market Context: classificazione regime, EMAProxy, configurazione
modulo_1_it.md Event Discovery: pipeline 5-step, ConsistencyGate, EventCandidate
modulo_2_it.md Alpha Discovery: target derivato, IC, OOS, AlphaContract
modulo_3_it.md Rule Discovery: backtest, verdetto EDGE, walk-forward, report
modulo_4_it.md Rule Registry: deduplicazione, cross-ticker, genericity, export
configuration_it.md Riferimento completo alla configurazione: ogni campo dataclass, tipo, default e descrizione
playground_it.md forgedge.playground: helper di analisi di sola lettura sopra i ForgeResult messi in pool
deployment_it.md forgedge.deployment: gate di promozione, export delle regole, manifest di monitoraggio per portare le regole scoperte in produzione
experiment_it.md forgedge.experiment: StepWiseDiscovery — una ricerca partition & compose che fa crescere una regola confermata sull'hold-out una condizione AND alla volta sopra forge()

Lavori su questo codebase con un agente AI? La skill forgedge in .claude/skills/forgedge/ copre l'API della libreria, i verdetti e gli invarianti della pipeline in una forma che un agente può usare direttamente.


Licenza

MIT