Skip to main content
Glama
gzcity

AI Quant Trading MCP Server

by gzcity

AI量化实战 - AI实时选股平台开发

基于MCP(Model Context Protocol)协议,构建AI驱动的实时选股服务平台

📋 目录


Related MCP server: TdxQuant MCP Server

1. 项目概述

本项目基于 MCP(Model Context Protocol) 协议,构建AI驱动的实时选股服务平台。通过MCP服务,AI大模型可以获得:

  • 📊 实时行情数据 - 股票报价、K线数据、市场概览

  • 📈 技术指标计算 - SMA、EMA、RSI、MACD、布林带等

  • 🔔 实时订阅推送 - 股票价格变动实时通知

  • 🤖 AI决策支持 - 为AI模型提供量化分析能力

架构图

┌─────────────────────────────────────────────────────────────┐
│                      AI 大模型(Trae)                        │
└─────────────────────────────────────────────────────────────┘
                              │
                              │ MCP Protocol (JSON-RPC)
                              │
        ┌─────────────────────┼─────────────────────┐
        │                     │                     │
        ▼                     ▼                     ▼
┌───────────────┐   ┌───────────────┐   ┌───────────────┐
│  stdio 模式   │   │  HTTP/SSE 模式 │  │   策略服务     │
│  (本地开发)   │   │  (生产环境)    │  │  (指标计算)   │
└───────────────┘   └───────────────┘   └───────────────┘
        │                     │                     │
        └─────────────────────┼─────────────────────┘
                              │
                              ▼
                    ┌───────────────────┐
                    │   行情数据源       │
                    │  (模拟/真实API)   │
                    └───────────────────┘

2. MCP协议简介

MCP(Model Context Protocol)是一种允许AI模型与外部工具和服务交互的协议。在量化交易领域,MCP服务可以为AI大模型提供实时行情数据、技术指标计算、风险评估等能力。

MCP服务模式对比

模式

通信方式

适用场景

特点

stdio

标准输入输出

本地开发/测试

无需网络配置,快速启动

HTTP/SSE

HTTP + Server-Sent Events

生产环境/团队协作

支持远程访问,可扩展

通信协议

MCP基于 JSON-RPC 2.0 协议:

  • 请求:通过标准输入发送JSON-RPC请求

  • 响应:通过标准输出返回JSON-RPC响应

  • 通知:支持异步推送(如实时行情更新)


3. 本地Python MCP服务(stdio模式)

本地Python MCP服务是最简单的MCP实现方式,通过标准输入输出(stdio)与AI进行通信。

3.1 核心原理

┌──────────────┐     stdin      ┌──────────────┐
│              │ ──────────────► │              │
│   AI 模型    │                 │  MCP Server  │
│              │ ◄────────────── │              │
└──────────────┘     stdout     └──────────────┘

3.2 完整实现代码

# mcp_server_stdio.py
import asyncio
import json
import sys
import logging
from typing import Dict, List, Any, Optional

logging.basicConfig(level=logging.WARNING, stream=sys.stderr)
logger = logging.getLogger(__name__)

PROTOCOL_VERSION = "2025-11-25"


