@gabrielerandelli/minus-tracker 0.5.6 → 0.5.8

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
@@ -1,37 +1,83 @@
1
1
  # minus-tracker
2
2
 
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
4
-
5
- > **Status:** v0.5.6 — published on npm as `@gabrielerandelli/minus-tracker`.
4
+ [![npm version](https://img.shields.io/npm/v/@gabrielerandelli/minus-tracker.svg)](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.
11
+
12
+ Il tool elabora i dati partendo direttamente dal formato CSV esportato da DEGIRO.
13
+
14
+ ### Funzionalità
15
+
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
22
+
23
+ ### Avvio rapido
24
+
25
+ Se non hai ancora un export di DEGIRO a disposizione, puoi testare il tool con il file di esempio incluso nel pacchetto.
26
+
27
+ **Via npx (senza installazione globale):**
28
+
29
+ ```bash
30
+ curl -O https://raw.githubusercontent.com/gabrielerandelli/minus-tracker/main/samples/sample-trades.csv
31
+ npx @gabrielerandelli/minus-tracker calc sample-trades.csv
32
+ ```
33
+
34
+ **Se hai già installato il pacchetto localmente:**
35
+
36
+ ```bash
37
+ ./node_modules/.bin/minus-tracker calc node_modules/@gabrielerandelli/minus-tracker/samples/sample-trades.csv
38
+ ```
14
39
 
15
- Carica dati seguendo il formato CSV adottato da DEGIRO.
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.
16
41
 
17
- ### Cosa fa
42
+ ### Output di esempio
18
43
 
19
- - Calcolo plusvalenze/minusvalenze con abbinamento lotti **LIFO e FIFO** (configurabile)
20
- - **Parser CSV DEGIRO**
21
- - Gestione **multi-valuta** con tassi BCE storici (EUR, USD, GBP, CHF)
22
- - Suite di test basata su **FAQ Agenzia Entrate**
23
- - L'ouput può essere restituito in **italiano** (predefinito) o **inglese** (`--lang en`)
24
- - minus-tracker è un package NPM con supporto CLI
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.
25
71
 
26
72
  ### Installazione CLI
27
73
 
28
- **Installazione globale** (comando disponibile da qualsiasi directory):
74
+ **Installazione globale** (per rendere il comando disponibile in ogni directory):
29
75
 
30
76
  ```bash
31
77
  npm install -g @gabrielerandelli/minus-tracker
32
78
  ```
33
79
 
34
- **Senza installazione globale** (nessuna configurazione necessaria):
80
+ **Senza installazione globale** (esecuzione al volo):
35
81
 
36
82
  ```bash
37
83
  npx @gabrielerandelli/minus-tracker calc trades.csv
@@ -39,47 +85,143 @@ npx @gabrielerandelli/minus-tracker calc trades.csv
39
85
 
40
86
  ### Utilizzo CLI
41
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
+
42
100
  ```bash
43
- # Calcola plusvalenze/minusvalenze (output in italiano)
101
+ # Calcola plusvalenze/minusvalenze (output in italiano, metodo LIFO)
44
102
  minus-tracker calc trades.csv
45
103
 
46
- # Output in inglese
47
- minus-tracker calc --lang en trades.csv
48
-
49
- # Imposta la lingua in modo permanente
50
- 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
51
106
 
52
107
  # Valida il CSV senza calcolare
53
108
  minus-tracker validate trades.csv
54
109
 
55
- # Controlla/aggiorna i tassi BCE
110
+ # Controlla o aggiorna i tassi BCE in locale
56
111
  minus-tracker rates --check
57
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
58
117
  ```
59
118
 
60
- ### Installazione libreria
119
+ ### Installazione come libreria
61
120
 
62
121
  ```bash
63
122
  npm install @gabrielerandelli/minus-tracker
64
123
  ```
65
124
 
66
- ### Utilizzo libreria
125
+ ### Esempio di utilizzo nel codice
67
126
 
68
127
  ```ts
69
- import { DEGIROParser, Calculator } from "@gabrielerandelli/minus-tracker";
70
-
71
- const transactions = new DEGIROParser().parse(csv);
72
- const report = new Calculator(transactions).calculateGains("LIFO"); // o "FIFO"
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
+ }
73
172
  ```
74
173
 
75
- minus-tracker è **solo calcolo fiscale** nessuna UI, autenticazione, database o PDF.
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.
76
177
 
77
178
  **Prerequisiti:** Node.js ≥ 24 ([nodejs.org](https://nodejs.org))
78
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
+
79
197
  ### Avvertenza
80
198
 
81
- minus-tracker è un **ausilio al calcolo, non consulenza fiscale**. I risultati sono
82
- destinati alla revisione e alla consegna a un commercialista qualificato.
199
+ minus-tracker è un **ausilio al calcolo e non costituisce in alcun modo consulenza fiscale**. I report generati sono pensati per essere verificati e consegnati a un commercialista o a un professionista qualificato.
200
+
201
+ ---
202
+
203
+ ## Stress Test
204
+
205
+ Puoi eseguire la suite di stress test integrata per verificare che l'installazione gestisca correttamente tutti gli scenari previsti:
206
+
207
+ ```bash
208
+ minus-tracker stress-test
209
+ ```
210
+
211
+ 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.
212
+
213
+ ### Opzioni disponibili
214
+
215
+ | Flag | Default | Descrizione |
216
+ | --------------------- | --------------------------------- | ------------------------------------------------ |
217
+ | `--range N-M` | `1-100` | Esegue solo gli scenari da N a M |
218
+ | `--keep` | disattivato | Mantiene i file CSV generati dopo il test |
219
+ | `--json` | disattivato | Restituisce i risultati in formato JSON |
220
+ | `--output-dir <path>` | `/tmp/minus-tracker-stress-<ts>/` | Permette di personalizzare la cartella di output |
221
+
222
+ ### Scenari coperti
223
+
224
+ 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).
83
225
 
84
226
  ---
85
227
 
@@ -100,6 +242,56 @@ It loads data following the CSV format used by DEGIRO.
100
242
  - Output in **Italian** (default) or **English** (`--lang en`)
101
243
  - minus-tracker is an NPM package with CLI support
102
244
 
245
+ ### Quick Start
246
+
247
+ Don't have a DEGIRO export yet? Use the sample file bundled with the package.
248
+
249
+ **Via npx (no global install needed):**
250
+
251
+ ```bash
252
+ curl -O https://raw.githubusercontent.com/gabrielerandelli/minus-tracker/main/samples/sample-trades.csv
253
+ npx @gabrielerandelli/minus-tracker calc sample-trades.csv
254
+ ```
255
+
256
+ **If you have already installed the package locally:**
257
+
258
+ ```bash
259
+ ./node_modules/.bin/minus-tracker calc node_modules/@gabrielerandelli/minus-tracker/samples/sample-trades.csv
260
+ ```
261
+
262
+ The file contains 5 fictional trades (Apple Inc in USD + ASML Holding in EUR) and
263
+ demonstrates partial LIFO matching, currency conversion, and a positive net result.
264
+
265
+ ### Example Output
266
+
267
+ Running `calc` on the sample file produces:
268
+
269
+ ```
270
+ METHOD: LIFO | TAX YEAR: 2024
271
+
272
+ ISIN PRODUCT QTY BUY DATE SELL DATE BUY EUR SELL EUR GAIN/LOSS
273
+ US0378331005 Apple Inc 10 2024-01-02 2024-01-05 1,371.11 1,188.37 -182.75
274
+ NL0010273215 ASML Holding N.V. 3 2024-04-01 2024-07-15 2,552.00 2,849.00 +297.00
275
+ NL0010273215 ASML Holding N.V. 3 2024-01-15 2024-07-15 2,401.20 2,849.00 +447.80
276
+
277
+ ────────────────────────────────────────────────────────────────────────
278
+ PLUSVALENZE: 744.80 EUR
279
+ MINUSVALENZE: 182.75 EUR
280
+ NET RESULT: 562.05 EUR
281
+ ```
282
+
283
+ Add `--json` to get the raw `GainsReport` object — useful for programmatic integrations (see [Library Usage](#library-usage)).
284
+
285
+ ### DEGIRO CSV Format
286
+
287
+ Export from **Activity → Transactions** (NOT the Account Statement) in your DEGIRO account. Use the default export with all columns selected.
288
+
289
+ Supported currencies: **EUR** (no conversion), **USD**, **GBP**, **CHF** (bundled ECB historical rates, 2019–present).
290
+
291
+ Dates in the DEGIRO export are in `DD-MM-YYYY` format; the parser converts them to ISO automatically.
292
+
293
+ 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.
294
+
103
295
  ### CLI Installation
104
296
 
105
297
  **Global install** (command available system-wide):
@@ -116,15 +308,24 @@ npx @gabrielerandelli/minus-tracker calc trades.csv
116
308
 
117
309
  ### CLI Usage
118
310
 
119
- ```bash
120
- # Calculate gains/losses (Italian output, default)
121
- minus-tracker calc trades.csv
311
+ | Command | Key flags | Notes |
312
+ | ---------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------- |
313
+ | `calc <file.csv>` | `--method LIFO\|FIFO` (default: LIFO), `--lang it\|en`, `--json` | Auto-fetches ECB rates if snapshot is more than 7 days old |
314
+ | `validate <file.csv>` | `--lang it\|en` | Exit 0 with warnings; exit 1 on hard errors |
315
+ | `rates --check` | — | Shows bundled ECB snapshot coverage |
316
+ | `rates --update` | — | Fetches fresh rates from the ECB API |
317
+ | `config --lang it\|en` | — | Saves language preference |
318
+ | `config --show` | — | Shows current language setting |
319
+ | `stress-test` | `--range N-M`, `--keep`, `--json`, `--output-dir` | Documented below |
320
+
321
+ Language precedence: `--lang` flag > saved config > Italian (default).
122
322
 
123
- # English output
323
+ ```bash
324
+ # Calculate gains/losses (English output, LIFO method)
124
325
  minus-tracker calc --lang en trades.csv
125
326
 
126
- # Set language permanently
127
- minus-tracker config --lang en # or: --lang it
327
+ # FIFO method, JSON output
328
+ minus-tracker calc --method FIFO --json trades.csv
128
329
 
129
330
  # Validate CSV without calculating
130
331
  minus-tracker validate trades.csv
@@ -132,6 +333,10 @@ minus-tracker validate trades.csv
132
333
  # Check/update ECB rates
133
334
  minus-tracker rates --check
134
335
  minus-tracker rates --update
336
+
337
+ # Set language permanently
338
+ minus-tracker config --lang en # or: --lang it
339
+ minus-tracker config --show
135
340
  ```
136
341
 
137
342
  ### Library Installation
@@ -143,16 +348,73 @@ npm install @gabrielerandelli/minus-tracker
143
348
  ### Library Usage
144
349
 
145
350
  ```ts
146
- import { DEGIROParser, Calculator } from "@gabrielerandelli/minus-tracker";
147
-
148
- const transactions = new DEGIROParser().parse(csv);
149
- const report = new Calculator(transactions).calculateGains("LIFO"); // or "FIFO"
351
+ import {
352
+ DEGIROParser,
353
+ Calculator,
354
+ ParseError,
355
+ CalculationError,
356
+ } from "@gabrielerandelli/minus-tracker";
357
+ import type { GainsReport, LotMethod } from "@gabrielerandelli/minus-tracker";
358
+
359
+ // 1. Parse
360
+ const parser = new DEGIROParser();
361
+ const transactions = parser.parse(csvString); // throws ParseError on bad CSV
362
+ if (parser.warnings.length > 0) {
363
+ console.warn("Skipped rows:", parser.warnings);
364
+ }
365
+
366
+ // 2. Calculate
367
+ const method: LotMethod = "LIFO"; // or "FIFO"
368
+ const report: GainsReport = new Calculator(
369
+ transactions,
370
+ parser.warnings,
371
+ ).calculateGains(method);
372
+
373
+ console.log(report.plusvalenze); // EUR capital gains (number)
374
+ console.log(report.minusvalenze); // EUR capital losses (number, absolute value)
375
+ console.log(report.netResult); // plusvalenze - minusvalenze
376
+ console.log(report.lots); // MatchedLot[] — per-lot breakdown
377
+
378
+ // 3. Error handling
379
+ try {
380
+ const txs = parser.parse(csvString);
381
+ const r = new Calculator(txs, parser.warnings).calculateGains("LIFO");
382
+ } catch (err) {
383
+ if (err instanceof ParseError) {
384
+ if (err.code === "MISSING_COLUMN") {
385
+ console.error("Missing column:", err.columnName);
386
+ } else {
387
+ console.error("Invalid CSV");
388
+ }
389
+ } else if (err instanceof CalculationError) {
390
+ console.error(`SELL without prior BUY: ${err.isin} on ${err.date}`);
391
+ }
392
+ }
150
393
  ```
151
394
 
395
+ > **Note:** `parser.warningEntries` (visible in TypeScript autocomplete) is an internal API used by the CLI renderer. Use `parser.warnings` (`string[]`) for library consumers.
396
+
152
397
  minus-tracker is **pure tax math** — no UI, auth, database, or PDF.
153
398
 
154
399
  **Prerequisites:** Node.js ≥ 24 ([nodejs.org](https://nodejs.org))
155
400
 
401
+ ### FAQ / Troubleshooting
402
+
403
+ **My CSV is rejected with "missing column" or "invalid CSV"**
404
+ Confirm you exported from Activity → **Transactions**, not the Account Statement. The parser requires the Transactions export format.
405
+
406
+ **Some rows are skipped with a warning**
407
+ 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.
408
+
409
+ **Error "no open lots for ISIN X on date Y"**
410
+ 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.
411
+
412
+ **ECB rates are outdated**
413
+ Run `minus-tracker rates --update`. The `calc` command also auto-updates if the snapshot is more than 7 days old.
414
+
415
+ **LIFO or FIFO?**
416
+ 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 commercialista for confirmation.
417
+
156
418
  ### Disclaimer
157
419
 
158
420
  minus-tracker is a **calculation aid, not tax advice**. Outputs are intended for review
@@ -160,6 +422,34 @@ and handoff to a qualified commercialista.
160
422
 
161
423
  ---
162
424
 
425
+ ## Stress Test Suite
426
+
427
+ Run the built-in stress test to verify your installation handles all supported scenarios:
428
+
429
+ ```bash
430
+ minus-tracker stress-test
431
+ ```
432
+
433
+ This generates 100 sample CSV files in a temporary directory, runs all CLI commands on each,
434
+ and reports pass/fail results without touching your project files.
435
+
436
+ ### Options
437
+
438
+ | Flag | Default | Description |
439
+ | --------------------- | --------------------------------- | -------------------------------------- |
440
+ | `--range N-M` | `1-100` | Run only scenarios N through M |
441
+ | `--keep` | off | Keep generated CSV files after the run |
442
+ | `--json` | off | Output results as JSON |
443
+ | `--output-dir <path>` | `/tmp/minus-tracker-stress-<ts>/` | Override temp directory |
444
+
445
+ ### Scenarios
446
+
447
+ 100 scenarios covering: EUR/USD/GBP/CHF stocks, LIFO vs FIFO divergence, partial lot
448
+ consumption, multi-ISIN portfolios, ECB weekend fallback, warning and error cases,
449
+ same-day trades, rounding edge cases, and large portfolios (up to 200 transactions).
450
+
451
+ ---
452
+
163
453
  ## License
164
454
 
165
455
  [MIT](./LICENSE) © 2026 Gabriele Randelli