Don't paste a raw candle array into your agent. Wrap one /v1/brief call in a framework tool — the token-compact brief is the context.
Wrap a single patternfetch /v1/brief call in a LangChain or CrewAI tool. The brief — patterns, support/resistance, regime, interpreted RSI/EMA, plus a one-line nl summary — is the context: a few hundred tokens instead of a multi-thousand-token candle array. The tool's docstring is what the LLM reads to decide when to call it, so write it well.
The instinct is to fetch 200 candles from an exchange and stuff the array into the prompt or hand it back from a tool. Two things go wrong. First, token blowup: a 200-row OHLCV array is roughly a few thousand tokens, and you pay for that on every turn it stays in context. Second, and worse, the model re-derives structure on every call — it tries to eyeball the trend, guess support/resistance, and do arithmetic on raw floats, which is exactly where LLMs hallucinate. You spend tokens to hand the model a problem it is bad at.
The fix is to send the digested market state, not the raw numbers. Compute the patterns, levels, regime and indicator state once, server-side, and give the agent a compact summary it can reason over directly. That is what a patternfetch brief is.
One @tool from langchain_core.tools. There is no Python SDK — patternfetch is a plain JSON HTTP API, so this uses requests directly. The docstring is the most important part: it is what the LLM reads to decide when to call the tool, so it describes exactly when market context is needed and what comes back.
import os
import json
import requests
from langchain_core.tools import tool
PF_KEY = os.environ["PATTERNFETCH_KEY"] # pf_… from POST /v1/keys
@tool
def market_brief(ticker: str, timeframe: str = "4h") -> str:
"""Get the current market-state brief for a crypto ticker.
Call this whenever you need market context to reason about a
crypto asset — trend, momentum, key levels, or chart patterns.
Do NOT try to compute these yourself from raw prices.
Returns a token-compact brief (a few hundred tokens, not a raw
candle dump): detected chart/candlestick patterns, support and
resistance levels, the regime (trend direction, strength,
volatility), interpreted RSI/EMA state, and a one-line summary.
Args:
ticker: e.g. "BTC/USDT", "ETH/USDT".
timeframe: one of 1m, 5m, 15m, 1h, 4h, 1d. Default "4h".
Returns:
A human-readable one-line summary followed by the structured
analysis (patterns, levels, regime, indicators) as JSON.
"""
r = requests.post(
"https://patternfetch.com/v1/brief",
json={"ticker": ticker, "timeframe": timeframe},
headers={"Authorization": "Bearer " + PF_KEY},
timeout=30,
)
r.raise_for_status()
analysis = r.json()["analysis"]
# The one-line nl summary is the part the model acts on; the
# structured block is there if it needs to cite a level/pattern.
return analysis["nl"] + "\n\n" + json.dumps(analysis, separators=(",", ":"))
# wire it into an agent
from langchain.agents import create_react_agent # or your agent of choice
# tools=[market_brief] → the model now has market context on demand
That is the whole integration. The agent decides, from the docstring, when it needs market context; it calls market_brief("BTC/USDT", "4h"); it gets back a few hundred tokens it can reason over. No candle math, no token blowup. Prefer httpx? Swap requests.post for httpx.post — the call is identical.
Same call, expressed as a BaseTool subclass (from crewai.tools; older versions use crewai_tools). CrewAI uses a Pydantic args_schema for the inputs and the tool's description as the model-facing docstring.
import os, json
import requests
from crewai.tools import BaseTool # older: from crewai_tools import BaseTool
from pydantic import BaseModel, Field
PF_KEY = os.environ["PATTERNFETCH_KEY"]
class MarketBriefInput(BaseModel):
ticker: str = Field(..., description='Crypto pair, e.g. "BTC/USDT".')
timeframe: str = Field("4h", description="1m, 5m, 15m, 1h, 4h or 1d.")
class MarketBriefTool(BaseTool):
name: str = "market_brief"
description: str = (
"Get the current market-state brief for a crypto ticker. Use this "
"whenever you need market context — trend, momentum, key levels, or "
"chart patterns. Do NOT compute these from raw prices yourself. "
"Returns a token-compact brief: patterns, support/resistance, regime "
"(trend/strength/volatility), interpreted RSI/EMA, and a one-line "
"summary — a few hundred tokens, not a raw candle dump."
)
args_schema: type[BaseModel] = MarketBriefInput
def _run(self, ticker: str, timeframe: str = "4h") -> str:
r = requests.post(
"https://patternfetch.com/v1/brief",
json={"ticker": ticker, "timeframe": timeframe},
headers={"Authorization": "Bearer " + PF_KEY},
timeout=30,
)
r.raise_for_status()
analysis = r.json()["analysis"]
return analysis["nl"] + "\n\n" + json.dumps(analysis, separators=(",", ":"))
# give it to any agent
# from crewai import Agent
# analyst = Agent(role="Market analyst", tools=[MarketBriefTool()], ...)
The tool returns the analysis block. The nl field is a ready-to-reason one-liner; the structured fields are there if the agent needs to cite a specific level or pattern. Here is the shape:
{
"patterns":[
{"name":"double_bottom","confidence":0.86}],
"levels":{
"support":[{"price":59820.4,"strength":1}],
"resistance":[{"price":63450.8,"strength":1}]},
"regime":{"trend":"up","strength":0.42,
"volPct":2.13},
"indicators":{
"rsi":{"v":58.3,"state":"neutral"},
"ema":{"v":61240.8,"state":"above_20_50"}},
"nl":"BTC/USDT: uptrend (moderate), +1.94%
last 4h, RSI 58.3 (neutral),
double_bottom (conf 0.86)."
}
// raw 200-candle OHLCV array
[
[1719000000,60125.4,60480.0,59890.1,
60310.7,1284.5],
[1719014400,60310.7,60900.2,60180.0,
60740.9,1530.2],
… 198 more rows …
]
// the model still has to derive the
// trend, levels and patterns itself —
// and do float math it gets wrong.
Approximate token sizes (estimates, not benchmarks): the brief above is on the order of a few hundred tokens; a raw 200-candle array is on the order of a few thousand. The brief is both smaller and richer — it already contains the structure the model would otherwise spend tokens trying (and often failing) to derive.
① No-signup demo — POST /v1/demo returns a real brief with no key, so you can test the tool wiring before you sign up. ② Free key with $0.05 starter credit (~5 briefs) from one call, no card — POST /v1/keys. ③ MCP one-click OAuth — add https://patternfetch.com/mcp in Claude.ai, Cursor or Smithery and click Authorize; a free-tier key is minted for you. After the free credit, $0.01 / brief.
# no signup — a real brief, no key
curl -X POST https://patternfetch.com/v1/demo \
-H "Content-Type: application/json" \
-d '{ "ticker": "BTC/USDT", "timeframe": "4h" }'
# free key with $0.05 starter credit (shown once)
curl -X POST https://patternfetch.com/v1/keys \
-H "Content-Type: application/json" \
-d '{ "email": "you@example.com" }'
# -> { "key": "pf_…" } → export PATTERNFETCH_KEY=pf_…
Full reference in the docs. Want one-click OAuth instead of handling keys? See the how-to for MCP setup.
Yes. patternfetch is just an HTTP endpoint, so the same tool works everywhere — OpenAI function-calling, Claude tool use, LangChain, CrewAI, or any framework. Describe one function that takes ticker and timeframe and POSTs to /v1/brief, then return the analysis block. There is also an MCP server at /mcp for one-click OAuth.
No. patternfetch is a plain JSON HTTP API — use requests or httpx. There is no pip install and no patternfetch module to import; just POST to https://patternfetch.com/v1/brief with a Bearer key.
Approximately a few hundred tokens, versus roughly a few thousand for a raw 200-candle OHLCV array. These are estimates, not exact benchmarks — and the brief also carries the patterns, levels, regime and one-line summary the agent can act on directly. See the token-cost breakdown.
No. It is impersonal market data and algorithmic signals for informational purposes only — not advice, not personalized, non-executing. See the disclaimer.