class MCPServer:
    """本地MCP服务 - stdio模式"""

    def __init__(self):
        self.tools = {
            "get_stock_quote": self.get_stock_quote,
            "calculate_indicator": self.calculate_indicator,
            "get_market_summary": self.get_market_summary,
            "get_kline_data": self.get_kline_data,
            "subscribe_stock": self.subscribe_stock
        }
        self.subscriptions: Dict[str, List[str]] = {}

    # ==================== 工具实现 ====================

    async def get_stock_quote(self, code: str) -> dict:
        """获取股票实时行情数据"""
        mock_data = {
            "600000": {
                "code": "600000",
                "name": "浦发银行",
                "price": 8.52,
                "open": 8.45,
                "high": 8.60,
                "low": 8.40,
                "volume": 1256000,
                "change_pct": 0.83
            },
            "000001": {
                "code": "000001",
                "name": "平安银行",
                "price": 12.35,
                "open": 12.20,
                "high": 12.50,
                "low": 12.15,
                "volume": 2345000,
                "change_pct": 1.23
            },
        }
        return mock_data.get(code, {"error": f"股票代码 {code} 不存在"})

    async def calculate_indicator(self, data: list, indicator: str, period: int = 14) -> dict:
        """计算技术指标"""
        if indicator.lower() == "sma":
            return self._calc_sma(data, period)
        elif indicator.lower() == "ema":
            return self._calc_ema(data, period)
        elif indicator.lower() == "rsi":
            return self._calc_rsi(data, period)
        elif indicator.lower() == "macd":
            return self._calc_macd(data)
        elif indicator.lower() == "bollinger":
            return self._calc_bollinger(data, period)
        else:
            return {"error": f"不支持的指标: {indicator}"}

    async def get_market_summary(self) -> dict:
        """获取市场概览"""
        return {
            "total_stocks": 5234,
            "up_count": 2345,
            "down_count": 2156,
            "flat_count": 733,
            "market_index": {"name": "上证指数", "value": 3256.78, "change_pct": 0.45}
        }

    async def get_kline_data(self, code: str, period: str = "1d", count: int = 30) -> dict:
        """获取K线数据"""
        # 模拟K线数据
        kline = []
        base_price = 10.0
        for i in range(count):
            kline.append({
                "date": f"2026-07-{i+1:02d}",
                "open": round(base_price + i * 0.1, 2),
                "high": round(base_price + i * 0.1 + 0.05, 2),
                "low": round(base_price + i * 0.1 - 0.05, 2),
                "close": round(base_price + i * 0.1 + 0.02, 2),
                "volume": 1000000 + i * 50000
            })
        return {"code": code, "period": period, "data": kline}

    async def subscribe_stock(self, code: str, action: str = "subscribe") -> dict:
        """订阅/取消订阅股票"""
        if action == "subscribe":
            if code not in self.subscriptions:
                self.subscriptions[code] = []
            return {"status": "subscribed", "code": code}
        else:
            self.subscriptions.pop(code, None)
            return {"status": "unsubscribed", "code": code}

    # ==================== 指标计算 ====================

    def _calc_sma(self, data: list, period: int) -> dict:
        """简单移动平均"""
        result = []
        for i in range(period - 1, len(data)):
            sma = sum(data[i - period + 1:i + 1]) / period
            result.append(round(sma, 4))
        return {"indicator": "SMA", "period": period, "result": result}

    def _calc_ema(self, data: list, period: int) -> dict:
        """指数移动平均"""
        multiplier = 2 / (period + 1)
        ema = [data[0]]
        for i in range(1, len(data)):
            ema.append(round((data[i] - ema[-1]) * multiplier + ema[-1], 4))
        return {"indicator": "EMA", "period": period, "result": ema}

    def _calc_rsi(self, data: list, period: int) -> dict:
        """相对强弱指标"""
        gains = []
        losses = []
        for i in range(1, len(data)):
            change = data[i] - data[i - 1]
            gains.append(max(0, change))
            losses.append(max(0, -change))

        avg_gain = sum(gains[:period]) / period
        avg_loss = sum(losses[:period]) / period

        rsi_values = []
        for i in range(period, len(gains)):
            avg_gain = (avg_gain * (period - 1) + gains[i]) / period
            avg_loss = (avg_loss * (period - 1) + losses[i]) / period
            rs = avg_gain / avg_loss if avg_loss != 0 else 100
            rsi = 100 - (100 / (1 + rs))
            rsi_values.append(round(rsi, 2))

        return {"indicator": "RSI", "period": period, "result": rsi_values}

    def _calc_macd(self, data: list) -> dict:
        """MACD指标"""
        ema12 = self._calc_ema(data, 12)["result"]
        ema26 = self._calc_ema(data, 26)["result"]

        # 对齐长度
        min_len = min(len(ema12), len(ema26))
        dif = [round(ema12[i] - ema26[i], 4) for i in range(min_len)]
        dea = self._calc_ema(dif, 9)["result"]

        macd = [round((dif[i] - dea[i]) * 2, 4) for i in range(min(len(dif), len(dea)))]

        return {"indicator": "MACD", "DIF": dif, "DEA": dea, "MACD": macd}

    def _calc_bollinger(self, data: list, period: int) -> dict:
        """布林带"""
        mid = self._calc_sma(data, period)["result"]
        upper = []
        lower = []

        for i in range(period - 1, len(data)):
            window = data[i - period + 1:i + 1]
            mean = sum(window) / period
            std = (sum((x - mean) ** 2 for x in window) / period) ** 0.5
            upper.append(round(mean + 2 * std, 4))
            lower.append(round(mean - 2 * std, 4))

        return {"indicator": "Bollinger", "period": period, "mid": mid, "upper": upper, "lower": lower}

    # ==================== MCP协议处理 ====================

    def get_tool_descriptions(self) -> dict:
        """获取工具描述(供AI模型发现)"""
        return {
            "tools": [
                {
                    "name": "get_stock_quote",
                    "description": "获取股票实时行情数据,包括价格、涨跌幅、成交量等",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "code": {"type": "string", "description": "股票代码,如 600000"}
                        },
                        "required": ["code"]
                    }
                },
                {
                    "name": "calculate_indicator",
                    "description": "计算技术指标:SMA、EMA、RSI、MACD、Bollinger",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "data": {"type": "array", "items": {"type": "number"}, "description": "价格序列"},
                            "indicator": {"type": "string", "description": "指标名称:sma/ema/rsi/macd/bollinger"},
                            "period": {"type": "integer", "description": "周期,默认14"}
                        },
                        "required": ["data", "indicator"]
                    }
                },
                {
                    "name": "get_market_summary",
                    "description": "获取市场整体概览,包括涨跌数量、指数等",
                    "inputSchema": {"type": "object", "properties": {}}
                },
                {
                    "name": "get_kline_data",
                    "description": "获取K线数据",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "code": {"type": "string", "description": "股票代码"},
                            "period": {"type": "string", "description": "周期:1d/1w/1m"},
                            "count": {"type": "integer", "description": "数据条数"}
                        },
                        "required": ["code"]
                    }
                },
                {
                    "name": "subscribe_stock",
                    "description": "订阅或取消订阅股票实时行情",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "code": {"type": "string", "description": "股票代码"},
                            "action": {"type": "string", "description": "操作:subscribe/unsubscribe"}
                        },
                        "required": ["code"]
                    }
                }
            ]
        }

    async def handle_request(self, request: dict) -> dict:
        """处理MCP请求"""
        method = request.get("method", "")
        params = request.get("params", {})

        if method == "initialize":
            return {
                "protocolVersion": PROTOCOL_VERSION,
                "capabilities": {"tools": {}},
                "serverInfo": {"name": "stock-mcp-server", "version": "1.0.0"}
            }
        elif method == "tools/list":
            return self.get_tool_descriptions()
        elif method == "tools/call":
            tool_name = params.get("name", "")
            arguments = params.get("arguments", {})
            if tool_name in self.tools:
                result = await self.tools[tool_name](**arguments)
                return {"content": [{"type": "text", "text": json.dumps(result, ensure_ascii=False)}]}
            else:
                return {"error": f"未知工具: {tool_name}"}
        else:
            return {"error": f"未知方法: {method}"}

    async def run(self):
        """运行MCP服务(stdio模式)"""
        print("MCP Stock Server started (stdio mode)", file=sys.stderr)
        loop = asyncio.get_event_loop()
        while True:
            try:
                line = await loop.run_in_executor(None, sys.stdin.readline)
                if not line:
                    break
                request = json.loads(line.strip())
                response = await self.handle_request(request)
                print(json.dumps(response, ensure_ascii=False), flush=True)
            except Exception as e:
                logger.error(f"Error: {e}")


