@gabrielerandelli/minus-tracker 0.5.7 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +321 -46
- package/dist/cli/index.js +1181 -25
- package/dist/cli/index.js.map +1 -1
- package/dist/data/stress-manifest.json +13387 -0
- package/dist/index.cjs +481 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +91 -2
- package/dist/index.d.ts +91 -2
- package/dist/index.js +479 -1
- package/dist/index.js.map +1 -1
- package/package.json +18 -1
package/README.md
CHANGED
|
@@ -1,31 +1,28 @@
|
|
|
1
1
|
# minus-tracker
|
|
2
2
|
|
|
3
3
|
[](./LICENSE)
|
|
4
|
-
|
|
5
|
-
> **Status:** v0.5.7 — published on npm as `@gabrielerandelli/minus-tracker`.
|
|
4
|
+
[](https://www.npmjs.com/package/@gabrielerandelli/minus-tracker)
|
|
6
5
|
|
|
7
6
|
---
|
|
8
7
|
|
|
9
8
|
## Italiano
|
|
10
9
|
|
|
11
|
-
minus-tracker è un progetto open-source sviluppato principalmente in TypeScript per il calcolo automatico di
|
|
12
|
-
**plusvalenze e minusvalenze** nel _Regime Dichiarativo_ — abbinamento lotti LIFO/FIFO,
|
|
13
|
-
normalizzazione multi-valuta con tassi BCE storici.
|
|
10
|
+
minus-tracker è un progetto open-source sviluppato principalmente in TypeScript per il calcolo automatico di **plusvalenze e minusvalenze** in _Regime Dichiarativo_. Gestisce la sincronizzazione dei lotti tramite logica LIFO/FIFO e la normalizzazione multivaluta utilizzando i tassi storici della BCE.
|
|
14
11
|
|
|
15
|
-
|
|
12
|
+
Il tool elabora i dati partendo direttamente dal formato CSV esportato da DEGIRO.
|
|
16
13
|
|
|
17
|
-
###
|
|
14
|
+
### Funzionalità
|
|
18
15
|
|
|
19
|
-
- Calcolo plusvalenze
|
|
20
|
-
- **Parser CSV DEGIRO
|
|
21
|
-
- Gestione **
|
|
22
|
-
- Suite di test
|
|
23
|
-
-
|
|
24
|
-
-
|
|
16
|
+
- Calcolo di plusvalenze e minusvalenze con gestione dei lotti via **LIFO o FIFO** (configurabile)
|
|
17
|
+
- **Parser integrato** per i file CSV di DEGIRO
|
|
18
|
+
- Gestione **multivaluta** con tassi storici BCE (EUR, USD, GBP, CHF)
|
|
19
|
+
- Suite di test allineata alle **FAQ dell'Agenzia delle Entrate**
|
|
20
|
+
- Output disponibile in **italiano** (default) o **inglese** (`--lang en`)
|
|
21
|
+
- Disponibile come pacchetto NPM con supporto CLI
|
|
25
22
|
|
|
26
23
|
### Avvio rapido
|
|
27
24
|
|
|
28
|
-
|
|
25
|
+
Se non hai ancora un export di DEGIRO a disposizione, puoi testare il tool con il file di esempio incluso nel pacchetto.
|
|
29
26
|
|
|
30
27
|
**Via npx (senza installazione globale):**
|
|
31
28
|
|
|
@@ -40,18 +37,47 @@ npx @gabrielerandelli/minus-tracker calc sample-trades.csv
|
|
|
40
37
|
./node_modules/.bin/minus-tracker calc node_modules/@gabrielerandelli/minus-tracker/samples/sample-trades.csv
|
|
41
38
|
```
|
|
42
39
|
|
|
43
|
-
Il file contiene 5 operazioni fittizie (Apple Inc in USD + ASML Holding in EUR) e mostra
|
|
44
|
-
|
|
40
|
+
Il file di esempio contiene 5 operazioni fittizie (Apple Inc in USD + ASML Holding in EUR) e mostra un esempio di scarico parziale LIFO, la conversione valutaria e un risultato netto positivo.
|
|
41
|
+
|
|
42
|
+
### Output di esempio
|
|
43
|
+
|
|
44
|
+
L'esecuzione di `calc` sul file di esempio produce:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
METODO: LIFO | ANNO FISCALE: 2024
|
|
48
|
+
|
|
49
|
+
ISIN TITOLO QTÀ DATA ACQUISTO DATA VENDITA ACQUISTO EUR VENDITA EUR GUADAGNO/PERDITA
|
|
50
|
+
US0378331005 Apple Inc 10 2024-01-02 2024-01-05 1371,11 1188,37 -182,75
|
|
51
|
+
NL0010273215 ASML Holding N.V. 3 2024-04-01 2024-07-15 2552,00 2849,00 +297,00
|
|
52
|
+
NL0010273215 ASML Holding N.V. 3 2024-01-15 2024-07-15 2401,20 2849,00 +447,80
|
|
53
|
+
|
|
54
|
+
────────────────────────────────────────────────────────────────────────
|
|
55
|
+
PLUSVALENZE: 744,80 EUR
|
|
56
|
+
MINUSVALENZE: 182,75 EUR
|
|
57
|
+
RISULTATO NETTO: 562,05 EUR
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Con il flag `--json` si ottiene direttamente l'oggetto `GainsReport` in formato JSON — utile per integrazioni programmatiche (vedi [Esempio di utilizzo nel codice](#esempio-di-utilizzo-nel-codice)).
|
|
61
|
+
|
|
62
|
+
### Formato CSV DEGIRO
|
|
63
|
+
|
|
64
|
+
Esporta da **Attività → Transazioni** (NON il rendiconto del conto) nella tua area personale DEGIRO. Usa l'esportazione predefinita con tutte le colonne.
|
|
65
|
+
|
|
66
|
+
Valute supportate: **EUR** (nessuna conversione), **USD**, **GBP**, **CHF** (tassi storici BCE inclusi, 2019–oggi).
|
|
67
|
+
|
|
68
|
+
Le date nel file DEGIRO sono in formato `GG-MM-AAAA`; il parser le converte automaticamente in ISO.
|
|
69
|
+
|
|
70
|
+
Le righe con ISIN mancante, valuta non supportata o nessun tasso BCE disponibile entro 3 giorni lavorativi vengono saltate con un avviso (non un errore) — usa `validate` per ispezionarle prima del calcolo.
|
|
45
71
|
|
|
46
72
|
### Installazione CLI
|
|
47
73
|
|
|
48
|
-
**Installazione globale** (comando disponibile
|
|
74
|
+
**Installazione globale** (per rendere il comando disponibile in ogni directory):
|
|
49
75
|
|
|
50
76
|
```bash
|
|
51
77
|
npm install -g @gabrielerandelli/minus-tracker
|
|
52
78
|
```
|
|
53
79
|
|
|
54
|
-
**Senza installazione globale** (
|
|
80
|
+
**Senza installazione globale** (esecuzione al volo):
|
|
55
81
|
|
|
56
82
|
```bash
|
|
57
83
|
npx @gabrielerandelli/minus-tracker calc trades.csv
|
|
@@ -59,47 +85,156 @@ npx @gabrielerandelli/minus-tracker calc trades.csv
|
|
|
59
85
|
|
|
60
86
|
### Utilizzo CLI
|
|
61
87
|
|
|
88
|
+
| Comando | Flag principali | Note |
|
|
89
|
+
| ---------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------- |
|
|
90
|
+
| `calc <file.csv>` | `--method LIFO\|FIFO` (default: LIFO), `--lang it\|en`, `--json` | Aggiorna i tassi BCE automaticamente se la snapshot ha più di 7 giorni |
|
|
91
|
+
| `validate <file.csv>` | `--lang it\|en` | Exit 0 con avvisi; exit 1 in caso di errori bloccanti |
|
|
92
|
+
| `rates --check` | — | Mostra la copertura della snapshot BCE in locale |
|
|
93
|
+
| `rates --update` | — | Scarica i tassi aggiornati dall'API BCE |
|
|
94
|
+
| `config --lang it\|en` | — | Salva la lingua preferita |
|
|
95
|
+
| `config --show` | — | Mostra la lingua correntemente impostata |
|
|
96
|
+
| `stress-test` | `--range N-M`, `--keep`, `--json`, `--output-dir` | Documentato in fondo |
|
|
97
|
+
|
|
98
|
+
Precedenza lingua: `--lang` > lingua salvata > italiano (default).
|
|
99
|
+
|
|
62
100
|
```bash
|
|
63
|
-
# Calcola plusvalenze/minusvalenze (output in italiano)
|
|
101
|
+
# Calcola plusvalenze/minusvalenze (output in italiano, metodo LIFO)
|
|
64
102
|
minus-tracker calc trades.csv
|
|
65
103
|
|
|
66
|
-
#
|
|
67
|
-
minus-tracker calc --lang en trades.csv
|
|
68
|
-
|
|
69
|
-
# Imposta la lingua in modo permanente
|
|
70
|
-
minus-tracker config --lang en # oppure: --lang it
|
|
104
|
+
# Metodo FIFO, output in inglese, formato JSON
|
|
105
|
+
minus-tracker calc --method FIFO --lang en --json trades.csv
|
|
71
106
|
|
|
72
107
|
# Valida il CSV senza calcolare
|
|
73
108
|
minus-tracker validate trades.csv
|
|
74
109
|
|
|
75
|
-
# Controlla
|
|
110
|
+
# Controlla o aggiorna i tassi BCE in locale
|
|
76
111
|
minus-tracker rates --check
|
|
77
112
|
minus-tracker rates --update
|
|
113
|
+
|
|
114
|
+
# Imposta la lingua di default in modo permanente
|
|
115
|
+
minus-tracker config --lang en # oppure: --lang it
|
|
116
|
+
minus-tracker config --show
|
|
78
117
|
```
|
|
79
118
|
|
|
80
|
-
### Installazione libreria
|
|
119
|
+
### Installazione come libreria
|
|
81
120
|
|
|
82
121
|
```bash
|
|
83
122
|
npm install @gabrielerandelli/minus-tracker
|
|
84
123
|
```
|
|
85
124
|
|
|
86
|
-
###
|
|
125
|
+
### Esempio di utilizzo nel codice
|
|
87
126
|
|
|
88
127
|
```ts
|
|
89
|
-
import {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
128
|
+
import {
|
|
129
|
+
DEGIROParser,
|
|
130
|
+
Calculator,
|
|
131
|
+
ParseError,
|
|
132
|
+
CalculationError,
|
|
133
|
+
} from "@gabrielerandelli/minus-tracker";
|
|
134
|
+
import type { GainsReport, LotMethod } from "@gabrielerandelli/minus-tracker";
|
|
135
|
+
|
|
136
|
+
// 1. Parsing
|
|
137
|
+
const parser = new DEGIROParser();
|
|
138
|
+
const transactions = parser.parse(csvString); // lancia ParseError in caso di CSV non valido
|
|
139
|
+
if (parser.warnings.length > 0) {
|
|
140
|
+
console.warn("Righe saltate:", parser.warnings);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 2. Calcolo
|
|
144
|
+
const method: LotMethod = "LIFO"; // oppure "FIFO"
|
|
145
|
+
const report: GainsReport = new Calculator(
|
|
146
|
+
transactions,
|
|
147
|
+
parser.warnings,
|
|
148
|
+
).calculateGains(method);
|
|
149
|
+
|
|
150
|
+
console.log(report.plusvalenze); // numero in EUR
|
|
151
|
+
console.log(report.minusvalenze); // numero in EUR (valore assoluto)
|
|
152
|
+
console.log(report.netResult); // plusvalenze - minusvalenze
|
|
153
|
+
console.log(report.lots); // MatchedLot[] — dettaglio per lotto
|
|
154
|
+
|
|
155
|
+
// 3. Gestione errori
|
|
156
|
+
try {
|
|
157
|
+
const txs = parser.parse(csvString);
|
|
158
|
+
const r = new Calculator(txs, parser.warnings).calculateGains("LIFO");
|
|
159
|
+
} catch (err) {
|
|
160
|
+
if (err instanceof ParseError) {
|
|
161
|
+
if (err.code === "MISSING_COLUMN") {
|
|
162
|
+
console.error("Colonna mancante:", err.columnName);
|
|
163
|
+
} else {
|
|
164
|
+
console.error("CSV non valido");
|
|
165
|
+
}
|
|
166
|
+
} else if (err instanceof CalculationError) {
|
|
167
|
+
console.error(
|
|
168
|
+
`VENDITA senza acquisto corrispondente: ${err.isin} del ${err.date}`,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
93
172
|
```
|
|
94
173
|
|
|
95
|
-
|
|
174
|
+
> **Nota:** `parser.warningEntries` (visibile nell'autocomplete TypeScript) è un'API interna usata dal renderer CLI. Per uso programmatico usa `parser.warnings` (`string[]`).
|
|
175
|
+
|
|
176
|
+
> 💡 minus-tracker si occupa **esclusivamente del calcolo fiscale** — non include interfacce grafiche (UI), sistemi di autenticazione, database o esportazioni in PDF.
|
|
96
177
|
|
|
97
178
|
**Prerequisiti:** Node.js ≥ 24 ([nodejs.org](https://nodejs.org))
|
|
98
179
|
|
|
180
|
+
### Domande frequenti
|
|
181
|
+
|
|
182
|
+
**Il CSV viene rifiutato con "colonna mancante" o "CSV non valido"**
|
|
183
|
+
Verifica di aver esportato da Attività → **Transazioni** e non dal rendiconto del conto. Il parser richiede il formato dell'export Transazioni.
|
|
184
|
+
|
|
185
|
+
**Alcune righe vengono saltate con un avviso**
|
|
186
|
+
Le righe vengono saltate (senza bloccare il calcolo) quando: l'ISIN è vuoto, la valuta non è tra EUR/USD/GBP/CHF, oppure non esiste un tasso BCE entro 3 giorni lavorativi dalla data dell'operazione. Usa `validate` per i dettagli.
|
|
187
|
+
|
|
188
|
+
**Errore "nessun lotto aperto per ISIN X alla data Y"**
|
|
189
|
+
Il CSV contiene una vendita per un titolo senza un acquisto precedente nel file. L'acquisto potrebbe essere in un export di un anno precedente non incluso. Usa `validate` per esaminare le transazioni parsate.
|
|
190
|
+
|
|
191
|
+
**I tassi BCE sono scaduti**
|
|
192
|
+
Esegui `minus-tracker rates --update`. Il comando `calc` esegue l'aggiornamento automaticamente se la snapshot ha più di 7 giorni.
|
|
193
|
+
|
|
194
|
+
**LIFO o FIFO?**
|
|
195
|
+
Il Regime Dichiarativo utilizza il LIFO come metodo predefinito ai sensi della normativa fiscale italiana. Il FIFO è disponibile per confronto. Consulta il tuo commercialista per conferma.
|
|
196
|
+
|
|
197
|
+
### Limitazioni note
|
|
198
|
+
|
|
199
|
+
minus-tracker aggrega le plusvalenze e le minusvalenze di **tutti gli strumenti finanziari in un'unica somma**, indipendentemente dalla loro categoria fiscale.
|
|
200
|
+
|
|
201
|
+
La normativa italiana prevede che i **redditi diversi** (azioni, derivati, certificati — Art. 67 TUIR) e i **redditi di capitale** (ETF/fondi UCITS — Art. 44 TUIR) non possano essere compensati tra loro: una minusvalenza su un ETF non può ridurre la plusvalenza su un'azione, e viceversa.
|
|
202
|
+
|
|
203
|
+
**Portafogli con soli titoli azionari o soli ETF:** il calcolo è corretto.
|
|
204
|
+
**Portafogli misti (azioni + ETF):** il risultato netto riportato non è direttamente utilizzabile ai fini dichiarativi. In questo caso è necessario separare manualmente i lotti per categoria fiscale prima di presentare la dichiarazione, con l'assistenza di un commercialista.
|
|
205
|
+
|
|
99
206
|
### Avvertenza
|
|
100
207
|
|
|
101
|
-
minus-tracker è un **
|
|
102
|
-
|
|
208
|
+
minus-tracker è un **progetto personale** sviluppato a titolo privato e **non è in alcun modo affiliato, sponsorizzato o rappresentativo del datore di lavoro dell'autore o di qualsiasi altra organizzazione**.
|
|
209
|
+
|
|
210
|
+
Il tool è fornito **esclusivamente come ausilio al calcolo** e **non costituisce consulenza fiscale, legale o finanziaria**. L'autore **declina ogni responsabilità** per eventuali errori nei calcoli, per un utilizzo improprio dello strumento o per le decisioni prese dall'utente finale sulla base dei report generati.
|
|
211
|
+
|
|
212
|
+
Si raccomanda **sempre** di verificare i risultati con un commercialista o professionista fiscale qualificato prima di presentare qualsiasi dichiarazione.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Stress Test
|
|
217
|
+
|
|
218
|
+
Puoi eseguire la suite di stress test integrata per verificare che l'installazione gestisca correttamente tutti gli scenari previsti:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
minus-tracker stress-test
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Questo comando genera 100 file CSV di test in una directory temporanea, esegue i vari comandi della CLI su ciascuno di essi e mostra i risultati del test senza modificare i file del tuo progetto.
|
|
225
|
+
|
|
226
|
+
### Opzioni disponibili
|
|
227
|
+
|
|
228
|
+
| Flag | Default | Descrizione |
|
|
229
|
+
| --------------------- | --------------------------------- | ------------------------------------------------ |
|
|
230
|
+
| `--range N-M` | `1-100` | Esegue solo gli scenari da N a M |
|
|
231
|
+
| `--keep` | disattivato | Mantiene i file CSV generati dopo il test |
|
|
232
|
+
| `--json` | disattivato | Restituisce i risultati in formato JSON |
|
|
233
|
+
| `--output-dir <path>` | `/tmp/minus-tracker-stress-<ts>/` | Permette di personalizzare la cartella di output |
|
|
234
|
+
|
|
235
|
+
### Scenari coperti
|
|
236
|
+
|
|
237
|
+
I 100 scenari includono: azioni in EUR/USD/GBP/CHF, divergenze nei calcoli LIFO vs FIFO, consumo parziale dei lotti, portafogli multi-ISIN, gestione dei giorni festivi (fallback sui tassi BCE del weekend), messaggi di avviso ed errore, operazioni effettuate nello stesso giorno (same-day), casi limite di arrotondamento e portafogli di grandi dimensioni (fino a 200 transazioni).
|
|
103
238
|
|
|
104
239
|
---
|
|
105
240
|
|
|
@@ -140,6 +275,36 @@ npx @gabrielerandelli/minus-tracker calc sample-trades.csv
|
|
|
140
275
|
The file contains 5 fictional trades (Apple Inc in USD + ASML Holding in EUR) and
|
|
141
276
|
demonstrates partial LIFO matching, currency conversion, and a positive net result.
|
|
142
277
|
|
|
278
|
+
### Example Output
|
|
279
|
+
|
|
280
|
+
Running `calc` on the sample file produces:
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
METHOD: LIFO | TAX YEAR: 2024
|
|
284
|
+
|
|
285
|
+
ISIN PRODUCT QTY BUY DATE SELL DATE BUY EUR SELL EUR GAIN/LOSS
|
|
286
|
+
US0378331005 Apple Inc 10 2024-01-02 2024-01-05 1,371.11 1,188.37 -182.75
|
|
287
|
+
NL0010273215 ASML Holding N.V. 3 2024-04-01 2024-07-15 2,552.00 2,849.00 +297.00
|
|
288
|
+
NL0010273215 ASML Holding N.V. 3 2024-01-15 2024-07-15 2,401.20 2,849.00 +447.80
|
|
289
|
+
|
|
290
|
+
────────────────────────────────────────────────────────────────────────
|
|
291
|
+
PLUSVALENZE: 744.80 EUR
|
|
292
|
+
MINUSVALENZE: 182.75 EUR
|
|
293
|
+
NET RESULT: 562.05 EUR
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Add `--json` to get the raw `GainsReport` object — useful for programmatic integrations (see [Library Usage](#library-usage)).
|
|
297
|
+
|
|
298
|
+
### DEGIRO CSV Format
|
|
299
|
+
|
|
300
|
+
Export from **Activity → Transactions** (NOT the Account Statement) in your DEGIRO account. Use the default export with all columns selected.
|
|
301
|
+
|
|
302
|
+
Supported currencies: **EUR** (no conversion), **USD**, **GBP**, **CHF** (bundled ECB historical rates, 2019–present).
|
|
303
|
+
|
|
304
|
+
Dates in the DEGIRO export are in `DD-MM-YYYY` format; the parser converts them to ISO automatically.
|
|
305
|
+
|
|
306
|
+
Rows with a missing ISIN, unsupported currency, or no ECB rate within 3 trading days of the trade date are skipped with a warning (not an error) — run `validate` to inspect them before calculating.
|
|
307
|
+
|
|
143
308
|
### CLI Installation
|
|
144
309
|
|
|
145
310
|
**Global install** (command available system-wide):
|
|
@@ -156,15 +321,24 @@ npx @gabrielerandelli/minus-tracker calc trades.csv
|
|
|
156
321
|
|
|
157
322
|
### CLI Usage
|
|
158
323
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
324
|
+
| Command | Key flags | Notes |
|
|
325
|
+
| ---------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------- |
|
|
326
|
+
| `calc <file.csv>` | `--method LIFO\|FIFO` (default: LIFO), `--lang it\|en`, `--json` | Auto-fetches ECB rates if snapshot is more than 7 days old |
|
|
327
|
+
| `validate <file.csv>` | `--lang it\|en` | Exit 0 with warnings; exit 1 on hard errors |
|
|
328
|
+
| `rates --check` | — | Shows bundled ECB snapshot coverage |
|
|
329
|
+
| `rates --update` | — | Fetches fresh rates from the ECB API |
|
|
330
|
+
| `config --lang it\|en` | — | Saves language preference |
|
|
331
|
+
| `config --show` | — | Shows current language setting |
|
|
332
|
+
| `stress-test` | `--range N-M`, `--keep`, `--json`, `--output-dir` | Documented below |
|
|
333
|
+
|
|
334
|
+
Language precedence: `--lang` flag > saved config > Italian (default).
|
|
162
335
|
|
|
163
|
-
|
|
336
|
+
```bash
|
|
337
|
+
# Calculate gains/losses (English output, LIFO method)
|
|
164
338
|
minus-tracker calc --lang en trades.csv
|
|
165
339
|
|
|
166
|
-
#
|
|
167
|
-
minus-tracker
|
|
340
|
+
# FIFO method, JSON output
|
|
341
|
+
minus-tracker calc --method FIFO --json trades.csv
|
|
168
342
|
|
|
169
343
|
# Validate CSV without calculating
|
|
170
344
|
minus-tracker validate trades.csv
|
|
@@ -172,6 +346,10 @@ minus-tracker validate trades.csv
|
|
|
172
346
|
# Check/update ECB rates
|
|
173
347
|
minus-tracker rates --check
|
|
174
348
|
minus-tracker rates --update
|
|
349
|
+
|
|
350
|
+
# Set language permanently
|
|
351
|
+
minus-tracker config --lang en # or: --lang it
|
|
352
|
+
minus-tracker config --show
|
|
175
353
|
```
|
|
176
354
|
|
|
177
355
|
### Library Installation
|
|
@@ -183,20 +361,117 @@ npm install @gabrielerandelli/minus-tracker
|
|
|
183
361
|
### Library Usage
|
|
184
362
|
|
|
185
363
|
```ts
|
|
186
|
-
import {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
364
|
+
import {
|
|
365
|
+
DEGIROParser,
|
|
366
|
+
Calculator,
|
|
367
|
+
ParseError,
|
|
368
|
+
CalculationError,
|
|
369
|
+
} from "@gabrielerandelli/minus-tracker";
|
|
370
|
+
import type { GainsReport, LotMethod } from "@gabrielerandelli/minus-tracker";
|
|
371
|
+
|
|
372
|
+
// 1. Parse
|
|
373
|
+
const parser = new DEGIROParser();
|
|
374
|
+
const transactions = parser.parse(csvString); // throws ParseError on bad CSV
|
|
375
|
+
if (parser.warnings.length > 0) {
|
|
376
|
+
console.warn("Skipped rows:", parser.warnings);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// 2. Calculate
|
|
380
|
+
const method: LotMethod = "LIFO"; // or "FIFO"
|
|
381
|
+
const report: GainsReport = new Calculator(
|
|
382
|
+
transactions,
|
|
383
|
+
parser.warnings,
|
|
384
|
+
).calculateGains(method);
|
|
385
|
+
|
|
386
|
+
console.log(report.plusvalenze); // EUR capital gains (number)
|
|
387
|
+
console.log(report.minusvalenze); // EUR capital losses (number, absolute value)
|
|
388
|
+
console.log(report.netResult); // plusvalenze - minusvalenze
|
|
389
|
+
console.log(report.lots); // MatchedLot[] — per-lot breakdown
|
|
390
|
+
|
|
391
|
+
// 3. Error handling
|
|
392
|
+
try {
|
|
393
|
+
const txs = parser.parse(csvString);
|
|
394
|
+
const r = new Calculator(txs, parser.warnings).calculateGains("LIFO");
|
|
395
|
+
} catch (err) {
|
|
396
|
+
if (err instanceof ParseError) {
|
|
397
|
+
if (err.code === "MISSING_COLUMN") {
|
|
398
|
+
console.error("Missing column:", err.columnName);
|
|
399
|
+
} else {
|
|
400
|
+
console.error("Invalid CSV");
|
|
401
|
+
}
|
|
402
|
+
} else if (err instanceof CalculationError) {
|
|
403
|
+
console.error(`SELL without prior BUY: ${err.isin} on ${err.date}`);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
190
406
|
```
|
|
191
407
|
|
|
408
|
+
> **Note:** `parser.warningEntries` (visible in TypeScript autocomplete) is an internal API used by the CLI renderer. Use `parser.warnings` (`string[]`) for library consumers.
|
|
409
|
+
|
|
192
410
|
minus-tracker is **pure tax math** — no UI, auth, database, or PDF.
|
|
193
411
|
|
|
194
412
|
**Prerequisites:** Node.js ≥ 24 ([nodejs.org](https://nodejs.org))
|
|
195
413
|
|
|
414
|
+
### FAQ / Troubleshooting
|
|
415
|
+
|
|
416
|
+
**My CSV is rejected with "missing column" or "invalid CSV"**
|
|
417
|
+
Confirm you exported from Activity → **Transactions**, not the Account Statement. The parser requires the Transactions export format.
|
|
418
|
+
|
|
419
|
+
**Some rows are skipped with a warning**
|
|
420
|
+
Rows are skipped (without aborting the calculation) when: the ISIN is empty, the currency is not EUR/USD/GBP/CHF, or no ECB rate exists within 3 trading days of the trade date. Run `validate` for details.
|
|
421
|
+
|
|
422
|
+
**Error "no open lots for ISIN X on date Y"**
|
|
423
|
+
The CSV contains a SELL for a position that has no prior BUY in the same file. The BUY may be in a prior year's export that was not included. Use `validate` to inspect the parsed transactions.
|
|
424
|
+
|
|
425
|
+
**ECB rates are outdated**
|
|
426
|
+
Run `minus-tracker rates --update`. The `calc` command also auto-updates if the snapshot is more than 7 days old.
|
|
427
|
+
|
|
428
|
+
**LIFO or FIFO?**
|
|
429
|
+
LIFO is the standard lot-matching method under Italian tax law for the Regime Dichiarativo. FIFO is available for comparison or other jurisdictions. Consult your tax advisor for confirmation.
|
|
430
|
+
|
|
431
|
+
### Known Limitations
|
|
432
|
+
|
|
433
|
+
minus-tracker aggregates gains and losses from **all financial instruments into a single total**, regardless of their tax category.
|
|
434
|
+
|
|
435
|
+
Italian law requires that **redditi diversi** (individual stocks, derivatives, certificates — Art. 67 TUIR) and **redditi di capitale** (ETFs / UCITS funds — Art. 44 TUIR) be kept separate: a loss on an ETF cannot offset a gain on a stock, and vice versa.
|
|
436
|
+
|
|
437
|
+
**Portfolios holding only stocks or only ETFs:** the calculation is correct.
|
|
438
|
+
**Mixed portfolios (stocks + ETFs):** the reported net result cannot be used directly for tax filing. In this case, lots must be manually separated by tax category before filing, with the help of a qualified tax advisor.
|
|
439
|
+
|
|
196
440
|
### Disclaimer
|
|
197
441
|
|
|
198
|
-
minus-tracker is a **
|
|
199
|
-
|
|
442
|
+
minus-tracker is a **personal project** developed in a private capacity and is **not affiliated with, endorsed by, or representative of the author's employer or any other organisation**.
|
|
443
|
+
|
|
444
|
+
This tool is provided **solely as a calculation aid** and **does not constitute tax, legal, or financial advice**. The author **accepts no liability** for errors in the output, misuse of the tool, or any decisions made by end users based on the generated reports.
|
|
445
|
+
|
|
446
|
+
You are **always** encouraged to review results with a qualified tax advisor before filing any return.
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## Stress Test Suite
|
|
451
|
+
|
|
452
|
+
Run the built-in stress test to verify your installation handles all supported scenarios:
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
minus-tracker stress-test
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
This generates 100 sample CSV files in a temporary directory, runs all CLI commands on each,
|
|
459
|
+
and reports pass/fail results without touching your project files.
|
|
460
|
+
|
|
461
|
+
### Options
|
|
462
|
+
|
|
463
|
+
| Flag | Default | Description |
|
|
464
|
+
| --------------------- | --------------------------------- | -------------------------------------- |
|
|
465
|
+
| `--range N-M` | `1-100` | Run only scenarios N through M |
|
|
466
|
+
| `--keep` | off | Keep generated CSV files after the run |
|
|
467
|
+
| `--json` | off | Output results as JSON |
|
|
468
|
+
| `--output-dir <path>` | `/tmp/minus-tracker-stress-<ts>/` | Override temp directory |
|
|
469
|
+
|
|
470
|
+
### Scenarios
|
|
471
|
+
|
|
472
|
+
100 scenarios covering: EUR/USD/GBP/CHF stocks, LIFO vs FIFO divergence, partial lot
|
|
473
|
+
consumption, multi-ISIN portfolios, ECB weekend fallback, warning and error cases,
|
|
474
|
+
same-day trades, rounding edge cases, and large portfolios (up to 200 transactions).
|
|
200
475
|
|
|
201
476
|
---
|
|
202
477
|
|