TradingAgent

TradingAgent

Enables natural-language paper trading with real-time market data, FinBERT sentiment analysis, conditional orders, and price alerts.

Category
Visit Server

README

TradingAgent

MCP-native conversational paper trading agent with FinBERT sentiment analysis.

"Buy 10 AAPL if it drops below $200 today" — type it, the agent handles the rest.

Table of Contents


Architecture

┌──────────────────────┐     ┌──────────────────────────────────────┐
│   CLI Agent (REPL)   │     │          Web UI (FastAPI)            │
│  claude-sonnet-4-6   │     │  Dark chat · WebSocket · marked.js   │
│  agentic loop        │     │  ngrok → shareable demo URL          │
└──────────┬───────────┘     └──────────────────┬───────────────────┘
           │  MCP (stdio)                        │  MCP (stdio, per session)
           └──────────────────┬──────────────────┘
                              │
           ┌──────────────────▼──────────────────┐
           │         FastMCP Server              │
           │     20 tools · 4 modules            │
           └────┬──────────┬──────────┬──────────┘
                │          │          │          │
          trading     market-data  sentiment  watchlist
           8 tools      5 tools    FinBERT    4 tools
                │          │          │          │
                └──────────┴──────────┴──────────┘
                                │
                  ┌─────────────▼──────────────┐
                  │   5-Layer Guardrail         │
                  │  input·llm·tool·exec·output │
                  └─────────────┬──────────────┘
                                │
                  ┌─────────────▼──────────────┐
                  │     Alpaca Paper API        │
                  │  real quotes · fake money   │
                  └─────────────┬──────────────┘
                                │
                  ┌─────────────▼──────────────┐
                  │      Alert Daemon           │
                  │  polls prices every 30s     │
                  │  fires conditional orders   │
                  └────────────────────────────┘

Quick Start

No Alpaca account needed for mock mode.

1 — Install

# Clone and enter project
git clone https://github.com/cactus001/TRADE-AGENT.git
cd TRADE-AGENT

# Install dependencies (Apple Silicon — use Homebrew Python)
uv sync --python /opt/homebrew/bin/python3.12

# Install dev dependencies for tests
uv sync --extra dev

2 — Configure

cp .env.example .env

Open .env and fill in:

ANTHROPIC_API_KEY=sk-ant-...          # required — get from console.anthropic.com
ALPACA_API_KEY=                        # optional — paper trading keys from alpaca.markets
ALPACA_SECRET_KEY=                     # optional — leave blank to use --mock mode

Note: Mock mode works without any Alpaca keys and runs FinBERT on real fake news headlines.


Running the Agent

Option A — CLI REPL (terminal chat)

# Mock mode (no Alpaca keys needed)
uv run python -m agent.cli_agent --mock

# Live paper trading (requires Alpaca keys in .env)
uv run python -m agent.cli_agent

Type natural language commands. Press Ctrl+C to exit — the session transcript saves automatically to transcripts/.

Option B — Web UI (shareable chat interface)

# Mock mode
uv run python -m src.webapp --mock

# Live paper trading
uv run python -m src.webapp

Open http://localhost:8000 in your browser — you'll see a dark-themed chat UI with:

  • Live tool call chips showing which MCP tools are running
  • Animated thinking indicator during inference
  • Markdown tables for portfolio/order data
  • PAPER TRADING — NO REAL MONEY watermark on all order confirmations

Option C — Share via ngrok (live demo from anywhere)

Use this for interviews, demos, or sharing with anyone over the internet.

Step 1 — Install ngrok

brew install ngrok

Step 2 — Authenticate

  1. Go to dashboard.ngrok.com/get-started/your-authtoken
  2. Copy your personal authtoken
  3. Run:
ngrok config add-authtoken YOUR_REAL_TOKEN_HERE

Step 3 — Start the web server

uv run python -m src.webapp --mock

Step 4 — Open the tunnel (in a second terminal)

ngrok http 8000

ngrok will print a public URL like:

Forwarding  https://oboe-routing-difficult.ngrok-free.app → http://localhost:8000

