273 lines
8.3 KiB
Markdown
273 lines
8.3 KiB
Markdown
# ETH↔USDT Swap Advisor — README
|
||
|
||
> Demone giornaliero che **prevede il cambio ETH/USDT** e ti **dice quando swappare**. Non esegue ordini: **notifica su Matrix** e lascia **l’ultima parola a un essere umano**.
|
||
|
||
---
|
||
|
||
## ✨ Cosa fa
|
||
|
||
1. **Scarica** gli ultimi *kline* da Binance per il pair ETH/USDT (fino a ~300 giorni).
|
||
2. **Costruisce un dataset** di log-return e feature derivate.
|
||
3. **Addestra** una RNN **LSTM (64 unità)** con:
|
||
|
||
* perdita **Huber** (robusta agli outlier),
|
||
* **gradient clipping**,
|
||
* **early stopping** (sulla media delle loss: si ferma quando scende sotto una frazione della loss iniziale o al max di epoche),
|
||
* split **train/validation**.
|
||
4. **Predice** la **variazione relativa di domani** (Δ%).
|
||
5. **Interroga THORNode** per stimare **fee/quote** di uno swap di riferimento.
|
||
6. **Decide** tra: `HOLD`, `SWAP_AB` (ETH→USDT), `SWAP_BA` (USDT→ETH) **solo se** il vantaggio atteso supera fee + margine di sicurezza.
|
||
7. **Non esegue** lo swap: **stampa istruzioni** e **invia una notifica Matrix** (se configurata).
|
||
8. **Mantiene stato locale** per evitare decisioni duplicate ravvicinate.
|
||
|
||
---
|
||
|
||
## 🧠 Modello / Pipeline ML
|
||
|
||
* **RNN:** LSTM a **64 unità** su finestre temporali (sequenze) dei log-return.
|
||
* **Target:** variazione percentuale del prezzo *close* del giorno successivo.
|
||
* **Feature principali:** log-return, medie mobili/volatilità (rolling), normalizzazione.
|
||
* **Loss:** **Huber**; **optimizer** Adam; **gradient clipping** per stabilità.
|
||
* **Early stopping:** si arresta quando `avgLoss ≤ firstLoss × EARLY_STOP_PCT` (o raggiunte `MAX_EPOCHS`).
|
||
* **Validazione:** MAE su hold-out set per monitoraggio overfitting.
|
||
* **Persistenza:** salvataggio modello e scaler su disco.
|
||
|
||
---
|
||
|
||
## 🔎 Logica decisionale (semplificata)
|
||
|
||
1. **Predizione** `pred_rel_move` (es. +0.8%).
|
||
2. **Quote THORNode** → **fee_totale** (bp o valore assoluto) per importi di riferimento.
|
||
3. **Edge atteso** = `|pred_rel_move| − fee_totale − MARGINE_SICUREZZA`.
|
||
4. Se `edge ≥ 0`:
|
||
|
||
* se `pred_rel_move > 0` ⇒ **`SWAP_BA`** *(USDT→ETH)*;
|
||
* se `pred_rel_move < 0` ⇒ **`SWAP_AB`** *(ETH→USDT)*;
|
||
* applica **isteresi** per evitare flip-flop.
|
||
5. Altrimenti **`HOLD`**.
|
||
|
||
**Esempio messaggi:**
|
||
|
||
* `decision: dir=HOLD pred=+0.36% fee=0.48% edge=-0.12%`
|
||
* `decision: dir=SWAP_AB (ETH→USDT) pred=-1.25% fee=0.40% edge=+0.85%`
|
||
* `decision: dir=SWAP_BA (USDT→ETH) pred=+0.90% fee=0.35% edge=+0.55%`
|
||
|
||
---
|
||
|
||
## 🧩 Perché Matrix
|
||
|
||
Il demone **non esegue ordini**: invia **notifiche su Matrix** con la decisione, i numeri (predizione, fee, edge) e le **istruzioni manuali** per lo swap. In questo modo:
|
||
|
||
* c’è **supervisione umana**,
|
||
* si evitano ordini indesiderati,
|
||
* si mantiene un audit trail nel canale Matrix.
|
||
|
||
**Formato notifica (esempio):**
|
||
|
||
```
|
||
[ETH/USDT] 2025-09-28
|
||
Decisione: SWAP_AB (ETH→USDT)
|
||
Pred: -1.25% | Fee stimata: 0.40% | Edge: +0.85%
|
||
Quote THORNode (ref): 5.00 ETH → 8,750.00 USDT
|
||
Istruzioni: eseguire swap su THORChain con slip <= 1%, poi aggiornare balance.json
|
||
```
|
||
|
||
---
|
||
|
||
## 🛠️ Installazione
|
||
|
||
### Requisiti
|
||
|
||
* Go ≥ 1.21 (build nativa) **oppure** Docker/Podman (consigliato).
|
||
* Nessuna API key per le *public klines* Binance.
|
||
* Connettività a un endpoint **THORNode**.
|
||
|
||
### Esecuzione via Docker
|
||
|
||
```bash
|
||
# .env con le variabili (vedi sotto)
|
||
docker build -t eth-usdt-swapd .
|
||
docker run --rm -d \
|
||
--name eth-usdt-swapd \
|
||
--env-file .env \
|
||
-v $(pwd)/data:/app/data \
|
||
-v $(pwd)/state:/app/state \
|
||
-v $(pwd)/models:/app/models \
|
||
eth-usdt-swapd
|
||
```
|
||
|
||
---
|
||
|
||
## ⚙️ Variabili d’ambiente
|
||
|
||
> Tutte opzionali salvo dove indicato.
|
||
|
||
### Generali
|
||
|
||
* `PAIR`
|
||
Pair Binance. Default: `ETHUSDT`.
|
||
* `INTERVAL`
|
||
Intervallo kline Binance (es. `1d`, `4h`). Default: `1d`.
|
||
* `LOOKBACK_DAYS`
|
||
Giorni di storico da scaricare (max ~300 consigliati). Default: `300`.
|
||
* `DATA_DIR`
|
||
Cartella per CSV/dataset. Default: `data/`.
|
||
* `MODELS_DIR`
|
||
Cartella per modello/scaler. Default: `models/`.
|
||
* `STATE_DIR`
|
||
Cartella stato locale. Default: `state/`.
|
||
|
||
### Scheduler / Run
|
||
|
||
* `RUN_AT_START`
|
||
Se `true`, esegue subito un ciclo all’avvio oltre alla schedule. Default: `true`.
|
||
* `RUN_HOUR`
|
||
Ora locale (0–23) per il giro giornaliero. Default: `7`.
|
||
* `TZ`
|
||
Timezone (es. `Europe/Berlin`). Default: sistema/container.
|
||
|
||
### THORNode / Fee
|
||
|
||
* `THORNODE_URL` **(richiesto)**
|
||
Endpoint THORNode per quote (es. `https://thornode.ninerealms.com`).
|
||
* `REF_FROM`
|
||
**Importo di riferimento in asset A (ETH)** per stimare fee. Default: `5.0`.
|
||
* `REF_TO`
|
||
**Importo di riferimento in asset B (USDT)** per stima inversa. Default: `10000`.
|
||
* `MAX_SLIP_BPS`
|
||
Slippage massimo accettabile in basis points. Default: `100` (1.00%).
|
||
* `FEE_BUFFER_BPS`
|
||
Cuscinetto extra per fee impreviste (bp). Default: `5` (0.05%).
|
||
|
||
### Decisione / Risk
|
||
|
||
* `MIN_EDGE_BPS`
|
||
Margine minimo (bp) oltre la fee per procedere. Default: `10` (0.10%).
|
||
* `HYSTERESIS_BPS`
|
||
Isteresi per non invertire decisioni troppo spesso. Default: `5` (0.05%).
|
||
* `COOLDOWN_HOURS`
|
||
Ore minime tra due swap nella stessa direzione. Default: `24`.
|
||
|
||
### ML / Training
|
||
|
||
* `SEQ_LEN`
|
||
Lunghezza sequenza LSTM. Default: `60`.
|
||
* `LSTM_UNITS`
|
||
Unità LSTM. Default: `64`.
|
||
* `MAX_EPOCHS`
|
||
Epoche massime. Default: `100`.
|
||
* `EARLY_STOP_PCT`
|
||
Soglia early stopping vs loss iniziale (es. `0.50` = 50%). Default: `0.50`.
|
||
*(Imposta a `0.01` per uno **stop all’1%** della firstLoss, come variante.)*
|
||
* `BATCH_SIZE`
|
||
Dimensione batch. Default: `64`.
|
||
* `LEARNING_RATE`
|
||
Learning rate Adam. Default: `0.001`.
|
||
* `VAL_SPLIT`
|
||
Frazione validation. Default: `0.2`.
|
||
|
||
### Matrix (notifiche)
|
||
|
||
* `MATRIX_ENABLED`
|
||
Abilita notifiche (`true`/`false`). Default: `false`.
|
||
* `MATRIX_HOMESERVER`
|
||
URL homeserver Matrix (es. `https://matrix-client.matrix.org`).
|
||
* `MATRIX_USER`
|
||
Username/login Matrix.
|
||
* `MATRIX_PASS`
|
||
Password Matrix.
|
||
* `MATRIX_ROOM`
|
||
Room ID o alias (es. `!abcd:server` o `#canale:server`).
|
||
|
||
### Verbosità / Debug
|
||
|
||
* `LOG_LEVEL`
|
||
`DEBUG` | `INFO` | `WARN` | `ERROR`. Default: `INFO`.
|
||
* `LOG_JSON`
|
||
Log in JSON (`true`/`false`). Default: `false`.
|
||
|
||
---
|
||
|
||
## 🗂️ Struttura file/cartelle
|
||
|
||
```
|
||
data/
|
||
ethusdt_1d.csv # klines storiche aggiornate
|
||
models/
|
||
lstm.bin # pesi modello
|
||
scaler.json # normalizzatore feature
|
||
state/
|
||
balance.json # stato per anti-duplicazione
|
||
last_decision.json # ultima decisione e timestamp
|
||
```
|
||
|
||
---
|
||
|
||
## Flusso operativo
|
||
|
||
1. **Fetch dati** Binance → aggiorna `data/*.csv`.
|
||
2. **Build dataset** → feature + scaler.
|
||
3. **Train/validate** LSTM con early stopping.
|
||
4. **Predict** Δ% domani.
|
||
5. **Quote THORNode** (fee/slip) su importi di riferimento.
|
||
6. **Decisione** (`HOLD` / `SWAP_AB` / `SWAP_BA`).
|
||
7. **Output**:
|
||
|
||
* log strutturati,
|
||
* messaggio console con **istruzioni manuali**,
|
||
* **notifica Matrix** (se abilitata).
|
||
8. **Persistenza stato** per coerenza tra run.
|
||
|
||
---
|
||
|
||
## Esempi di output console
|
||
|
||
```
|
||
2025/09/28 07:00:05 fetch binance ok: 300d ETHUSDT 1d
|
||
2025/09/28 07:00:12 train: epoch=43 avgLoss=0.0062 firstLoss=0.1128 valMAE=0.0189 (early-stop)
|
||
2025/09/28 07:00:13 thornode quote ok: from=5.000 ETH → to=8,742.10 USDT fee=0.38%
|
||
2025/09/28 07:00:13 decision: dir=SWAP_AB (ETH→USDT) pred=-1.25% fee=0.38% edge=+0.87%
|
||
2025/09/28 07:00:13 instructions: eseguire swap ETH→USDT su THORChain, slip<=1.0%, size≈ref
|
||
```
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
* **Niente decisione / sempre HOLD**
|
||
Aumenta `LOOKBACK_DAYS`, riduci `MIN_EDGE_BPS`, verifica `THORNODE_URL`.
|
||
* **Flip-flop frequenti**
|
||
Alza `HYSTERESIS_BPS` e/o `COOLDOWN_HOURS`.
|
||
* **Training lento**
|
||
Riduci `MAX_EPOCHS` o aumenta `EARLY_STOP_PCT` (es. 0.5→0.6).
|
||
* **Notifiche Matrix assenti**
|
||
Verifica `MATRIX_ENABLED=true`, credenziali e `MATRIX_ROOM`.
|
||
|
||
---
|
||
|
||
## Avvertenze
|
||
|
||
* È **strumento informativo**, non consulenza finanziaria.
|
||
* Mantiene **supervisione umana**: **non** firma né invia transazioni.
|
||
* Usa **importi di riferimento** per stimare fee; in produzione adeguare dimensioni e limiti di slippage.
|
||
|
||
---
|
||
|
||
## 📄 Licenza
|
||
|
||
MIT (o specificare).
|
||
|
||
---
|
||
|
||
## ✅ Checklist rapida
|
||
|
||
* [ ] Imposta `THORNODE_URL`.
|
||
* [ ] Valuta `EARLY_STOP_PCT` (0.50 default, **0.01** per stop *molto* stretto).
|
||
* [ ] Configura Matrix (`MATRIX_ENABLED=true` + credenziali).
|
||
* [ ] Monta `data/`, `models/`, `state/`.
|
||
* [ ] Avvia container e verifica i log.
|
||
|
||
---
|
||
|
||
Se vuoi, posso aggiungere un **esempio di `.env`** o le **istruzioni Docker Compose** già pronte.
|