if __name__ == "__main__":
    server = MCPServer()
    asyncio.run(server.run())

3.3 配置文件

// .trae/mcp.json
{
  "mcpServers": {
    "stock-mcp": {
      "command": "python",
      "args": ["mcp_server_stdio.py"]
    }
  }
}

4. 远程HTTP/SSE MCP服务

远程MCP服务通过HTTP/SSE协议通信,适合生产环境和团队协作。

4.1 架构设计

┌──────────────┐     HTTP      ┌──────────────┐
│              │ ─────────────► │              │
│   AI 模型    │                │  MCP Server  │
│              │ ◄───────────── │   (HTTP/SSE) │
└──────────────┘     SSE       └──────────────┘
                                    │
                                    ▼
                            ┌──────────────┐
                            │  行情数据API  │
                            └──────────────┘

4.2 完整实现代码

# mcp_server_http.py
import asyncio
import json
import logging
from aiohttp import web

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

PROTOCOL_VERSION = "2025-11-25"


class MCPHTTPServer:
    """远程MCP服务 - HTTP/SSE模式"""

    def __init__(self, host: str = "0.0.0.0", port: int = 8080):
        self.host = host
        self.port = port
        self.app = web.Application()
        self.sessions = {}
        self._setup_routes()

    def _setup_routes(self):
        self.app.router.add_post("/mcp", self.handle_mcp_post)
        self.app.router.add_get("/mcp/sse", self.handle_sse)
        self.app.router.add_get("/health", self.health_check)

    async def handle_mcp_post(self, request: web.Request) -> web.Response:
        """处理MCP POST请求"""
        try:
            body = await request.json()
            method = body.get("method", "")
            params = body.get("params", {})

            if method == "initialize":
                response = {
                    "protocolVersion": PROTOCOL_VERSION,
                    "capabilities": {"tools": {}},
                    "serverInfo": {"name": "stock-mcp-http", "version": "1.0.0"}
                }
            elif method == "tools/list":
                response = self._get_tools()
            elif method == "tools/call":
                response = await self._call_tool(params)
            else:
                response = {"error": f"未知方法: {method}"}

            return web.json_response(response)
        except Exception as e:
            return web.json_response({"error": str(e)}, status=500)

    async def handle_sse(self, request: web.Request) -> web.Response:
        """处理SSE长连接"""
        response = web.StreamResponse()
        response.headers["Content-Type"] = "text/event-stream"
        response.headers["Cache-Control"] = "no-cache"
        response.headers["Connection"] = "keep-alive"
        await response.prepare(request)

        session_id = request.query.get("session_id", "default")
        self.sessions[session_id] = response

        try:
            while True:
                await asyncio.sleep(30)
                await response.write(b": ping\n\n")
        except (ConnectionResetError, asyncio.CancelledError):
            pass
        finally:
            self.sessions.pop(session_id, None)

        return response

    async def health_check(self, request: web.Request) -> web.Response:
        """健康检查端点"""
        return web.json_response({"status": "ok", "service": "stock-mcp-http"})

    def _get_tools(self) -> dict:
        """获取工具列表"""
        return {
            "tools": [
                {
                    "name": "get_stock_quote",
                    "description": "获取股票实时行情数据",
                    "inputSchema": {
                        "type": "object",
                        "properties": {"code": {"type": "string"}},
                        "required": ["code"]
                    }
                },
                {
                    "name": "calculate_indicator",
                    "description": "计算技术指标",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "data": {"type": "array", "items": {"type": "number"}},
                            "indicator": {"type": "string"},
                            "period": {"type": "integer"}
                        },
                        "required": ["data", "indicator"]
                    }
                },
                {
                    "name": "get_market_summary",
                    "description": "获取市场概览",
                    "inputSchema": {"type": "object", "properties": {}}
                }
            ]
        }

    async def _call_tool(self, params: dict) -> dict:
        """调用工具"""
        tool_name = params.get("name", "")
        args = params.get("arguments", {})

        if tool_name == "get_stock_quote":
            result = {"code": args["code"], "price": 10.5, "name": "测试股票"}
        elif tool_name == "calculate_indicator":
            result = {"indicator": args.get("indicator"), "result": [1, 2, 3]}
        elif tool_name == "get_market_summary":
            result = {"total": 5000, "up": 2500, "down": 2500}
        else:
            result = {"error": f"未知工具: {tool_name}"}

        return {"content": [{"type": "text", "text": json.dumps(result, ensure_ascii=False)}]}

    async def broadcast(self, event: str, data: dict):
        """向所有SSE客户端广播消息"""
        message = f"event: {event}\ndata: {json.dumps(data, ensure_ascii=False)}\n\n"
        for session_id, response in list(self.sessions.items()):
            try:
                await response.write(message.encode())
            except Exception:
                self.sessions.pop(session_id, None)

    def run(self):
        """启动服务"""
        web.run_app(self.app, host=self.host, port=self.port)


