feat(mcp-macro): fetch_cot_disaggregated async fetcher with cache

This commit is contained in:
AdrianoDev
2026-04-29 00:03:53 +02:00
parent 66bcab05f9
commit 2474445b4c
2 changed files with 83 additions and 0 deletions
@@ -664,3 +664,43 @@ async def fetch_cot_tff(symbol: str, lookback_weeks: int = 52) -> dict[str, Any]
_COT_CACHE[key] = out _COT_CACHE[key] = out
_COT_CACHE_TS[key] = now _COT_CACHE_TS[key] = now
return out return out
async def fetch_cot_disaggregated(symbol: str, lookback_weeks: int = 52) -> dict[str, Any]:
"""Fetch COT Disaggregated report per simbolo commodity. Returns ASC by date."""
import time
symbol = symbol.upper()
if symbol not in SYMBOL_TO_CFTC_CODE_DISAGG:
return {"error": "unknown_symbol", "available": ALL_DISAGG_SYMBOLS}
key = (symbol, "disaggregated", lookback_weeks)
now = time.monotonic()
if key in _COT_CACHE and (now - _COT_CACHE_TS[key]) < _COT_TTL:
return _COT_CACHE[key]
code = SYMBOL_TO_CFTC_CODE_DISAGG[symbol]
url = f"{CFTC_BASE_URL}/{DISAGG_DATASET_ID}.json"
async with async_client(timeout=10.0) as client:
resp = await client.get(
url,
params={
"cftc_contract_market_code": code,
"$order": "report_date_as_yyyy_mm_dd DESC",
"$limit": str(lookback_weeks),
},
)
if resp.status_code != 200:
return {"symbol": symbol, "report_type": "disaggregated", "rows": [], "error": "cftc_unavailable"}
raw_rows = resp.json() or []
parsed = [parse_disagg_row(r) for r in raw_rows]
parsed.sort(key=lambda r: r["report_date"])
out = {
"symbol": symbol,
"report_type": "disaggregated",
"rows": parsed,
"data_timestamp": datetime.now(UTC).isoformat(),
}
_COT_CACHE[key] = out
_COT_CACHE_TS[key] = now
return out
+43
View File
@@ -318,3 +318,46 @@ async def test_fetch_cot_tff_unknown_symbol():
assert out.get("error") == "unknown_symbol" assert out.get("error") == "unknown_symbol"
assert "ES" in out.get("available", []) assert "ES" in out.get("available", [])
@pytest.mark.asyncio
async def test_fetch_cot_disagg_happy_path(httpx_mock: pytest_httpx.HTTPXMock):
from mcp_macro.fetchers import fetch_cot_disaggregated
httpx_mock.add_response(
url=httpx.URL(
"https://publicreporting.cftc.gov/resource/72hh-3qpy.json",
params={
"cftc_contract_market_code": "067651",
"$order": "report_date_as_yyyy_mm_dd DESC",
"$limit": "52",
},
),
json=[
{
"report_date_as_yyyy_mm_dd": "2026-04-22T00:00:00.000",
"prod_merc_positions_long_all": "100000",
"prod_merc_positions_short_all": "300000",
"swap_positions_long_all": "50000",
"swap_positions_short_all": "60000",
"m_money_positions_long_all": "200000",
"m_money_positions_short_all": "80000",
"other_rept_positions_long_all": "10000",
"other_rept_positions_short_all": "10000",
"open_interest_all": "1500000",
},
],
)
out = await fetch_cot_disaggregated("CL", lookback_weeks=52)
assert out["symbol"] == "CL"
assert out["report_type"] == "disaggregated"
assert len(out["rows"]) == 1
assert out["rows"][0]["managed_money_net"] == 120000
assert out["rows"][0]["producer_net"] == -200000
@pytest.mark.asyncio
async def test_fetch_cot_disagg_unknown_symbol():
from mcp_macro.fetchers import fetch_cot_disaggregated
out = await fetch_cot_disaggregated("XYZ", lookback_weeks=52)
assert out.get("error") == "unknown_symbol"
assert "CL" in out.get("available", [])