Add price_trend / price_series MCP tools (USDA NASS grain)
CI / test (push) Failing after 0s
CI / build-push (push) Has been skipped

Real $/bu price + MoM/YoY change + seasonal percentile context for corn/soy/
wheat, US + states, deep history. Wraps the new /api/data/price-trend and
/api/data/price-series endpoints. Changelog updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 12:02:13 -04:00
parent 7b6661e3d9
commit 47cac9b521
5 changed files with 215 additions and 0 deletions
+79
View File
@@ -90,6 +90,85 @@ def fmt_best(commodity: str, payload: dict) -> str:
)
# ---------- reference price trends (USDA NASS / EIA) ----------
def _unit_money(cents, unit: str) -> str:
if cents is None:
return ""
dollars = cents / 100
if unit == "$/gal":
return f"${dollars:.3f}/gal"
if unit == "$/bu":
return f"${dollars:.2f}/bu"
if unit == "$/ton":
return f"${dollars:.2f}/ton"
return f"${dollars:.2f}"
def _signed(cents) -> str:
if cents is None:
return ""
return f"{'+' if cents >= 0 else ''}${abs(cents)/100:.2f}"
def _pct(p) -> str:
return "" if p is None else f"{'+' if p >= 0 else ''}{abs(p):.1f}%"
def _ym(period: str) -> str:
# 2026-04-01 -> "Apr 2026"; weekly date -> as-is
try:
y, m, d = period.split("-")
return f"{_MONTH_NAMES_3[int(m)-1]} {y}" if d == "01" else period
except Exception:
return period
_MONTH_NAMES_3 = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
def fmt_price_trend(payload: dict, label: str = "price received") -> str:
commodity = payload.get("commodity")
geo = payload.get("geo")
unit = payload.get("unit") or "$/bu"
t = payload.get("trend")
if not t:
return f"### {commodity}{geo}{label}\n\nNo data on file.\n"
when = _ym(t["period"])
lines = [f"### {commodity}{geo}{label}, {when}: {_unit_money(t['value_cents'], unit)}", ""]
arrow = _delta_arrow(t.get("change_cents"))
lines.append(f"- **Change:** {arrow} {_signed(t.get('change_cents'))} ({_pct(t.get('change_pct'))}) vs prior period")
if t.get("yoy_cents") is not None:
lines.append(f"- **Year-over-year:** {_signed(t.get('yoy_change_cents'))} ({_pct(t.get('yoy_pct'))})")
s = t.get("seasonal")
if s:
lines.append(
f"- **Seasonal:** {s['percentile']}th pct vs last {s['sample_years']} same-months "
f"(normal {_unit_money(s['normal_cents'], unit)}, range "
f"{_unit_money(s['min_cents'], unit)}{_unit_money(s['max_cents'], unit)}) "
f"· {_pct(s.get('vs_normal_pct'))} vs normal")
lines.append(f"- **Recent direction:** {_delta_arrow({'up':1,'down':-1,'flat':0}[t['recent_direction']])} {t['recent_direction']}")
lines.append(f"\n_Source: {payload.get('source') or 'USDA NASS'} · {t['points']} months on file_")
return "\n".join(lines) + "\n"
def fmt_price_series(payload: dict, max_points: int = 60) -> str:
commodity = payload.get("commodity")
geo = payload.get("geo")
unit = payload.get("unit") or "$/bu"
series = payload.get("series") or []
if not series:
return f"### {commodity}{geo} series\n\nNo data on file.\n"
shown = series[-max_points:]
head = [f"### {commodity}{geo}{payload.get('count', len(series))} periods "
f"(showing last {len(shown)})", "",
"| Period | Price |", "|---|---:|"]
body = [f"| {_ym(p['period'])} | {_unit_money(p['value_cents'], unit)} |" for p in shown]
return "\n".join(head + body) + "\n"
# ---------- futures quote + change ----------