if __name__ == "__main__":
    server = MCPHTTPServer(port=8080)
    server.run()

4.3 配置文件

// .trae/mcp.json (远程模式)
{
  "mcpServers": {
    "stock-mcp-remote": {
      "url": "http://localhost:8080/mcp",
      "transport": "sse"
    }
  }
}

5. MCP策略服务 - 指标与因子算法

策略服务提供量化分析所需的各类指标和因子计算。

5.1 核心指标实现

# indicators.py
import numpy as np
from typing import List, Dict, Optional


class TechnicalIndicators:
    """技术指标计算类"""

    @staticmethod
    def sma(data: List[float], period: int) -> List[float]:
        """简单移动平均 (Simple Moving Average)"""
        result = []
        for i in range(period - 1, len(data)):
            result.append(round(sum(data[i - period + 1:i + 1]) / period, 4))
        return result

    @staticmethod
    def ema(data: List[float], period: int) -> List[float]:
        """指数移动平均 (Exponential Moving Average)"""
        multiplier = 2 / (period + 1)
        ema_values = [data[0]]
        for i in range(1, len(data)):
            val = (data[i] - ema_values[-1]) * multiplier + ema_values[-1]
            ema_values.append(round(val, 4))
        return ema_values

    @staticmethod
    def rsi(data: List[float], period: int = 14) -> List[float]:
        """相对强弱指标 (Relative Strength Index)"""
        gains, losses = [], []
        for i in range(1, len(data)):
            change = data[i] - data[i - 1]
            gains.append(max(0, change))
            losses.append(max(0, -change))

        avg_gain = sum(gains[:period]) / period
        avg_loss = sum(losses[:period]) / period

        rsi_values = []
        for i in range(period, len(gains)):
            avg_gain = (avg_gain * (period - 1) + gains[i]) / period
            avg_loss = (avg_loss * (period - 1) + losses[i]) / period
            rs = avg_gain / avg_loss if avg_loss != 0 else 100
            rsi_values.append(round(100 - (100 / (1 + rs)), 2))

        return rsi_values

    @staticmethod
    def macd(data: List[float], fast: int = 12, slow: int = 26, signal: int = 9) -> Dict:
        """MACD指标"""
        ema_fast = TechnicalIndicators.ema(data, fast)
        ema_slow = TechnicalIndicators.ema(data, slow)

        min_len = min(len(ema_fast), len(ema_slow))
        dif = [round(ema_fast[i] - ema_slow[i], 4) for i in range(min_len)]
        dea = TechnicalIndicators.ema(dif, signal)
        macd_hist = [round((dif[i] - dea[i]) * 2, 4) for i in range(min(len(dif), len(dea)))]

        return {"DIF": dif, "DEA": dea, "MACD": macd_hist}

    @staticmethod
    def bollinger_bands(data: List[float], period: int = 20, std_dev: float = 2.0) -> Dict:
        """布林带 (Bollinger Bands)"""
        mid = TechnicalIndicators.sma(data, period)
        upper, lower = [], []

        for i in range(period - 1, len(data)):
            window = data[i - period + 1:i + 1]
            mean = sum(window) / period
            std = (sum((x - mean) ** 2 for x in window) / period) ** 0.5
            upper.append(round(mean + std_dev * std, 4))
            lower.append(round(mean - std_dev * std, 4))

        return {"mid": mid, "upper": upper, "lower": lower}

    @staticmethod
    def kdj(data: List[Dict], period: int = 9) -> Dict:
        """KDJ随机指标"""
        k_values, d_values, j_values = [], [], []

        for i in range(period - 1, len(data)):
            window = data[i - period + 1:i + 1]
            high = max(d["high"] for d in window)
            low = min(d["low"] for d in window)
            close = data[i]["close"]

            rsv = (close - low) / (high - low) * 100 if high != low else 50
            k = 2 / 3 * (k_values[-1] if k_values else 50) + 1 / 3 * rsv
            d = 2 / 3 * (d_values[-1] if d_values else 50) + 1 / 3 * k
            j = 3 * k - 2 * d

            k_values.append(round(k, 2))
            d_values.append(round(d, 2))
            j_values.append(round(j, 2))

        return {"K": k_values, "D": d_values, "J": j_values}

