328 lines
12 KiB
Markdown
328 lines
12 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: `24`.
|
||
* `TZ`
|
||
Timezone (es. `Europe/Berlin`). Default: quello del 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`. Serve per avere la quotazione dello swap da THORNet.
|
||
* `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
|
||
```
|
||
|
||
## Esempi di output su matrix
|
||
|
||
HOLD
|
||
|
||
```
|
||
consiglio: azione=HOLD expectedBps=18.602 feeBps=26.000 netBps=-7.398 confOK=true motivo=Previsione rialzista ma non abbastanza sopra fee+margine o confidenza bassa
|
||
Suggerimento: nessuna azione (HOLD). Motivo=Previsione rialzista ma non abbastanza sopra fee+margine o confidenza bassa
|
||
Suggerimento valido sino a: 2025-09-28 12:58:03 CEST
|
||
La quotazione dei costi è valida sino a 2025-09-28 12:58:03 CEST (≈ 14m 59s restanti). Non fare lo swap dopo questa data.
|
||
```
|
||
|
||
SWAP
|
||
|
||
```
|
||
consiglio: azione=ETH -> USDT expectedBps=-63.477 feeBps=8.000 netBps=45.477 confOK=true motivo=Previsione ribassista per asset from, confidenza valida, guadagno oltre fee+margine
|
||
ISTRUZIONI MANUALI: esegui swap ETH.ETH->ETH.USDT amount=0.10000000; procedi solo se feeTotali<=53.477 bps (stima THOR=8.000 bps) e costo<=~0.00053477 ETH.ETH | motivo=Previsione ribassista per asset from, confidenza valida, guadagno oltre fee+margine
|
||
Suggerimento valido sino a: 2025-09-28 12:58:03 CEST
|
||
La quotazione dei costi è valida sino a 2025-09-28 12:58:03 CEST (≈ 14m 59s restanti). Dopo questa data, verifica i costi di swap
|
||
```
|
||
|
||
|
||
|
||
---
|
||
|
||
## 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
|
||
|
||
* È uno **strumento informativo**, non una consulenza finanziaria. Dovrebbe prenderci spesso, ma non ve lo giuro.
|
||
* Mantiene **supervisione umana**: **non** firma né invia transazioni. Lo swap lo fate voi.
|
||
* Usa **importi di riferimento** per stimare fee; in produzione adeguare dimensioni e limiti di slippage.
|
||
|
||
---
|
||
|
||
## 📄 Licenza
|
||
|
||
VEDI file LICENSE.
|
||
|
||
---
|
||
|
||
## Checklist rapida per l'installazione
|
||
|
||
* [ ] 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.
|
||
|
||
## FAQ
|
||
|
||
- Perche' e' tutto in italiano?
|
||
- Italy First! Make Italy Great Again!
|
||
|
||
- Perche' l'indirizzo di USDT sembra hardcodes? Io ho il mio!
|
||
- No, non hai il tuo. USDT non e' una moneta, bensi' un contratto (o "token") basato su Ethereum. Il suo ID e' costante e pubblico. Non hai "il tuo".
|
||
|
||
- Perche' usi il cambio USDT vs ETH per giocare?
|
||
- Perche' una RNN LSTM ha bisogno di un buon rapporto tra segnale e rumore. Due crypto indipendenti hanno molto piu' rumore che segnale. Se non capisci questa risposta, non farti la domanda.
|
||
|
||
- Ma USDT e' una stablecoin sul dollaro. Perche' mai non usare il cambio in dollari, allora, e usare ETH -> USD invece di ETH -> USDT
|
||
- Perche il costo dello swap e' minore, e ogni volta che swappate in moneta pagate anche le tasse, mentre tra ETH e un contratto in USDT il fee e' minimo.
|
||
|
||
- Ma THORnet e' legale? Non e' una darknet?
|
||
- No, quella e' Tor. Thornet e' uno scambiatore, legittimo, che costa poco perche' non fa KYC. Insomma, non vi chiede anche le analisi del sangue per lavorare con voi. E comunque lo usiamo solo per avere delle quotazioni e poi, manualmente, per fare lo swap, se lo usate.
|
||
|
||
- Ma a me il dio THOR non piace. Posso usare un altro scambiatore?
|
||
- Ovvio. Il messaggio che ti arriva su Matrix specifica anche quant'e' il fee massimo che devi accettare per guadagnarci.
|
||
|
||
- Perche' Matrix?
|
||
- Perche' tu ricevi il messaggio, magari anche la notifica sul tuo cellulare, e poi decidi TU cosa fare.
|
||
|
||
- Ma io non ci capisco niente. Lasciare a me la decisione e' assurdo. Perche' non fa tutto da solo?
|
||
- Perche' se facesse tutto da solo, i tuoi soldi sarebbero esposti a qualsiasi idiozia, AKA "black swan" , per fare un'esempio, del Washington Bozo Circus, o di Donald Stable Genius Trump, o di Elon Mezzasega Musk. Invece, un filtro umano potrebbe filtrare queste cose, e rimandare gli swap a dopo.
|
||
|
||
- Ma io non so come fare lo swap tra USDT e ETH.
|
||
- Forse non dovresti usare questo software, allora. E nemmeno toccare una Crypto. E anche darsi fuoco di fronte al Duomo di Milano non e' un'ipotesi da scartare del tutto.
|
||
|
||
- Ma io non so usare Matrix e non so come creare una room.
|
||
- Il Duomo. Il Duomo e' tuo amico.E sbrigati, perche' la proliferazione di auto elettriche potrebbe rendere difficile trovare la benzina.
|
||
|
||
|
||
|
||
|
||
|