Share that URL — anyone with the link can open the chat interface and interact with TradingAgent in real time from any browser, no setup needed.

Option D — Docker (Redis + Web UI)

Docker Compose spins up two services:

  • redis — redis:7-alpine, persists to a named volume, health-checked before the agent starts
  • trading-agent — builds from Dockerfile, runs the web UI on port 8000, connects to Redis automatically
# Copy env file and add your Anthropic key
cp .env.example .env
# edit .env — add ANTHROPIC_API_KEY (REDIS_URL is set automatically by compose)

# Build and start both services
docker-compose up --build

# Or run detached
docker-compose up --build -d

Open http://localhost:8000 — the chat UI is live.

# Tail logs
docker-compose logs -f trading-agent

# Stop everything
docker-compose down

# Stop and wipe all volumes (resets state + Redis cache)
docker-compose down -v

Run the CLI agent instead of web UI:

docker-compose run --rm trading-agent uv run python -m agent.cli_agent --mock

Example Conversation

You: what's my portfolio looking like

Agent: Portfolio — $101,432.20 total (+1.4% today)
  TSLA  15 shares  $248.20  +$190.50  (+5.4%)
  NVDA   5 shares  $134.50  -$43.00   (-6.0%)
  Cash  $94,890.50 available

You: what's the sentiment on NVDA right now

Agent: NVDA Sentiment (last 4h): BEARISH — score -0.41
  Top drivers:
  • "Analyst cuts NVDA target to $125"  (negative, -0.81)
  • "Nvidia faces rising competition"    (negative, -0.62)
  Recommendation: Consider waiting for stabilisation before adding.

You: buy 10 AAPL if it drops below $200 today

Agent: Day Limit Buy Preview  [PAPER TRADING — NO REAL MONEY]
  10 shares AAPL  ·  Limit @ $200.00
  AAPL currently: $212.95
  Expires: 4:00 PM ET today  ·  Max cost: $2,000.00
  Confirm? (yes/no)

You: yes

Agent: ✅ Order placed (ID: abc-12345)
  Limit buy active — AAPL will be purchased automatically if price hits $200.
  [PAPER TRADING — NO REAL MONEY]

You: alert me when TSLA drops below 240

Agent: ✅ Alert set — will notify when TSLA < $240.00
  Current price: $248.20  (monitoring every 30s)

Tools

20 tools across 4 modules:

Module Tools
trading get_account, get_positions, get_orders, place_order, cancel_order, cancel_all_orders, get_portfolio_history, get_asset_info
market-data get_quote, get_bars, get_news, get_market_status, search_symbol
sentiment get_sentiment, get_market_mood, explain_sentiment
watchlist set_price_alert, get_active_alerts, cancel_alert, get_trade_history

Safety

A 5-layer guardrail pipeline runs on every order:

Layer What it catches
Input guard Prompt injection patterns in user messages
LLM guard Injected instructions hidden in news headlines; hardens system prompt
Tool guard Invalid ticker formats, negative qty, missing required prices, sanity limits
Execution guard Single order > 20% portfolio, daily loss > 5%, > 10 orders/hr, wash trades (< 5 min), circuit breaker (SPY down > 5%)
Output guard Broker rejections, post-trade concentration warnings

place_order enforces a mandatory two-step flow: confirm=False (preview) must be called before confirm=True (execute). No order reaches the broker without an explicit user confirmation in the conversation.


FinBERT as a Production Service

src/models/finbert.py promotes FinBERT (ProsusAI/finbert) from a standalone script to a production-grade callable MCP service:

Pattern Implementation
Singleton Module-level _instance, one model loaded per process
Lazy loading Model not loaded until first analyze() call
Double-checked locking threading.Lock with if self._loaded checked inside the lock
Device auto-detection CUDA → Apple MPS → CPU, no environment config needed
Batch inference Chunks news lists into BATCH_SIZE=16 to avoid OOM
Normalised score Returns pos_prob − neg_prob in [-1.0, +1.0]
Redis cache sha256(headline) key, 1h TTL — identical headlines never hit GPU twice
Partial-hit pattern Per-batch cache lookup; only misses go to FinBERT, hits served in <1ms
Graceful degradation Redis unavailable → cache is a no-op, inference runs normally