5.2 因子计算

# factors.py
from typing import List, Dict
from indicators import TechnicalIndicators


class AlphaFactors:
    """Alpha因子计算"""

    @staticmethod
    def momentum_factor(prices: List[float], period: int = 20) -> float:
        """动量因子"""
        if len(prices) < period:
            return 0.0
        return round(prices[-1] / prices[-period] - 1, 4)

    @staticmethod
    def reversal_factor(prices: List[float], period: int = 5) -> float:
        """反转因子"""
        if len(prices) < period:
            return 0.0
        return round(-(prices[-1] / prices[-period] - 1), 4)

    @staticmethod
    def volatility_factor(prices: List[float], period: int = 20) -> float:
        """波动率因子"""
        if len(prices) < period:
            return 0.0
        recent = prices[-period:]
        mean = sum(recent) / len(recent)
        variance = sum((x - mean) ** 2 for x in recent) / len(recent)
        return round(variance ** 0.5 / mean, 4)

    @staticmethod
    def volume_factor(volumes: List[float], period: int = 20) -> float:
        """成交量因子"""
        if len(volumes) < period:
            return 0.0
        avg_vol = sum(volumes[-period:]) / period
        return round(volumes[-1] / avg_vol if avg_vol > 0 else 0, 4)

    @staticmethod
    def rsi_factor(prices: List[float], period: int = 14) -> float:
        """RSI因子"""
        rsi_values = TechnicalIndicators.rsi(prices, period)
        return rsi_values[-1] if rsi_values else 50.0

    @staticmethod
    def comprehensive_score(prices: List[float], volumes: List[float]) -> Dict:
        """综合评分"""
        momentum = AlphaFactors.momentum_factor(prices)
        reversal = AlphaFactors.reversal_factor(prices)
        volatility = AlphaFactors.volatility_factor(prices)
        volume = AlphaFactors.volume_factor(volumes)
        rsi = AlphaFactors.rsi_factor(prices)

        # 综合打分 (0-100)
        score = 50
        score += momentum * 100 * 0.2
        score += reversal * 100 * 0.15
        score -= volatility * 100 * 0.15
        score += (volume - 1) * 10 if volume > 1.5 else 0
        score += (rsi - 50) * 0.2

        return {
            "score": round(max(0, min(100, score)), 2),
            "momentum": momentum,
            "reversal": reversal,
            "volatility": volatility,
            "volume_factor": volume,
            "rsi": rsi
        }

