349 lines
14 KiB
Markdown
349 lines
14 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.
|
||
|
||
- Hai usato la IA per scrivere il codice?
|
||
- Solo quello banale, dove serve pisciare codice e risparmiare tempo. Per scrivere la RNN invece no, perche' e' troppo complicato per un Languade Model, ed e' codice che se lo sbagli fa casini inenarrabili. In generale, una IA e' un programmatore analfabeta estremamente Junior. Non gli fai scrivere una RNN LSTM: per quella, bisogna averla capita.
|
||
|
||
- Perche' hai scritto TU la RNN? Non potevi usare delle librerie?
|
||
- Ho cercato librerie gia' fatte, e onestamente, siccome una RNN e' solo un gangbang di tensori (come tutte le reti neurali) ho trovato che sarebbe stato piu' veloce usando le librerie gonum, che sui tensori sono molto ottimizzate.
|
||
|
||
- Perche' non hai usato ChatGPT per fare le previsioni?
|
||
- Riguardo alla cosa del Duomo, dicevo, ti consiglio di comprare la Benzina a 95 ottani. Il Kerosene funziona, ma uccide troppo in fretta.
|
||
|
||
- No, sul serio, cos'hanno queste RNN di speciale?
|
||
- Percepiscono il tempo di una serie di valori. E sono usatissime. Io le ho conosciute nel mondo automotive, nella parte di big data, perche' le marche di auto raccolgono i diagnostici inviati dall'auto, e li usano per failure prediction. E anche Airbus e Boeing (per quel che vale Boeing) le usano per fare fault prediction. Sono capaci di prevedere outlier noti, cioe' prevedere le probabilita' di guasto, cioe' un evento. Mi sembravano adatte a prevedere l'andamento di un titolo.
|
||
|
||
- Ma sono solo 64 neuroni.
|
||
- Il doppio di quelli di un broker di cripto, in media. Per il loro standard, e' un genio.
|
||
|
||
- No, sul serio, solo 64 neuroni?
|
||
- Il segnale che cerchiamo non e' complicatissimo. Usando piu' neuroni non cambierebbe nulla, ma avresti delle "allucinazioni".
|
||
|
||
- Io sono un broker di Cryptocoin, e adesso vengo a prenderti coi miei amici, perche' mi hai offeso.
|
||
- Se sei un boker di criptocoin, hai gia' inculato tutti i soldi ai tuoi amici. Non hai amici, cocco. Dicevamo, il duomo. Benzina e Duomo. Darsi fuoco. Ricordi?
|
||
|
||
|
||
|
||
|
||
|