Files
ag-bids-mcp/CHANGELOG.md
T
justin 0c9bc3b328 Add futures_quote tool: CBOT price + change since open + on day
New futures_quote(commodity, delivery?) tool wraps the new /api/data/futures
endpoint: reports latest price, today's session open, prior settle, and both
moves (since open and on the day). With a delivery month it resolves the listed
contract; without it, the continuous nearby. Adds client.futures(), fmt_futures(),
tests, and a CHANGELOG entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 15:36:56 -04:00

107 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog
Notes for clients/agents that consume the ag-bids MCP tools and the underlying
`ag-monitor` `/api/data/*` HTTP API. Newest first.
## 2026-05-29 — Futures price + change tool
### New MCP tool
- **`futures_quote(commodity, delivery?)`** — CBOT futures price and change for a
grain. Reports the latest price, today's **session open**, the prior day's
close, and **both** moves: **change since open** and **change on the day**
(vs the previous settle). With `delivery` (e.g. `"Jul 2026"`) it resolves the
listed contract that month prices against (e.g. `ZCN26`); without it, the
continuous nearby.
### API changes (`ag-monitor`)
- **`GET /api/data/futures?commodity=<grain>&delivery=<label?>`** — new endpoint.
Returns `{ commodity, delivery, contract, symbol, quote }` where `quote` is
`{ settle_date, open_cents, last_cents, prev_close_cents,
change_since_open_cents, change_on_day_cents, fetched_at }` (or `null` if no
data yet for that contract). `commodity` must be `corn`/`soy`/`wheat`.
- **`futures_quotes` table** gained an `open_cents` column; the futures scraper
now stores the session **Open** alongside the close. Rows captured before this
change have `open_cents = NULL`, so `change_since_open_cents` is `null` for
those until the next session is scraped.
- Futures now also pull at **:30 during the CBOT day session** (on top of the
hourly :00), so `last` and the changes track the session every ~30 min.
### Example questions → tool calls
| Ask | Call |
|---|---|
| Corn Jul futures and how far it's moved today | `futures_quote(commodity="corn", delivery="Jul 2026")` |
| Soy nearby futures, change on the day | `futures_quote(commodity="soy")` |
## 2026-05-29 — Flexible history + basis movement
### New MCP tools
- **`basis_movement(commodity?, source?, delivery?, days=30)`** — aggregated
basis trend, **one headline line per crop**. Averages every matching
(elevator × delivery) series to `avg basis first → last` over the window and
reports how far it moved. This is the cheap "how is basis moving overall"
view. All filters optional; `commodity` (if given) must be `corn`/`soy`/`wheat`.
- Positive move = **cash strengthened** vs futures (basis up); negative = weaker.
- Aggregation is intentional: divergent elevators can net to "flat". When the
aggregate looks flat or surprising, call `basis_detail` to see per-elevator
splits.
- **`basis_detail(commodity?, source?, delivery?, days=30)`** — the drill-down
for `basis_movement`. **One row per (elevator, crop, delivery)** series with
basis `first → last` and the move. Same optional filters.
Both tools do the aggregation **server-side (in the MCP)** and return compact
markdown — they do not dump every raw sample — to keep token usage low. Pattern:
call `basis_movement` first, then `basis_detail` (optionally filtered) only when
you need the breakdown.
### Changed MCP tools
- **`price_history`** — `commodity` is now **optional** (was required). Omit it
to span every crop. Output now groups by **(elevator, crop, delivery)**,
surfaces **basis first → last** in each series summary, and adds a **Futures**
column to the raw points table. Every filter (`commodity`, `source`,
`delivery`, `days`) is optional and AND'd — pivot per elevator, per crop, per
delivery, or any combination.
- Raw per-row points are still only included when the window has ≤ ~60 samples;
wider queries return the per-series summaries only.
- **`latest_prices`** — added the **`kind`** filter (`grain` | `fertilizer`) for
parity with the API. `commodity`, `source`, `delivery`, `kind` all optional.
### API changes (`ag-monitor`)
- **`GET /api/data/history`** — `commodity` query param is now **optional**.
When omitted, returns history across all crops. `source_id`, `delivery`, and
`days` (1730, default 30) remain optional. Response shape is unchanged:
`{ "commodity": <str|null>, "days": <int>, "rows": [...] }`. Each row carries
`fetched_at, source_id, source_name, commodity, delivery, bid_cents,
basis_cents, futures_cents` so callers can pivot client-side.
- `GET /api/data/latest` already supported optional `commodity`, `source`,
`delivery`, `kind` — unchanged.
### Conventions / gotchas
- All money fields are **integer cents**. `bid_cents`/`futures_cents` render as
`$/bu` (4 dp) for grain and `$/ton` (2 dp) for fertilizer; `basis_cents`
renders as a signed dollar value (2 dp), e.g. `-0.14`.
- Basis is only meaningful for grain — the basis tools skip non-grain rows and
any series with no basis on file.
- `source` filtering is by **exact** elevator display name (e.g.
`"Mercer Landmark — Minster"`). Use `list_sources` to get exact names.
### Example questions → tool calls
| Ask | Call |
|---|---|
| Basis movement overall, last 7 days | `basis_movement(days=7)` |
| Corn basis movement across all elevators | `basis_movement(commodity="corn")` |
| Basis movement at one elevator | `basis_movement(source="Mercer Landmark — Minster")` |
| Per-elevator basis breakdown for corn | `basis_detail(commodity="corn")` |
| Last 7 days of history from elevator X for corn | `price_history(commodity="corn", source="…", days=7)` |
| All-crop price history at one elevator | `price_history(source="…")` |
| Latest grain bids only | `latest_prices(kind="grain")` |