Refactor code structure for improved readability and maintainability

This commit is contained in:
2026-08-05 10:05:20 +02:00
parent 61f1e59964
commit f96ed670ca
239 changed files with 23858 additions and 730 deletions
+150
View File
@@ -0,0 +1,150 @@
{
"_comment": "Encelado — configurazione unica. Ogni numero qui sotto è stato verificato su due dataset indipendenti: 4.756 barre giornaliere Bitstamp (2012-2025, ripiegate da 6,8 milioni di barre da un minuto) e 3.260 barre Binance (2017-2026). Vedi il README.",
"alpaca": {
"paper": true,
"dataFeed": "iex",
"requestsPerMinute": 180,
"httpTimeoutSeconds": 15,
"maxRetries": 4
},
"engine": {
"assetClass": "crypto",
"_timeFrame": "Giornaliero. Le stesse regole su barre orarie perdono il 99% del capitale: con ~50 bps di costo per giro completo la frequenza uccide prima della direzione.",
"timeFrame": "1Day",
"_warmup": "La media è a 100 giorni. 220 barre danno margine.",
"warmupBars": 220,
"tradeOnlyRegularHours": false,
"flattenBeforeCloseMinutes": 0,
"_crypto": "Alpaca sulle crypto vuole quantità frazionarie e non supporta i bracket order: lo stop lo tiene l'engine e lo verifica a ogni quotazione.",
"allowFractionalShares": true,
"useBracketOrders": false,
"entryOrderType": "limit",
"limitOffsetBps": 8,
"dryRun": false,
"_reconcile": "Ogni quanto il bot ricontrolla conto, posizioni e ordini contro il broker, e chiede le barre già chiuse. È anche il momento in cui si accorge che una barra nuova è disponibile da valutare, quindi abbassarlo lo rende più reattivo all'apertura di una barra.",
"reconcileSeconds": 30,
"_status": "Riepilogo periodico nel log: contatori, latenze, stato delle connessioni.",
"statusSeconds": 60,
"_explain": "Ogni quanto il bot rilegge cosa farebbe al prezzo attuale e lo scrive nel log, se è cambiato rispetto a prima. Su barre giornaliere il bot è legittimamente silenzioso per settimane, e da fuori il silenzio è indistinguibile da un blocco: questa riga lo trasforma in una frase.",
"explainSeconds": 5,
"maxQuoteAgeSeconds": 120,
"closeOnShutdown": false
},
"risk": {
"_sizing": "Questa strategia compete con il comprare e tenere, quindi quando è dentro deve esserci per intero: qualunque frazione inferiore perde la gara in partenza. stakePct 1.0 impegna tutto il saldo disponibile; il risk engine si ferma comunque al 98% per lasciare spazio alle commissioni.",
"stakePct": 1.0,
"stakeAmount": 0,
"_risk": "Non usato finché stakePct è impostato, ma deve restare valido: è il criterio di riserva se un giorno azzeri stakePct.",
"maxRiskPerTradePct": 0.05,
"_caps": "A 1.0 perché con un solo asset e stake pieno la posizione È il portafoglio. Abbassarli qui significa restare parzialmente liquidi e perdere rendimento senza guadagnare protezione: la protezione la dà l'uscita sotto la media.",
"maxPositionNotionalPct": 1.0,
"maxGrossExposurePct": 1.0,
"_openPositions": "0 = nessun limite. Nota però che con un solo simbolo il numero di posizioni contemporanee resta 1 comunque: il risk engine rifiuta un secondo ingresso sullo stesso strumento con 'already in position'. E con stakePct 1.0 la prima posizione impegna tutto il saldo, quindi una seconda non avrebbe con cosa aprirsi. Questo limite torna a contare quando aggiungi simboli.",
"maxOpenPositions": 0,
"_frequency": "0 = nessun limite. Il bot può aprire quante posizioni vuole e fare quante operazioni vuole: a fermarlo è la strategia, non un contatore. Attenzione: erano una rete contro un bug (un ciclo che riapre la stessa posizione mille volte costa mille commissioni). Con 0 quella rete non c'è più.",
"maxTradesPerDay": 0,
"maxTradesPerSymbolPerDay": 0,
"minSecondsBetweenEntries": 0,
"_dailyLoss": "Kill switch giornaliero. Al 25% perché su BTC un -20% in un giorno è successo più volte e non è una ragione per smettere: la strategia esce quando cede la media, non quando fa male. Troppo stretto qui significa liquidare sul minimo.",
"maxDailyLossPct": 0.25,
"maxDailyProfitPct": 0,
"maxRelativeSpread": 0.0015,
"minPrice": 0.01,
"maxPrice": 10000000,
"minOrderNotional": 25,
"maxOrderNotional": 0,
"_shorting": "Alpaca non consente lo short sulle crypto. La strategia è long/flat.",
"allowShorting": false,
"_stop": "Rete di sicurezza per un gap, non il controllo del rischio. Quello vero è l'uscita sotto la media: uno stop stretto venderebbe e poi aspetterebbe un nuovo incrocio per rientrare, che è esattamente come il modello precedente trasformava le oscillazioni in perdite realizzate.",
"defaultStopPct": 0.35,
"maxStopDistancePct": 0.60
},
"logging": {
"_level": "trace | debug | info | warn | error | none. 'debug' registra anche ogni segnale scartato e ogni rifiuto del risk engine: utile per capire perché il bot NON ha fatto qualcosa.",
"level": "debug",
"_directory": "Dove salvare tutti gli output. Relativa all'eseguibile, oppure un percorso assoluto tipo D:\\encelado-logs. Si cambia anche da Impostazioni → Log, che verifica di potervi scrivere prima di salvare.",
"directory": "logs",
"console": false,
"file": "encelado.log",
"_rotation": "Ruota encelado.log in encelado.1.log e così via, tenendo gli ultimi 10.",
"maxFileSizeMb": 32,
"maxFiles": 10,
"_analysis": "decisions.csv ha una riga per ogni barra valutata con tutti gli indicatori; executions.csv ha una riga per ogni segnale arrivato agli ordini, con il verdetto del risk engine. Si uniscono su decisionId. Sono il materiale per migliorare il modello.",
"tradeJournal": "trades.jsonl",
"decisionLog": "decisions.csv",
"executionLog": "executions.csv",
"_verbose": "Con logMarketData attivo e level=trace registra ogni singola quotazione e ogni print. File enormi: serve solo per diagnosticare il flusso dati.",
"logMarketData": false,
"_everyBar": "Scrive una riga per ogni barra da un minuto che arriva dallo stream, non solo per quelle che chiudono una barra della strategia. Su barre giornaliere 1439 minuti su 1440 vengono assorbiti in silenzio: senza questo il log non mostra nulla per ventiquattr'ore e il bot sembra fermo.",
"logEveryBar": true,
"_inApp": "Quante righe tiene la striscia ATTIVITÀ nella pagina Stato e quante ne tiene la scheda Log. La seconda è il tetto di memoria del log in-app. Il file su disco resta completo comunque.",
"statusLines": 200,
"bufferedLines": 5000
},
"ui": {
"url": "http://localhost:5088",
"autoStartBot": false,
"openBrowser": false
},
"_symbols": "Solo BTC/USD. ETH è stato tolto: la strategia è tarata e verificata su BTC, e con stakePct 1.0 un secondo asset dimezzerebbe l'esposizione al primo senza che nessun backtest lo giustifichi.",
"symbols": [
{
"symbol": "BTC/USD",
"strategy": "trend-filter",
"enabled": true,
"parameters": {
"_period": "Media a 100 giorni. È l'unico valore che batte il comprare e tenere su ENTRAMBI i dataset: 120 rende di più su Bitstamp ma perde su Binance, 200 perde su tutti e due. La riga dei 100 giorni vince su entrambi a qualunque banda.",
"period": 100,
"_band": "Isteresi, non un filtro: si entra il 2% sopra la media e si esce il 2% sotto, così un prezzo appoggiato alla media non genera un'operazione ogni due giorni. Dimezza gli scambi lasciando il rendimento dov'era.",
"band": 0.02,
"_stop": "Rete per un gap. La vera uscita è la media.",
"stopPct": 0.35,
"_cvd": "Gate di order flow, disattivato. Misurato su Binance con il volume taker: alzandolo il Calmar scende da 0,71 a 0,66 a 0,64. Serviva al modello precedente, che operava di rado e poteva permettersi di aspettare conferma; qui ogni barra passata ad aspettare è una barra che non compone. Il valore resta calcolato e registrato nei log.",
"cvdThreshold": 0,
"cvdPeriod": 10,
"cvdNormPeriod": 60,
"_diagnostics": "Solo per il pannello e i log, non entrano in nessuna decisione.",
"volPeriod": 30,
"barsPerYear": 365,
"atrPeriod": 14,
"allowShort": 0
}
}
]
}
@@ -0,0 +1,12 @@
{
"_comment": "Copy this file to encelado.local.json (gitignored) next to encelado.json. It is merged on top of the main config, so it only needs the keys you want to override. Environment variables still win over both.",
"alpaca": {
"keyId": "PK...........",
"secretKey": "................................"
},
"engine": {
"dryRun": true
}
}