6. Python接入SDK

6.1 MCP客户端SDK

# mcp_client.py
import asyncio
import json
import subprocess
from typing import Dict, List, Optional, Any


class MCPClient:
    """MCP客户端SDK"""

    def __init__(self, command: str, args: List[str] = None):
        self.command = command
        self.args = args or []
        self.process: Optional[subprocess.Popen] = None
        self._request_id = 0

    async def start(self):
        """启动MCP服务进程"""
        self.process = subprocess.Popen(
            [self.command] + self.args,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        # 初始化
        response = await self.send_request("initialize", {})
        return response

    async def send_request(self, method: str, params: dict) -> dict:
        """发送MCP请求"""
        self._request_id += 1
        request = {
            "jsonrpc": "2.0",
            "id": self._request_id,
            "method": method,
            "params": params
        }
        self.process.stdin.write(json.dumps(request) + "\n")
        self.process.stdin.flush()

        response_line = self.process.stdout.readline()
        return json.loads(response_line.strip())

    async def list_tools(self) -> List[dict]:
        """获取可用工具列表"""
        response = await self.send_request("tools/list", {})
        return response.get("tools", [])

    async def call_tool(self, name: str, arguments: dict) -> dict:
        """调用工具"""
        response = await self.send_request("tools/call", {
            "name": name,
            "arguments": arguments
        })
        return response

    async def get_stock_quote(self, code: str) -> dict:
        """获取股票行情"""
        result = await self.call_tool("get_stock_quote", {"code": code})
        return json.loads(result["content"][0]["text"])

    async def calculate_indicator(self, data: list, indicator: str, period: int = 14) -> dict:
        """计算技术指标"""
        result = await self.call_tool("calculate_indicator", {
            "data": data,
            "indicator": indicator,
            "period": period
        })
        return json.loads(result["content"][0]["text"])

    async def stop(self):
        """停止MCP服务"""
        if self.process:
            self.process.terminate()
            self.process.wait()


# ==================== 使用示例 ====================

async def main():
    """SDK使用示例"""
    client = MCPClient("python", ["mcp_server_stdio.py"])

    try:
        # 启动服务
        await client.start()
        print("✅ MCP服务已启动")

        # 获取工具列表
        tools = await client.list_tools()
        print(f"📋 可用工具: {len(tools)} 个")
        for tool in tools:
            print(f"   - {tool['name']}: {tool['description']}")

        # 获取股票行情
        quote = await client.get_stock_quote("600000")
        print(f"\n📊 股票行情: {quote}")

        # 计算技术指标
        prices = [10.0, 10.2, 10.5, 10.3, 10.8, 11.0, 10.9, 11.2, 11.5, 11.3]
        sma = await client.calculate_indicator(prices, "sma", 5)
        print(f"\n📈 SMA指标: {sma}")

    finally:
        await client.stop()


if __name__ == "__main__":
    asyncio.run(main())

7. 项目结构

ai-quant-trading/
├── README.md                    # 项目文档
├── requirements.txt             # 依赖
├── mcp_server_stdio.py          # 本地stdio模式服务
├── mcp_server_http.py           # 远程HTTP/SSE模式服务
├── mcp_client.py                # Python SDK客户端
├── indicators.py                # 技术指标计算
├── factors.py                   # Alpha因子计算
├── tests/
│   ├── test_indicators.py       # 指标测试
│   ├── test_factors.py          # 因子测试
│   └── test_mcp_client.py       # 客户端测试
└── .trae/
    └── mcp.json                 # Trae MCP配置

requirements.txt

aiohttp>=3.9.0
numpy>=1.24.0
pytest>=7.0.0

8. 总结

核心要点

  1. MCP协议:基于JSON-RPC 2.0,支持stdio和HTTP/SSE两种通信模式

  2. 本地开发:stdio模式无需网络配置,适合快速迭代

  3. 生产部署:HTTP/SSE模式支持远程访问和实时推送

  4. 策略服务:提供完整的技术指标和Alpha因子计算能力

  5. SDK接入:封装客户端SDK,简化AI模型与MCP服务的交互

下一步

  • 接入真实行情数据源(如Tushare、AKShare)

  • 实现更多量化因子和策略

  • 添加风控和仓位管理模块

  • 构建可视化监控面板


📝 License: MIT

🤝 Contributions Welcome

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/gzcity/ai-quant-trading'

If you have feedback or need assistance with the MCP directory API, please join our Discord server