On Apple Silicon, inference runs on the MPS GPU (confirmed: device: mps). With Redis warm, repeated get_sentiment calls on the same news cycle return instantly.


Project Structure

TRADE-AGENT/
├── agent/
│   └── cli_agent.py            # REPL — manual agentic loop, auto-saves transcripts
├── src/
│   ├── server.py                # FastMCP entry point — registers all 4 tool modules
│   ├── webapp.py                # FastAPI + WebSocket web interface
│   ├── config.py                # Pydantic settings — env vars with defaults
│   ├── state_manager.py         # Persistent state (~/.trading-agent/state.json)
│   ├── alert_daemon.py          # Background thread — polls prices every 30s
│   ├── models/
│   │   └── finbert.py           # FinBERT singleton service (production ML pattern)
│   ├── cache/
│   │   └── redis_cache.py       # Redis sentiment cache — partial-hit, 1h TTL, graceful degradation
│   ├── clients/
│   │   └── alpaca_client.py     # Thin wrapper around alpaca-py SDK
│   ├── guardrails/
│   │   ├── input_guard.py       # Regex injection pattern detection
│   │   ├── llm_guard.py         # News sanitisation + system prompt hardening
│   │   ├── tool_guard.py        # Symbol/qty/price validation
│   │   ├── execution_guard.py   # Size, loss, velocity, wash-trade, circuit-breaker
│   │   ├── output_guard.py      # Broker rejection + concentration check
│   │   └── guard_registry.py    # Wires all 5 layers into one object
│   ├── tools/
│   │   ├── trading.py           # 8 trading tools (place_order confirm gate)
│   │   ├── market_data.py       # 5 market data tools
│   │   ├── sentiment.py         # 3 FinBERT sentiment tools
│   │   └── watchlist.py         # 4 alert/history tools
│   └── static/
│       └── index.html           # Dark chat UI (WebSocket, marked.js, tool chips)
├── mock/
│   └── mock_provider.py         # MockAlpacaClient — full demo without API keys
├── tests/
│   ├── test_guardrails.py       # 15 tests across all 5 guardrail layers
│   └── test_sentiment.py        # 7 tests — singleton, batch, device detection
├── transcripts/                 # Auto-saved session logs (git-ignored)
├── pyproject.toml
├── docker-compose.yml
├── Dockerfile
└── .env.example

Tests

uv run pytest tests/ -v
# 22 passed

Environment Variables

Variable Required Default Description
ANTHROPIC_API_KEY Yes — Claude API key — console.anthropic.com
ALPACA_API_KEY No — Alpaca paper trading key — alpaca.markets
ALPACA_SECRET_KEY No — Alpaca paper trading secret
REDIS_URL No redis://localhost:6379 Redis connection string — auto-set by docker-compose
MAX_ORDER_PCT No 0.20 Max single order as fraction of portfolio
DAILY_LOSS_LIMIT No -0.05 Halt buys if day P&L falls below this
VELOCITY_LIMIT No 10 Max orders per hour

State Persistence

The agent persists alerts, trade history, and the velocity/wash-trade counters to:

~/.trading-agent/state.json

This file lives outside the project directory and is never committed. Delete it to reset all state.


Tech Stack

Component Technology
Agent SDK Anthropic Python SDK (claude-sonnet-4-6)
Tool protocol MCP (Model Context Protocol) via FastMCP
Broker API Alpaca Paper Trading (alpaca-py)
Sentiment model ProsusAI/FinBERT (HuggingFace Transformers)
ML runtime PyTorch 2.x — MPS / CUDA / CPU auto
Inference cache Redis 7 — sha256-keyed, 1h TTL, graceful degradation
Web server FastAPI + Uvicorn + WebSocket
Frontend Vanilla JS, marked.js, CSS custom properties
Containers Docker + docker-compose (two-service: redis + trading-agent)
Tunnel ngrok (free tier)
Package manager uv
Tests pytest + pytest-asyncio

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured