@gabrielerandelli/minus-tracker 0.7.0 → 0.8.1

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 CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
4
4
  [![npm version](https://img.shields.io/npm/v/@gabrielerandelli/minus-tracker.svg)](https://www.npmjs.com/package/@gabrielerandelli/minus-tracker)
5
+ [![npm downloads](https://img.shields.io/npm/dm/@gabrielerandelli/minus-tracker.svg)](https://www.npmjs.com/package/@gabrielerandelli/minus-tracker)
6
+ [![Node](https://img.shields.io/badge/node-%3E%3D24-brightgreen.svg)](https://nodejs.org)
7
+ [![MCP](https://img.shields.io/badge/MCP-server-blueviolet.svg)](https://modelcontextprotocol.io)
8
+
9
+ ⚠️ **Ausilio al calcolo, non consulenza fiscale** — vedi l'[Avvertenza](#avvertenza).
10
+ ⚠️ **Calculation aid only, not tax advice** — see the [Disclaimer](#disclaimer).
11
+
12
+ 🤖 **Novità: server MCP** — qualsiasi agente AI può calcolare plusvalenze/minusvalenze italiane direttamente, senza passare dalla CLI.
13
+ 🤖 **New: MCP server** — any AI agent can compute Italian capital gains/losses directly, no CLI required.
14
+
15
+ ✅ Validato su tutti i 12 scenari FAQ dell'Agenzia delle Entrate · 120 test automatici · zero dipendenze runtime nella libreria core.
16
+ ✅ Validated against all 12 Agenzia delle Entrate FAQ scenarios · 120 automated tests · zero runtime dependencies in the core library.
17
+
18
+ _L'unico tool open-source che trasforma un export DEGIRO grezzo direttamente in plusvalenze/minusvalenze corrette secondo l'Agenzia delle Entrate — come CLI, libreria, o strumento MCP richiamabile dal tuo agente AI._
19
+ _The only open-source tool that turns a raw DEGIRO export directly into Agenzia-Entrate-correct capital gains/losses — as a CLI, a library, or an MCP tool your AI agent can call._
5
20
 
6
21
  ---
7
22
 
@@ -16,10 +31,23 @@ Il tool elabora i dati partendo direttamente dal formato CSV esportato da DEGIRO
16
31
  - Calcolo di plusvalenze e minusvalenze con gestione dei lotti via **LIFO o FIFO** (configurabile)
17
32
  - **Parser integrato** per i file CSV di DEGIRO
18
33
  - Gestione **multivaluta** con tassi storici BCE (EUR, USD, GBP, CHF)
34
+ - **Classificazione fiscale degli strumenti finanziari in due categorie** (Bucket A/B) — azioni,
35
+ ETF, titoli di stato, derivati — con classificazione automatica tramite OpenFIGI e sidecar JSON
36
+ persistente
37
+ - **Modello Redditi PF**: genera Quadro RT (redditi diversi) e Quadro RM (redditi di capitale) a
38
+ partire dai lotti calcolati, con riporto delle minusvalenze pregresse (regola dei 4 anni)
19
39
  - Suite di test allineata alle **FAQ dell'Agenzia delle Entrate**
20
40
  - Output disponibile in **italiano** (default) o **inglese** (`--lang en`)
21
41
  - Disponibile come pacchetto NPM con supporto CLI
22
42
 
43
+ **Novità in v0.8.0:**
44
+
45
+ - **Modalità stateless per `Classifier`**: `classify()` può ora funzionare senza alcun accesso al
46
+ filesystem (nessun sidecar), utile per l'integrazione con agenti e automazioni
47
+ - **Server MCP** (`minus-tracker-mcp`): espone `parse_transactions`, `classify_instruments` e
48
+ `calculate_gains` come tool MCP su stdio, per l'uso diretto da parte di agenti AI — vedi la
49
+ sezione [Server MCP](#server-mcp) più sotto
50
+
23
51
  ### Avvio rapido
24
52
 
25
53
  Se non hai ancora un export di DEGIRO a disposizione, puoi testare il tool con il file di esempio incluso nel pacchetto.
@@ -85,15 +113,16 @@ npx @gabrielerandelli/minus-tracker calc trades.csv
85
113
 
86
114
  ### Utilizzo CLI
87
115
 
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 |
116
+ | Comando | Flag principali | Note |
117
+ | ---------------------- | -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
118
+ | `calc <file.csv>` | `--method LIFO\|FIFO` (default: LIFO), `--lang it\|en`, `--json`, `--export-dichiarazione [path]`, `--carry-forward` | Non aggiorna mai i tassi BCE da solo esegui `rates --update` periodicamente; usa il sidecar di `classify` se presente |
119
+ | `classify <file.csv>` | `--offline` | Classifica gli strumenti (Bucket A/B) e crea/aggiorna il sidecar `*.classify.json` |
120
+ | `validate <file.csv>` | `--lang it\|en` | Exit 0 con avvisi; exit 1 in caso di errori bloccanti |
121
+ | `rates --check` | — | Mostra la copertura della snapshot BCE in locale |
122
+ | `rates --update` | — | Scarica i tassi aggiornati dall'API BCE |
123
+ | `config --lang it\|en` | — | Salva la lingua preferita |
124
+ | `config --show` | — | Mostra la lingua correntemente impostata |
125
+ | `stress-test` | `--range N-M`, `--keep`, `--json`, `--output-dir` | Documentato in fondo |
97
126
 
98
127
  Precedenza lingua: `--lang` > lingua salvata > italiano (default).
99
128
 
@@ -128,6 +157,7 @@ npm install @gabrielerandelli/minus-tracker
128
157
  import {
129
158
  DEGIROParser,
130
159
  Calculator,
160
+ Classifier,
131
161
  ParseError,
132
162
  CalculationError,
133
163
  } from "@gabrielerandelli/minus-tracker";
@@ -140,19 +170,25 @@ if (parser.warnings.length > 0) {
140
170
  console.warn("Righe saltate:", parser.warnings);
141
171
  }
142
172
 
143
- // 2. Calcolo
144
- const method: LotMethod = "LIFO"; // oppure "FIFO"
145
- const report: GainsReport = new Calculator(
173
+ // 2. Classificazione (Bucket A/B) — facoltativa, abilita Quadro RT/RM nel report
174
+ const classification = await new Classifier().classify(
146
175
  transactions,
147
- parser.warnings,
148
- ).calculateGains(method);
176
+ "trades.classify.json", // sidecar persistente; assente in modalità stateless
177
+ );
178
+
179
+ // 3. Calcolo
180
+ const method: LotMethod = "LIFO"; // oppure "FIFO"
181
+ const report: GainsReport = new Calculator(transactions, parser.warnings, {
182
+ classification,
183
+ }).calculateGains(method);
149
184
 
150
185
  console.log(report.plusvalenze); // numero in EUR
151
186
  console.log(report.minusvalenze); // numero in EUR (valore assoluto)
152
187
  console.log(report.netResult); // plusvalenze - minusvalenze
153
188
  console.log(report.lots); // MatchedLot[] — dettaglio per lotto
189
+ console.log(report.dichiarazione); // Quadro RT/RM, se classification è stata passata
154
190
 
155
- // 3. Gestione errori
191
+ // 4. Gestione errori
156
192
  try {
157
193
  const txs = parser.parse(csvString);
158
194
  const r = new Calculator(txs, parser.warnings).calculateGains("LIFO");
@@ -177,6 +213,46 @@ try {
177
213
 
178
214
  **Prerequisiti:** Node.js ≥ 24 ([nodejs.org](https://nodejs.org))
179
215
 
216
+ ### Server MCP
217
+
218
+ A partire dalla v0.8.0, minus-tracker include un binario `minus-tracker-mcp` che espone un
219
+ [server MCP](https://modelcontextprotocol.io) su stdio, pensato per l'uso diretto da parte di
220
+ agenti AI (senza passare dalla CLI):
221
+
222
+ ```bash
223
+ npx -p @gabrielerandelli/minus-tracker minus-tracker-mcp
224
+ ```
225
+
226
+ Configurazione tipica per un client MCP (es. Claude Desktop, `claude_desktop_config.json`):
227
+
228
+ ```json
229
+ {
230
+ "mcpServers": {
231
+ "minus-tracker": {
232
+ "command": "npx",
233
+ "args": [
234
+ "-y",
235
+ "-p",
236
+ "@gabrielerandelli/minus-tracker",
237
+ "minus-tracker-mcp"
238
+ ]
239
+ }
240
+ }
241
+ }
242
+ ```
243
+
244
+ Il server espone 3 tool:
245
+
246
+ | Tool | Descrizione |
247
+ | ---------------------- | -------------------------------------------------------------------------------------- |
248
+ | `parse_transactions` | Esegue il parsing di un CSV DEGIRO, restituendo `transactions`/`warnings`/`incomeRows` |
249
+ | `classify_instruments` | Classifica gli ISIN in Bucket A/B (modalità stateless — nessun sidecar) |
250
+ | `calculate_gains` | Calcola plusvalenze/minusvalenze (LIFO/FIFO) e, se disponibile, Quadro RT/RM |
251
+
252
+ `classify_instruments` supporta `existingClassification`, `overrides` e `offline: true` per
253
+ funzionare senza rete e senza accesso al filesystem — pensato per essere invocato ripetutamente
254
+ da un agente in chiamate successive, mantenendo lo stato lato client.
255
+
180
256
  ### Domande frequenti
181
257
 
182
258
  **Il CSV viene rifiutato con "colonna mancante" o "CSV non valido"**
@@ -189,7 +265,7 @@ Le righe vengono saltate (senza bloccare il calcolo) quando: l'ISIN è vuoto, la
189
265
  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
266
 
191
267
  **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.
268
+ Esegui `minus-tracker rates --update`. Il comando `calc` non aggiorna mai i tassi da solo: l'aggiornamento è sempre un'azione esplicita.
193
269
 
194
270
  **LIFO o FIFO?**
195
271
  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.
@@ -251,10 +327,22 @@ It loads data following the CSV format used by DEGIRO.
251
327
  - Capital-gains/loss calculation with configurable **LIFO and FIFO** lot matching
252
328
  - **DEGIRO CSV parser**
253
329
  - **Multi-currency** handling with historical ECB rates (EUR, USD, GBP, CHF)
330
+ - **Two-bucket classification** (Bucket A/B) of financial instruments — stocks, ETFs, government
331
+ bonds, derivatives — with automatic OpenFIGI-backed classification and a persistent JSON sidecar
332
+ - **Modello Redditi PF** generation: Quadro RT (capital gains) and Quadro RM (capital income) built
333
+ from the calculated lots, with prior-year loss carryforward (4-year rule)
254
334
  - Test suite based on **Agenzia Entrate FAQ**
255
335
  - Output in **Italian** (default) or **English** (`--lang en`)
256
336
  - minus-tracker is an NPM package with CLI support
257
337
 
338
+ **New in v0.8.0:**
339
+
340
+ - **Stateless mode for `Classifier`**: `classify()` can now run with zero filesystem access (no
341
+ sidecar file), useful for embedding in agents/automations
342
+ - **MCP server** (`minus-tracker-mcp`): exposes `parse_transactions`, `classify_instruments`, and
343
+ `calculate_gains` as MCP tools over stdio, for direct use by AI agents — see the
344
+ [MCP Server](#mcp-server) section below
345
+
258
346
  ### Quick Start
259
347
 
260
348
  Don't have a DEGIRO export yet? Use the sample file bundled with the package.
@@ -321,15 +409,16 @@ npx @gabrielerandelli/minus-tracker calc trades.csv
321
409
 
322
410
  ### CLI Usage
323
411
 
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 |
412
+ | Command | Key flags | Notes |
413
+ | ---------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
414
+ | `calc <file.csv>` | `--method LIFO\|FIFO` (default: LIFO), `--lang it\|en`, `--json`, `--export-dichiarazione [path]`, `--carry-forward` | Never fetches ECB rates on its own run `rates --update` periodically; uses `classify`'s sidecar when present |
415
+ | `classify <file.csv>` | `--offline` | Classifies instruments (Bucket A/B) and creates/updates the `*.classify.json` sidecar |
416
+ | `validate <file.csv>` | `--lang it\|en` | Exit 0 with warnings; exit 1 on hard errors |
417
+ | `rates --check` | — | Shows bundled ECB snapshot coverage |
418
+ | `rates --update` | — | Fetches fresh rates from the ECB API |
419
+ | `config --lang it\|en` | — | Saves language preference |
420
+ | `config --show` | — | Shows current language setting |
421
+ | `stress-test` | `--range N-M`, `--keep`, `--json`, `--output-dir` | Documented below |
333
422
 
334
423
  Language precedence: `--lang` flag > saved config > Italian (default).
335
424
 
@@ -364,6 +453,7 @@ npm install @gabrielerandelli/minus-tracker
364
453
  import {
365
454
  DEGIROParser,
366
455
  Calculator,
456
+ Classifier,
367
457
  ParseError,
368
458
  CalculationError,
369
459
  } from "@gabrielerandelli/minus-tracker";
@@ -376,19 +466,25 @@ if (parser.warnings.length > 0) {
376
466
  console.warn("Skipped rows:", parser.warnings);
377
467
  }
378
468
 
379
- // 2. Calculate
380
- const method: LotMethod = "LIFO"; // or "FIFO"
381
- const report: GainsReport = new Calculator(
469
+ // 2. Classify (Bucket A/B) — optional, enables Quadro RT/RM in the report
470
+ const classification = await new Classifier().classify(
382
471
  transactions,
383
- parser.warnings,
384
- ).calculateGains(method);
472
+ "trades.classify.json", // persistent sidecar; omit for stateless mode
473
+ );
474
+
475
+ // 3. Calculate
476
+ const method: LotMethod = "LIFO"; // or "FIFO"
477
+ const report: GainsReport = new Calculator(transactions, parser.warnings, {
478
+ classification,
479
+ }).calculateGains(method);
385
480
 
386
481
  console.log(report.plusvalenze); // EUR capital gains (number)
387
482
  console.log(report.minusvalenze); // EUR capital losses (number, absolute value)
388
483
  console.log(report.netResult); // plusvalenze - minusvalenze
389
484
  console.log(report.lots); // MatchedLot[] — per-lot breakdown
485
+ console.log(report.dichiarazione); // Quadro RT/RM, when classification was passed
390
486
 
391
- // 3. Error handling
487
+ // 4. Error handling
392
488
  try {
393
489
  const txs = parser.parse(csvString);
394
490
  const r = new Calculator(txs, parser.warnings).calculateGains("LIFO");
@@ -411,6 +507,46 @@ minus-tracker is **pure tax math** — no UI, auth, database, or PDF.
411
507
 
412
508
  **Prerequisites:** Node.js ≥ 24 ([nodejs.org](https://nodejs.org))
413
509
 
510
+ ### MCP Server
511
+
512
+ As of v0.8.0, minus-tracker ships a `minus-tracker-mcp` binary exposing an
513
+ [MCP server](https://modelcontextprotocol.io) over stdio, for direct use by AI agents (no need to
514
+ go through the CLI):
515
+
516
+ ```bash
517
+ npx -p @gabrielerandelli/minus-tracker minus-tracker-mcp
518
+ ```
519
+
520
+ Typical MCP client configuration (e.g. Claude Desktop, `claude_desktop_config.json`):
521
+
522
+ ```json
523
+ {
524
+ "mcpServers": {
525
+ "minus-tracker": {
526
+ "command": "npx",
527
+ "args": [
528
+ "-y",
529
+ "-p",
530
+ "@gabrielerandelli/minus-tracker",
531
+ "minus-tracker-mcp"
532
+ ]
533
+ }
534
+ }
535
+ }
536
+ ```
537
+
538
+ The server exposes 3 tools:
539
+
540
+ | Tool | Description |
541
+ | ---------------------- | --------------------------------------------------------------------- |
542
+ | `parse_transactions` | Parses a DEGIRO CSV into `transactions`/`warnings`/`incomeRows` |
543
+ | `classify_instruments` | Classifies ISINs into Bucket A/B (stateless mode — no sidecar file) |
544
+ | `calculate_gains` | Calculates gains/losses (LIFO/FIFO) and, when available, Quadro RT/RM |
545
+
546
+ `classify_instruments` supports `existingClassification`, `overrides`, and `offline: true` to run
547
+ without network access or filesystem access — designed to be called repeatedly by an agent across
548
+ multiple calls, with state kept client-side.
549
+
414
550
  ### FAQ / Troubleshooting
415
551
 
416
552
  **My CSV is rejected with "missing column" or "invalid CSV"**
@@ -423,7 +559,7 @@ Rows are skipped (without aborting the calculation) when: the ISIN is empty, the
423
559
  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
560
 
425
561
  **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.
562
+ Run `minus-tracker rates --update`. The `calc` command never fetches rates on its own — refreshing is always an explicit, user-invoked action.
427
563
 
428
564
  **LIFO or FIFO?**
429
565
  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.