Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 65509a27d6 |
@@ -97,6 +97,10 @@ def input_cost_geographies(item: str) -> dict:
|
|||||||
return _get("/api/data/input-cost-geographies", item=item)
|
return _get("/api/data/input-cost-geographies", item=item)
|
||||||
|
|
||||||
|
|
||||||
|
def nutrient_cost(geo: str | None = None) -> dict:
|
||||||
|
return _get("/api/data/nutrient-cost", geo=geo)
|
||||||
|
|
||||||
|
|
||||||
def futures(commodity: str, delivery: str | None = None) -> dict:
|
def futures(commodity: str, delivery: str | None = None) -> dict:
|
||||||
return _get("/api/data/futures", commodity=commodity, delivery=delivery)
|
return _get("/api/data/futures", commodity=commodity, delivery=delivery)
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ def _ton(cents: Optional[int]) -> str:
|
|||||||
return f"${cents / 100:.2f}"
|
return f"${cents / 100:.2f}"
|
||||||
|
|
||||||
|
|
||||||
|
def _per_lb(cents: Optional[int]) -> str:
|
||||||
|
if cents is None:
|
||||||
|
return "—"
|
||||||
|
return f"${cents / 100:.2f}"
|
||||||
|
|
||||||
|
|
||||||
def _basis(cents: Optional[int]) -> str:
|
def _basis(cents: Optional[int]) -> str:
|
||||||
if cents is None:
|
if cents is None:
|
||||||
return "—"
|
return "—"
|
||||||
@@ -207,6 +213,57 @@ def fmt_price_series(payload: dict, max_points: int = 60) -> str:
|
|||||||
return "\n".join(head + body) + "\n"
|
return "\n".join(head + body) + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
_NUTRIENT_LABEL = {"n": "Nitrogen (N)", "p2o5": "Phosphate (P₂O₅)", "k2o": "Potash (K₂O)"}
|
||||||
|
|
||||||
|
|
||||||
|
def fmt_nutrient_cost(payload: dict) -> str:
|
||||||
|
"""Cheapest fertilizer per pound of N / P2O5 / K2O for a region."""
|
||||||
|
geo = payload.get("geo") or "Cornbelt"
|
||||||
|
src = payload.get("source") or "USDA AgTransport"
|
||||||
|
products = payload.get("products") or []
|
||||||
|
cheapest = payload.get("cheapest") or {}
|
||||||
|
if not products:
|
||||||
|
return f"### Fertilizer value per nutrient — {geo}\n\nNo data on file.\n"
|
||||||
|
by_item = {p["item"]: p for p in products}
|
||||||
|
|
||||||
|
lines = [f"### Fertilizer value per pound of nutrient — {geo}", ""]
|
||||||
|
for nut in ("n", "p2o5", "k2o"):
|
||||||
|
it = cheapest.get(nut)
|
||||||
|
prod = by_item.get(it or "")
|
||||||
|
if prod is not None:
|
||||||
|
c = (prod.get("cost_per_lb") or {}).get(nut)
|
||||||
|
lines.append(
|
||||||
|
f"- **Cheapest {_NUTRIENT_LABEL[nut]}:** "
|
||||||
|
f"{prod.get('label') or it} at {_per_lb(c)}/lb"
|
||||||
|
)
|
||||||
|
lines += ["", "| Product | Grade | $/ton | $/lb N | $/lb P₂O₅ | $/lb K₂O |",
|
||||||
|
"|---|---|---:|---:|---:|---:|"]
|
||||||
|
|
||||||
|
def _nkey(p: dict):
|
||||||
|
v = (p.get("cost_per_lb") or {}).get("n")
|
||||||
|
return (v is None, v if v is not None else 0)
|
||||||
|
|
||||||
|
for p in sorted(products, key=_nkey): # cheapest N first, blanks last
|
||||||
|
a = p.get("analysis") or {}
|
||||||
|
cpl = p.get("cost_per_lb") or {}
|
||||||
|
grade = (a.get("grade") or "") + ("*" if a.get("grade_assumed") else "")
|
||||||
|
lines.append(
|
||||||
|
f"| {p.get('label') or p['item']} | {grade} | {_ton(p.get('price_cents_per_ton'))} | "
|
||||||
|
f"{_per_lb(cpl.get('n'))} | {_per_lb(cpl.get('p2o5'))} | {_per_lb(cpl.get('k2o'))} |"
|
||||||
|
)
|
||||||
|
|
||||||
|
period = next((p.get("period") for p in products if p.get("period")), None)
|
||||||
|
assumed = any((p.get("analysis") or {}).get("grade_assumed") for p in products)
|
||||||
|
foot = f"_Source: {src}"
|
||||||
|
if period:
|
||||||
|
foot += f" · as of {_ym(period)}"
|
||||||
|
foot += " · $/lb = $/ton ÷ (analysis% × 2000 lb)"
|
||||||
|
if assumed:
|
||||||
|
foot += " · *UAN grade assumed 32-0-0"
|
||||||
|
lines.append("\n" + foot + "_")
|
||||||
|
return "\n".join(lines) + "\n"
|
||||||
|
|
||||||
|
|
||||||
# ---------- futures quote + change ----------
|
# ---------- futures quote + change ----------
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -411,6 +411,27 @@ def input_cost_series(
|
|||||||
return fmt.fmt_price_series(client.input_cost_series(item=it, geo=g))
|
return fmt.fmt_price_series(client.input_cost_series(item=it, geo=g))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def nutrient_cost(
|
||||||
|
geo: Annotated[
|
||||||
|
str | None,
|
||||||
|
Field(description="Fertilizer region (default 'Cornbelt'). Same regions as "
|
||||||
|
"input_cost_trend (e.g. 'U.S. Gulf NOLA', 'Northern Plains')."),
|
||||||
|
] = None,
|
||||||
|
) -> str:
|
||||||
|
"""Cheapest fertilizer per POUND of nutrient — "what's the best value for N (or P/K)?".
|
||||||
|
|
||||||
|
Converts each fertilizer's regional $/ton (USDA AgTransport, latest month) into
|
||||||
|
$/lb of N, P2O5, and K2O from its grade, ranks them, and names the cheapest
|
||||||
|
source of each nutrient (anhydrous usually wins on N; DAP/MAP are phosphate
|
||||||
|
buys; potash is the K source). Use THIS — not input_cost_trend ($/ton only) —
|
||||||
|
whenever the grower asks which fertilizer is the best buy / best nitrogen value.
|
||||||
|
UAN grade is assumed 32-0-0."""
|
||||||
|
g = geo.strip() if geo else None
|
||||||
|
with track("nutrient_cost", geo=g or ""):
|
||||||
|
return fmt.fmt_nutrient_cost(client.nutrient_cost(geo=g))
|
||||||
|
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def list_sources() -> str:
|
def list_sources() -> str:
|
||||||
"""All active scrapers + their last-success timestamps and any pending failures."""
|
"""All active scrapers + their last-success timestamps and any pending failures."""
|
||||||
|
|||||||
@@ -390,3 +390,44 @@ def test_fmt_summary_includes_best_for_today():
|
|||||||
assert "Mercer Landmark — St Henry" in out
|
assert "Mercer Landmark — St Henry" in out
|
||||||
assert "$4.5800" in out # corn last
|
assert "$4.5800" in out # corn last
|
||||||
assert "No current-month local bid posted" in out # soy fallback
|
assert "No current-month local bid posted" in out # soy fallback
|
||||||
|
|
||||||
|
|
||||||
|
def test_fmt_nutrient_cost():
|
||||||
|
payload = {
|
||||||
|
"geo": "Cornbelt",
|
||||||
|
"source": "USDA AgTransport",
|
||||||
|
"products": [
|
||||||
|
{"item": "anhydrous", "label": "anhydrous ammonia", "unit": "$/ton",
|
||||||
|
"geo": "Cornbelt", "period": "2026-03-01", "price_cents_per_ton": 88062,
|
||||||
|
"analysis": {"grade": "82-0-0", "grade_assumed": False},
|
||||||
|
"cost_per_lb": {"n": 54, "p2o5": None, "k2o": None}},
|
||||||
|
{"item": "urea", "label": "urea", "unit": "$/ton", "geo": "Cornbelt",
|
||||||
|
"period": "2026-03-01", "price_cents_per_ton": 69812,
|
||||||
|
"analysis": {"grade": "46-0-0", "grade_assumed": False},
|
||||||
|
"cost_per_lb": {"n": 76, "p2o5": None, "k2o": None}},
|
||||||
|
{"item": "uan", "label": "UAN (28-32%)", "unit": "$/ton", "geo": "Cornbelt",
|
||||||
|
"period": "2026-03-01", "price_cents_per_ton": 47612,
|
||||||
|
"analysis": {"grade": "32-0-0", "grade_assumed": True},
|
||||||
|
"cost_per_lb": {"n": 74, "p2o5": None, "k2o": None}},
|
||||||
|
{"item": "potash", "label": "potash (0-0-60)", "unit": "$/ton",
|
||||||
|
"geo": "Cornbelt", "period": "2026-03-01", "price_cents_per_ton": 35938,
|
||||||
|
"analysis": {"grade": "0-0-60", "grade_assumed": False},
|
||||||
|
"cost_per_lb": {"n": None, "p2o5": None, "k2o": 30}},
|
||||||
|
],
|
||||||
|
"cheapest": {"n": "anhydrous", "p2o5": None, "k2o": "potash"},
|
||||||
|
}
|
||||||
|
out = fmt.fmt_nutrient_cost(payload)
|
||||||
|
assert "Cornbelt" in out
|
||||||
|
assert "Cheapest Nitrogen (N):** anhydrous ammonia at $0.54/lb" in out
|
||||||
|
assert "Cheapest Potash (K₂O):** potash (0-0-60) at $0.30/lb" in out
|
||||||
|
# anhydrous (cheapest N) sorts above urea in the table
|
||||||
|
assert out.index("anhydrous ammonia |") < out.index("| urea |")
|
||||||
|
# UAN grade-assumed marker + footnote
|
||||||
|
assert "32-0-0*" in out
|
||||||
|
assert "UAN grade assumed 32-0-0" in out
|
||||||
|
# potash supplies no N -> em-dash in the N column
|
||||||
|
assert "—" in out
|
||||||
|
|
||||||
|
|
||||||
|
def test_fmt_nutrient_cost_empty():
|
||||||
|
assert "No data on file" in fmt.fmt_nutrient_cost({"geo": "Cornbelt", "products": []})
|
||||||
|
|||||||
Reference in New Issue
Block a user