A cautious, rules-driven market agent that:
- Scans macro headlines (Mediastack),
- Maps news → candidate tickers (Finnhub),
- Applies conservative trade rules,
- Optionally places paper orders (Alpaca).
The agent prefers not to trade unless conviction is high. Skipping is always allowed.
- First inspects the paper trading account and market clock (Alpaca).
- Scans macro news using a prioritized keyword list (e.g., “FOMC”, “CPI”, “beats estimates”, “merger”, “FDA approval”, etc.).
- Builds a candidate ticker list from headlines and proxy ETFs (e.g., XLF, TLT, NVDA, XLE).
- For each ticker:
- Pulls quotes, company news, and earnings context (Finnhub).
- Optionally checks intraday bars (Alpaca Market Data v2).
- Applies risk & sizing guardrails and, only if warranted, submits one paper order (Alpaca).
- This agent (you’re reading its README) is a Python module that uses:
google-adk(LlmAgent) for reasoning & tool orchestration.MCPToolsetto call your MCP server over HTTP.
- MCP server (separate service) provides tools:
- Mediastack:
news_headlines,news_get - Finnhub:
symbol_search,quote,company_news,earnings_* - Alpaca (paper):
paper_account,paper_clock,paper_positions,paper_open_orders,paper_submit_order,paper_cancel_order,paper_quote,paper_bars
- Mediastack:
This README is for the agent, not the MCP server. Ensure your MCP server is running and reachable at
AGENT_MCP_URL.
- Python: 3.10+
- Packages (add to your
requirements.txt):google-adklitellmpython-dotenv
Example requirements.txt:
google-adk
litellm
python-dotenv
Create a .env in the agent’s project root:
# Model (via LiteLLM routing)
MARKET_AGENT_MODEL=openai/gpt-4o
OPENAI_API_KEY=sk-...
# MCP endpoint (HTTP Streamable)
# If you’re tunneling to a remote service: ssh -N -L 8181:127.0.0.1:8000 ubuntu@<EC2_IP>
# Then set:
AGENT_MCP_URL=http://localhost:8181/mcp
# Optional: if your environment needs to inject extra import roots for the agent
MARKET_MCP_PYTHONPATH=/opt/market-mcp
Heads-up: If you previously used
AGENT_MCPP_URL(with two “P”s), correct it toAGENT_MCP_URL. The agent code readsAGENT_MCP_URL.
-
Install deps
python -m venv .venv . .venv/bin/activate pip install -r requirements.txt
-
Confirm MCP server is reachable
curl -sS -i -X POST http://localhost:8181/mcp -H 'content-type: application/json' -d '{}'
You should receive a 200/202 response (GET to /mcp often returns 400; that’s normal for the streaming endpoint).
-
Run the agent from Python
from agent import root_agent # the file containing your agent code snippet prompt = "market digest" result = root_agent.run(prompt) if hasattr(root_agent, "run") else root_agent.chat(prompt) if hasattr(root_agent, "chat") else root_agent(prompt) print(result)
python run_agent.py
Different
google-adkversions expose different call methods (run,chat, or__call__). The example above tries them in a safe order.
- First action (always):
paper_account()→ checkequity,buying_power, flags.paper_clock()→ only consider trades ifis_open(or within ~10 min of open).
- Macro scan (strictly sequential; never batch):
- For each prioritized term, call
news_headlines(keywords=TERM, limit=5). - Deduplicate by URL/title; cap to ~20 headlines total.
- If headlines look important but vague, fetch details via
news_getfor that term. - Fallback:
news_headlines("markets", 5)if signal is thin.
- For each prioritized term, call
- Map news → tickers:
- Extract company/brand names; resolve ambiguity via
symbol_search. - Add thoughtful proxy tickers (e.g., rates → XLF/KRE/ITB/TLT; chips/AI → NVDA/AMD/AVGO/TSM/ASML; oil/tensions → XLE/XOM/CVX).
- Keep ≤ 12 candidates; prioritize recent/high-signal.
- Extract company/brand names; resolve ambiguity via
- Per-ticker:
quote(symbol);company_news(symbol, 2d); earnings viaearnings_expectationsorearnings_results.- If needed, intraday context with
paper_bars(symbol, "1Min", 60).
- Trade decision (paper only):
- Require both: (A) strong catalyst and (B) confirming price action or attractive R/R.
- If uncertain → do not trade.
- Risk & sizing:
- Max 2 new positions per day.
- Skip if open orders or oversized exposure exist (
paper_open_orders,paper_positions). - Default size: min(5% of buying_power, $2,000), using notional when possible.
- Prefer BRACKET for longs: take_profit ≈ +4%, stop_loss ≈ -2%.
- Order placement (if any):
- One order only,
type="market"for liquid names,time_in_force="DAY". client_order_id="md-<SYMBOL>-<YYYYMMDD-HHMM>".- Confirm via
paper_open_orders(limit=20).
- One order only,
- Output:
- Executive summary, Trade decisions, Ticker drill-down, US macro pulse.
- Concise, factual; inline sources/time when available.
- Constraints:
- Never batch across tickers/endpoints; max ~25 tool calls.
- Note errors briefly and continue.
- If closed or low conviction → no trades.
The agent will only use these MCP tools:
- Finnhub:
symbol_search,quote,company_news,earnings_expectations,earnings_calendar,earnings_results - Mediastack:
news_headlines,news_get - Alpaca (paper):
paper_account,paper_clock,paper_positions,paper_open_orders,paper_submit_order,paper_cancel_order,paper_quote,paper_bars - Misc:
ping
Ensure your MCP server actually exposes these (use the MCP Inspector to verify
ListTools).
- The agent is paper-only by design.
- It will not trade if the market is closed or conviction is low.
- Caps new positions and sizes; prefers bracket risk controls.
- You may still want to add account-level safeguards (e.g., permissions or MCP-side validation).
- “market digest”
- “market digest — focus on chips and CPI”
- “market digest; skip trades today, just research” (you can customize the instruction block if you want stricter behavior)