@fuzzle/opencode-accountant 0.0.12 → 0.0.13
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 +23 -25
- package/agent/accountant.md +105 -5
- package/docs/tools/classify-statements.md +404 -0
- package/docs/tools/import-statements.md +252 -0
- package/docs/tools/update-prices.md +581 -0
- package/package.json +3 -2
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
# update-prices Tool
|
|
2
|
+
|
|
3
|
+
The `update-prices` tool fetches end-of-day currency exchange rates and updates the price journals in `ledger/currencies/`. It uses the external `pricehist` tool to fetch data from various sources (Yahoo Finance, CoinMarketCap, ECB, etc.).
|
|
4
|
+
|
|
5
|
+
This tool is **restricted to the accountant agent only**.
|
|
6
|
+
|
|
7
|
+
## Arguments
|
|
8
|
+
|
|
9
|
+
| Argument | Type | Default | Description |
|
|
10
|
+
| ---------- | ------- | ------- | -------------------------------------------------------------- |
|
|
11
|
+
| `backfill` | boolean | `false` | If true, fetch historical prices from configured backfill_date |
|
|
12
|
+
|
|
13
|
+
## Output Format
|
|
14
|
+
|
|
15
|
+
### Daily Update Success (backfill: false)
|
|
16
|
+
|
|
17
|
+
When fetching only yesterday's prices:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"success": true,
|
|
22
|
+
"endDate": "2026-02-21",
|
|
23
|
+
"backfill": false,
|
|
24
|
+
"results": [
|
|
25
|
+
{
|
|
26
|
+
"ticker": "EUR",
|
|
27
|
+
"priceLine": "P 2026-02-21 EUR 0.944 CHF",
|
|
28
|
+
"file": "eur.journal"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"ticker": "USD",
|
|
32
|
+
"priceLine": "P 2026-02-21 USD 0.881 CHF",
|
|
33
|
+
"file": "usd.journal"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"ticker": "BTC",
|
|
37
|
+
"priceLine": "P 2026-02-21 BTC 52341.50 CHF",
|
|
38
|
+
"file": "btc.journal"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Note:** The `priceLine` shows the latest (most recent) price added. In daily mode, only one price per currency is fetched.
|
|
45
|
+
|
|
46
|
+
### Backfill Success (backfill: true)
|
|
47
|
+
|
|
48
|
+
When fetching historical prices:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"success": true,
|
|
53
|
+
"endDate": "2026-02-21",
|
|
54
|
+
"backfill": true,
|
|
55
|
+
"results": [
|
|
56
|
+
{
|
|
57
|
+
"ticker": "EUR",
|
|
58
|
+
"priceLine": "P 2026-02-21 EUR 0.944 CHF",
|
|
59
|
+
"file": "eur.journal"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"ticker": "USD",
|
|
63
|
+
"priceLine": "P 2026-02-21 USD 0.881 CHF",
|
|
64
|
+
"file": "usd.journal"
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Note:** The output shows the latest price line, but many historical prices were added to the journal files. Check the journal files to see all added prices.
|
|
71
|
+
|
|
72
|
+
### Partial Failure
|
|
73
|
+
|
|
74
|
+
When some currencies succeed and others fail:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"success": false,
|
|
79
|
+
"endDate": "2026-02-21",
|
|
80
|
+
"backfill": false,
|
|
81
|
+
"results": [
|
|
82
|
+
{
|
|
83
|
+
"ticker": "EUR",
|
|
84
|
+
"priceLine": "P 2026-02-21 EUR 0.944 CHF",
|
|
85
|
+
"file": "eur.journal"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"ticker": "BTC",
|
|
89
|
+
"error": "No price data found within date range 2026-02-21 to 2026-02-21"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"ticker": "AAPL",
|
|
93
|
+
"error": "API rate limit exceeded"
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The tool processes all currencies independently. Partial success is possible.
|
|
100
|
+
|
|
101
|
+
### Configuration Error
|
|
102
|
+
|
|
103
|
+
When `config/prices.yaml` is missing or invalid:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"error": "Failed to load configuration: config/prices.yaml not found"
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Agent Restriction Error
|
|
112
|
+
|
|
113
|
+
When called by the wrong agent:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"error": "This tool is restricted to the accountant agent only.",
|
|
118
|
+
"hint": "Use: Task(subagent_type='accountant', prompt='update prices')",
|
|
119
|
+
"caller": "main assistant"
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Daily vs Backfill Modes
|
|
124
|
+
|
|
125
|
+
### Daily Mode (backfill: false, default)
|
|
126
|
+
|
|
127
|
+
**Behavior:**
|
|
128
|
+
|
|
129
|
+
- Fetches only yesterday's price for each currency
|
|
130
|
+
- Fast execution (single date per currency)
|
|
131
|
+
- Typical use: Daily or weekly routine updates
|
|
132
|
+
|
|
133
|
+
**Date range:** Yesterday to yesterday
|
|
134
|
+
|
|
135
|
+
**Example:**
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
update-prices()
|
|
139
|
+
# or
|
|
140
|
+
update-prices(backfill: false)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Use when:**
|
|
144
|
+
|
|
145
|
+
- Performing routine price updates
|
|
146
|
+
- Keeping prices current
|
|
147
|
+
- No historical gaps exist
|
|
148
|
+
|
|
149
|
+
### Backfill Mode (backfill: true)
|
|
150
|
+
|
|
151
|
+
**Behavior:**
|
|
152
|
+
|
|
153
|
+
- Fetches historical prices from `backfill_date` to yesterday
|
|
154
|
+
- Slower execution (multiple dates per currency)
|
|
155
|
+
- Typical use: Initial setup, adding new currency, filling gaps
|
|
156
|
+
|
|
157
|
+
**Date range:** Per-currency `backfill_date` (or default) to yesterday
|
|
158
|
+
|
|
159
|
+
**Example:**
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
update-prices(backfill: true)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Use when:**
|
|
166
|
+
|
|
167
|
+
- Adding a new currency (populate full history)
|
|
168
|
+
- Fixing missing dates (fill gaps)
|
|
169
|
+
- Initial repository setup (populate all currencies)
|
|
170
|
+
- Recovering from extended outage
|
|
171
|
+
|
|
172
|
+
### Backfill Date Configuration
|
|
173
|
+
|
|
174
|
+
**Per-currency backfill_date:**
|
|
175
|
+
|
|
176
|
+
```yaml
|
|
177
|
+
currencies:
|
|
178
|
+
EUR:
|
|
179
|
+
source: yahoo
|
|
180
|
+
pair: EURCHF=X
|
|
181
|
+
fmt_base: CHF
|
|
182
|
+
backfill_date: '2024-01-01' # Start from this date
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Default backfill_date:**
|
|
186
|
+
|
|
187
|
+
- If currency has no `backfill_date` configured: January 1st of current year
|
|
188
|
+
- Example: In 2026, default is `2026-01-01`
|
|
189
|
+
|
|
190
|
+
**Why per-currency?**
|
|
191
|
+
|
|
192
|
+
- Different assets have different availability histories
|
|
193
|
+
- Cryptocurrencies may have shorter histories
|
|
194
|
+
- Some stocks/commodities have specific start dates
|
|
195
|
+
|
|
196
|
+
## Date Range Behavior
|
|
197
|
+
|
|
198
|
+
### End Date (Always Yesterday)
|
|
199
|
+
|
|
200
|
+
The tool **always fetches up to yesterday**, never today.
|
|
201
|
+
|
|
202
|
+
**Why?**
|
|
203
|
+
|
|
204
|
+
- End-of-day prices are used for accounting
|
|
205
|
+
- Today's prices are incomplete (market still open)
|
|
206
|
+
- Consistency: yesterday is the latest complete day
|
|
207
|
+
|
|
208
|
+
**Example:**
|
|
209
|
+
|
|
210
|
+
- If run on 2026-02-22, `endDate` will be `2026-02-21`
|
|
211
|
+
|
|
212
|
+
### Start Date
|
|
213
|
+
|
|
214
|
+
**Daily mode:**
|
|
215
|
+
|
|
216
|
+
- Start date = end date (yesterday)
|
|
217
|
+
- Fetches only one day
|
|
218
|
+
|
|
219
|
+
**Backfill mode:**
|
|
220
|
+
|
|
221
|
+
- Start date = currency's `backfill_date` (or default: Jan 1 of current year)
|
|
222
|
+
- Fetches range from start to yesterday
|
|
223
|
+
|
|
224
|
+
### Date Filtering
|
|
225
|
+
|
|
226
|
+
The tool filters price data to only include dates within the requested range.
|
|
227
|
+
|
|
228
|
+
**Why?**
|
|
229
|
+
|
|
230
|
+
- Prevents accidentally adding future dates
|
|
231
|
+
- Ensures data consistency
|
|
232
|
+
- Some sources may return data outside requested range
|
|
233
|
+
|
|
234
|
+
## Deduplication Logic
|
|
235
|
+
|
|
236
|
+
The tool updates journal files **in place** with automatic deduplication.
|
|
237
|
+
|
|
238
|
+
### How Deduplication Works
|
|
239
|
+
|
|
240
|
+
1. **Read existing** price lines from journal file (or empty if new)
|
|
241
|
+
2. **Build map** of `date → price line`
|
|
242
|
+
3. **Add existing** prices to map
|
|
243
|
+
4. **Add/override** with new prices (newer overwrites older for same date)
|
|
244
|
+
5. **Sort** by date (ascending: oldest first, newest at bottom)
|
|
245
|
+
6. **Write** back to file
|
|
246
|
+
|
|
247
|
+
### Key Behaviors
|
|
248
|
+
|
|
249
|
+
| Behavior | Description |
|
|
250
|
+
| --------------- | -------------------------------------------------- |
|
|
251
|
+
| Duplicate dates | Newer price overwrites older for the same date |
|
|
252
|
+
| Timestamps | Preserved from original source (if present) |
|
|
253
|
+
| Sort order | Chronological (oldest first, newest at bottom) |
|
|
254
|
+
| File updates | In-place (no backups created) |
|
|
255
|
+
| Idempotent | Running twice produces same result as running once |
|
|
256
|
+
|
|
257
|
+
### Deduplication Example
|
|
258
|
+
|
|
259
|
+
**Before (existing file):**
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
P 2026-02-19 EUR 0.942 CHF
|
|
263
|
+
P 2026-02-20 EUR 0.943 CHF
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**New data fetched:**
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
P 2026-02-20 EUR 0.945 CHF # Different price for same date
|
|
270
|
+
P 2026-02-21 EUR 0.944 CHF # New date
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**After deduplication:**
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
P 2026-02-19 EUR 0.942 CHF # Unchanged
|
|
277
|
+
P 2026-02-20 EUR 0.945 CHF # Updated (newer overwrites)
|
|
278
|
+
P 2026-02-21 EUR 0.944 CHF # Added
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Timestamps
|
|
282
|
+
|
|
283
|
+
Some sources provide timestamps:
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
P 2026-02-21 00:00:00 EUR 0.944 CHF
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The tool preserves timestamps if present, but deduplication is based on **date only** (ignoring time).
|
|
290
|
+
|
|
291
|
+
## Price File Format
|
|
292
|
+
|
|
293
|
+
### Journal File Structure
|
|
294
|
+
|
|
295
|
+
```
|
|
296
|
+
# ledger/currencies/eur.journal
|
|
297
|
+
P 2026-01-15 EUR 0.945 CHF
|
|
298
|
+
P 2026-01-16 EUR 0.943 CHF
|
|
299
|
+
P 2026-02-21 EUR 0.944 CHF
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Price Line Format
|
|
303
|
+
|
|
304
|
+
**Format:** `P date commodity price base-currency`
|
|
305
|
+
|
|
306
|
+
**Components:**
|
|
307
|
+
|
|
308
|
+
- `P` = Price directive (hledger syntax)
|
|
309
|
+
- `date` = YYYY-MM-DD (may include timestamp HH:MM:SS)
|
|
310
|
+
- `commodity` = Currency being priced (e.g., EUR, USD, BTC)
|
|
311
|
+
- `price` = Exchange rate value
|
|
312
|
+
- `base-currency` = Base currency for conversion (e.g., CHF)
|
|
313
|
+
|
|
314
|
+
**Example:**
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
P 2026-02-21 EUR 0.944 CHF
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Means: 1 EUR = 0.944 CHF on 2026-02-21
|
|
321
|
+
|
|
322
|
+
### File Locations
|
|
323
|
+
|
|
324
|
+
- All price journals stored in `ledger/currencies/`
|
|
325
|
+
- One file per currency (configured in `config/prices.yaml`)
|
|
326
|
+
- Files updated in place (existing prices preserved, new ones added/merged)
|
|
327
|
+
|
|
328
|
+
**Example structure:**
|
|
329
|
+
|
|
330
|
+
```
|
|
331
|
+
ledger/
|
|
332
|
+
└── currencies/
|
|
333
|
+
├── eur.journal
|
|
334
|
+
├── usd.journal
|
|
335
|
+
├── btc.journal
|
|
336
|
+
└── eth.journal
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Typical Workflow
|
|
340
|
+
|
|
341
|
+
### Scenario 1: Daily Price Update
|
|
342
|
+
|
|
343
|
+
**Goal:** Keep prices current with daily/weekly updates
|
|
344
|
+
|
|
345
|
+
1. Run `update-prices()` (or `update-prices(backfill: false)`)
|
|
346
|
+
2. Check output for any errors
|
|
347
|
+
3. Verify prices were added:
|
|
348
|
+
```bash
|
|
349
|
+
tail -3 ledger/currencies/eur.journal
|
|
350
|
+
```
|
|
351
|
+
4. Success: Latest prices now available for hledger
|
|
352
|
+
|
|
353
|
+
**Frequency:** Daily, weekly, or as needed for current prices
|
|
354
|
+
|
|
355
|
+
### Scenario 2: Adding a New Currency
|
|
356
|
+
|
|
357
|
+
**Goal:** Add a new currency with full historical data
|
|
358
|
+
|
|
359
|
+
1. Add currency config to `config/prices.yaml`:
|
|
360
|
+
```yaml
|
|
361
|
+
currencies:
|
|
362
|
+
GBP:
|
|
363
|
+
source: yahoo
|
|
364
|
+
pair: GBPCHF=X
|
|
365
|
+
fmt_base: CHF
|
|
366
|
+
file: gbp.journal
|
|
367
|
+
backfill_date: '2024-01-01'
|
|
368
|
+
```
|
|
369
|
+
2. Run `update-prices(backfill: true)` to fetch historical data
|
|
370
|
+
3. Check output and verify `ledger/currencies/gbp.journal` created
|
|
371
|
+
4. Inspect file to confirm date range:
|
|
372
|
+
```bash
|
|
373
|
+
head -3 ledger/currencies/gbp.journal
|
|
374
|
+
tail -3 ledger/currencies/gbp.journal
|
|
375
|
+
```
|
|
376
|
+
5. Subsequent updates: use daily mode (`update-prices()`)
|
|
377
|
+
|
|
378
|
+
### Scenario 3: Fixing Missing Dates
|
|
379
|
+
|
|
380
|
+
**Goal:** Fill gaps in existing price history
|
|
381
|
+
|
|
382
|
+
1. Identify date gaps in price journals:
|
|
383
|
+
```bash
|
|
384
|
+
cat ledger/currencies/eur.journal
|
|
385
|
+
# Notice: prices for Feb 15-20 are missing
|
|
386
|
+
```
|
|
387
|
+
2. Run `update-prices(backfill: true)` to fill gaps
|
|
388
|
+
3. Deduplication ensures:
|
|
389
|
+
- Existing prices preserved
|
|
390
|
+
- Missing dates added
|
|
391
|
+
- No duplicate entries
|
|
392
|
+
4. Verify gaps are filled:
|
|
393
|
+
```bash
|
|
394
|
+
cat ledger/currencies/eur.journal | grep "2026-02"
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Scenario 4: Handling Errors
|
|
398
|
+
|
|
399
|
+
**Goal:** Recover from partial failures
|
|
400
|
+
|
|
401
|
+
1. Run `update-prices()`
|
|
402
|
+
2. Output shows `success: false` with partial results:
|
|
403
|
+
```json
|
|
404
|
+
{
|
|
405
|
+
"success": false,
|
|
406
|
+
"results": [
|
|
407
|
+
{ "ticker": "EUR", "priceLine": "..." },
|
|
408
|
+
{ "ticker": "BTC", "error": "API rate limit exceeded" }
|
|
409
|
+
]
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
3. Check error messages for each failed currency
|
|
413
|
+
4. Common fixes:
|
|
414
|
+
- **Network issues**: Retry later
|
|
415
|
+
- **API rate limits**: Wait (usually resets hourly/daily) and retry
|
|
416
|
+
- **Invalid config**: Fix `config/prices.yaml` syntax or source/pair
|
|
417
|
+
- **Missing pricehist**: Install external dependency
|
|
418
|
+
5. Re-run tool (idempotent - safe to retry)
|
|
419
|
+
|
|
420
|
+
**Note:** Successful currencies are already updated. Only failed currencies need retry.
|
|
421
|
+
|
|
422
|
+
## Configuration
|
|
423
|
+
|
|
424
|
+
### Config File: `config/prices.yaml`
|
|
425
|
+
|
|
426
|
+
**Structure:**
|
|
427
|
+
|
|
428
|
+
```yaml
|
|
429
|
+
currencies:
|
|
430
|
+
<TICKER>:
|
|
431
|
+
source: <source-name> # e.g., yahoo, coinbase, coinmarketcap, ecb
|
|
432
|
+
pair: <trading-pair> # Source-specific format
|
|
433
|
+
file: <journal-filename> # e.g., eur.journal
|
|
434
|
+
fmt_base: <base-currency> # Optional, e.g., CHF, USD
|
|
435
|
+
backfill_date: <YYYY-MM-DD> # Optional, per-currency backfill start
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Field Descriptions
|
|
439
|
+
|
|
440
|
+
| Field | Required | Description |
|
|
441
|
+
| --------------- | -------- | -------------------------------------------------------------- |
|
|
442
|
+
| `source` | Yes | Price data source (passed to pricehist) |
|
|
443
|
+
| `pair` | Yes | Trading pair identifier (source-specific format) |
|
|
444
|
+
| `file` | Yes | Journal filename in `ledger/currencies/` |
|
|
445
|
+
| `fmt_base` | No | Base currency for price notation (default: inferred from pair) |
|
|
446
|
+
| `backfill_date` | No | Override default backfill start date for this currency |
|
|
447
|
+
|
|
448
|
+
### Configuration Examples
|
|
449
|
+
|
|
450
|
+
**Fiat currencies (Yahoo Finance):**
|
|
451
|
+
|
|
452
|
+
```yaml
|
|
453
|
+
currencies:
|
|
454
|
+
EUR:
|
|
455
|
+
source: yahoo
|
|
456
|
+
pair: EURCHF=X
|
|
457
|
+
fmt_base: CHF
|
|
458
|
+
file: eur.journal
|
|
459
|
+
backfill_date: '2024-01-01'
|
|
460
|
+
|
|
461
|
+
USD:
|
|
462
|
+
source: yahoo
|
|
463
|
+
pair: USDCHF=X
|
|
464
|
+
fmt_base: CHF
|
|
465
|
+
file: usd.journal
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Cryptocurrencies (CoinMarketCap):**
|
|
469
|
+
|
|
470
|
+
```yaml
|
|
471
|
+
currencies:
|
|
472
|
+
BTC:
|
|
473
|
+
source: coinmarketcap
|
|
474
|
+
pair: BTC/CHF
|
|
475
|
+
fmt_base: CHF
|
|
476
|
+
file: btc.journal
|
|
477
|
+
backfill_date: '2025-01-01'
|
|
478
|
+
|
|
479
|
+
ETH:
|
|
480
|
+
source: coinmarketcap
|
|
481
|
+
pair: ETH/CHF
|
|
482
|
+
fmt_base: CHF
|
|
483
|
+
file: eth.journal
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
**EUR via ECB (European Central Bank):**
|
|
487
|
+
|
|
488
|
+
```yaml
|
|
489
|
+
currencies:
|
|
490
|
+
EUR:
|
|
491
|
+
source: ecb
|
|
492
|
+
pair: EUR/CHF
|
|
493
|
+
fmt_base: CHF
|
|
494
|
+
file: eur.journal
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### External Dependency: pricehist
|
|
498
|
+
|
|
499
|
+
The tool uses the `pricehist` command-line tool to fetch price data.
|
|
500
|
+
|
|
501
|
+
**Requirements:**
|
|
502
|
+
|
|
503
|
+
- `pricehist` must be installed and available in PATH
|
|
504
|
+
- Install: `pip install pricehist` (or distribution-specific package)
|
|
505
|
+
|
|
506
|
+
**Supported sources:** Yahoo Finance, CoinMarketCap, Coinbase, ECB, and more. See `pricehist` documentation for full list.
|
|
507
|
+
|
|
508
|
+
**Note:** The tool abstracts pricehist details - you only need to configure `source` and `pair` in the YAML.
|
|
509
|
+
|
|
510
|
+
## Error Handling
|
|
511
|
+
|
|
512
|
+
### Common Errors
|
|
513
|
+
|
|
514
|
+
| Error | Cause | Solution |
|
|
515
|
+
| ------------------- | --------------------------------------- | ------------------------------------------------------------------------------ |
|
|
516
|
+
| External tool error | pricehist not installed or not in PATH | Install pricehist: `pip install pricehist` |
|
|
517
|
+
| No price data found | No data available for date range | Check if date range is valid; API may not have historical data for that period |
|
|
518
|
+
| API rate limit | Too many requests to price source | Wait and retry; rate limits typically reset hourly or daily |
|
|
519
|
+
| Network error | Cannot reach price data source | Check internet connection; retry later |
|
|
520
|
+
| Configuration error | Missing or invalid `config/prices.yaml` | Ensure config file exists with proper YAML syntax and required fields |
|
|
521
|
+
| Invalid date range | Start date after end date | Check `backfill_date` configuration; must be before yesterday |
|
|
522
|
+
| Agent restriction | Called by wrong agent | Use `Task(subagent_type='accountant', prompt='update prices')` |
|
|
523
|
+
| Permission error | Cannot write to journal files | Check file permissions on `ledger/currencies/` directory |
|
|
524
|
+
| Invalid source/pair | Source or pair format incorrect | Check `pricehist` docs for correct format for your source |
|
|
525
|
+
|
|
526
|
+
### Partial Failures
|
|
527
|
+
|
|
528
|
+
The tool processes all currencies **independently**.
|
|
529
|
+
|
|
530
|
+
**Behavior:**
|
|
531
|
+
|
|
532
|
+
- Each currency is fetched and updated separately
|
|
533
|
+
- Failure in one currency doesn't affect others
|
|
534
|
+
- Overall `success: false` if ANY currency fails
|
|
535
|
+
- Check `results` array for per-currency status
|
|
536
|
+
|
|
537
|
+
**Example:**
|
|
538
|
+
|
|
539
|
+
```json
|
|
540
|
+
{
|
|
541
|
+
"success": false,
|
|
542
|
+
"results": [
|
|
543
|
+
{ "ticker": "EUR", "priceLine": "P 2026-02-21 EUR 0.944 CHF", "file": "eur.journal" },
|
|
544
|
+
{ "ticker": "BTC", "error": "API rate limit exceeded" }
|
|
545
|
+
]
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
EUR succeeded (updated), BTC failed (not updated).
|
|
550
|
+
|
|
551
|
+
**Recovery:**
|
|
552
|
+
|
|
553
|
+
- Can re-run tool safely (idempotent)
|
|
554
|
+
- Successful currencies won't re-fetch (deduplication handles this)
|
|
555
|
+
- Only failed currencies will retry
|
|
556
|
+
|
|
557
|
+
### Debugging Tips
|
|
558
|
+
|
|
559
|
+
**Check pricehist directly:**
|
|
560
|
+
|
|
561
|
+
```bash
|
|
562
|
+
pricehist fetch -o ledger -s 2026-02-21 -e 2026-02-21 yahoo EURCHF=X
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
**Check journal file:**
|
|
566
|
+
|
|
567
|
+
```bash
|
|
568
|
+
cat ledger/currencies/eur.journal
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
**Check config syntax:**
|
|
572
|
+
|
|
573
|
+
```bash
|
|
574
|
+
cat config/prices.yaml
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
**Check permissions:**
|
|
578
|
+
|
|
579
|
+
```bash
|
|
580
|
+
ls -la ledger/currencies/
|
|
581
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fuzzle/opencode-accountant",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "An OpenCode accounting agent, specialized in double-entry-bookkepping with hledger",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "ali bengali",
|
|
@@ -23,8 +23,9 @@
|
|
|
23
23
|
"access": "public"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
|
+
"agent",
|
|
26
27
|
"dist",
|
|
27
|
-
"
|
|
28
|
+
"docs"
|
|
28
29
|
],
|
|
29
30
|
"dependencies": {
|
|
30
31
|
"@opencode-ai/plugin": "latest",
|