opa_get_futures_curve
Retrieve the full futures forward curve for crude oil, including prices across all contract months and market structure analysis such as contango or backwardation.
Instructions
Get the full futures forward curve showing prices across all contract months. Use when the user asks about the forward curve, contango/backwardation, or term structure. Returns a table of contract months with prices and changes, plus market structure analysis.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| contract | No | Futures contract: BZ = Brent crude, CL = WTI crude (default: BZ) | BZ |
Implementation Reference
- src/index.ts:970-1018 (handler)Full tool definition, schema, and handler function for 'opa_get_futures_curve'. Uses server.tool() to register the tool. Accepts a 'contract' parameter (enum BZ/CL, default BZ). Handler calls the /v1/futures/curve API, formats a markdown table of contract months with prices and changes, and computes market structure (contango/backwardation).
server.tool( "opa_get_futures_curve", "Get the full futures forward curve showing prices across all contract months. Use when the user asks about the forward curve, contango/backwardation, or term structure. Returns a table of contract months with prices and changes, plus market structure analysis.", { contract: z .enum(["BZ", "CL"]) .default("BZ") .describe( "Futures contract: BZ = Brent crude, CL = WTI crude (default: BZ)", ), }, async ({ contract }) => { const response = await makeApiRequest<ApiResponse<FuturesData>>( `/v1/futures/curve?contract=${contract}`, ); if ( !response || response.status !== "success" || !response.data.contracts?.length ) { return errorResult( `No futures curve data available for ${contract === "BZ" ? "Brent" : "WTI"} (${contract}). Futures data requires a paid plan.`, ); } const contractName = contract === "BZ" ? "Brent Crude" : "WTI Crude"; const contracts = response.data.contracts; let text = `# ${contractName} Futures Curve (${contract})\n\n`; text += `| Month | Price | Change |\n|-------|-------|--------|\n`; for (const c of contracts) { const changeStr = c.change !== undefined ? `${c.change >= 0 ? "+" : ""}$${c.change.toFixed(2)}` : "N/A"; text += `| ${c.month} | $${c.price.toFixed(2)} | ${changeStr} |\n`; } const front = contracts[0].price; const back = contracts[contracts.length - 1].price; const structure = front > back ? "backwardation" : "contango"; text += `\n**Market Structure**: ${structure} (front $${front.toFixed(2)} vs back $${back.toFixed(2)})`; text += `\n\n_Data from [OilPriceAPI](https://oilpriceapi.com)_`; return textResult(text); }, ); - src/index.ts:972-979 (schema)Input schema for the tool: contract is a Zod enum of 'BZ' (Brent) or 'CL' (WTI), defaulting to 'BZ'.
"Get the full futures forward curve showing prices across all contract months. Use when the user asks about the forward curve, contango/backwardation, or term structure. Returns a table of contract months with prices and changes, plus market structure analysis.", { contract: z .enum(["BZ", "CL"]) .default("BZ") .describe( "Futures contract: BZ = Brent crude, CL = WTI crude (default: BZ)", ), - src/index.ts:970-971 (registration)Registration of the tool via server.tool('opa_get_futures_curve', ...) with description.
server.tool( "opa_get_futures_curve", - src/index.ts:261-269 (helper)FuturesData interface used for the API response type. Contains an array of contracts with month, price, change, and optional volume fields.
interface FuturesData { contracts: Array<{ contract: string; month: string; price: number; change?: number; volume?: number; }>; } - src/index.ts:457-518 (helper)makeApiRequest helper function used by the tool handler to make HTTP requests to the OilPriceAPI with retry logic.
export async function makeApiRequest<T>( endpoint: string, fetchFn: typeof fetch = fetch, ): Promise<T | null> { const headers: Record<string, string> = { "User-Agent": USER_AGENT, Accept: "application/json", }; if (API_KEY) { headers["Authorization"] = `Bearer ${API_KEY}`; } const maxRetries = 3; for (let attempt = 0; attempt <= maxRetries; attempt++) { try { const response = await fetchFn(`${API_BASE}${endpoint}`, { headers }); if (response.ok) { return (await response.json()) as T; } if (response.status === 401) { console.error( "Authentication failed. Set OILPRICEAPI_KEY environment variable. Get a free key at https://oilpriceapi.com/signup", ); return null; } // Retry on 429 and 5xx if ( (response.status === 429 || response.status >= 500) && attempt < maxRetries ) { const retryAfter = response.headers.get("Retry-After"); const delay = retryAfter ? Math.min(parseInt(retryAfter, 10), 60) * 1000 : Math.pow(2, attempt) * 1000; await new Promise((resolve) => setTimeout(resolve, delay)); continue; } console.error( `HTTP ${response.status}: ${response.statusText} for ${endpoint}`, ); return null; } catch (error) { if (attempt === maxRetries) { console.error( `API request failed after ${maxRetries + 1} attempts: ${endpoint}`, error, ); return null; } const delay = Math.pow(2, attempt) * 1000; await new Promise((resolve) => setTimeout(resolve, delay)); } } return null; }