Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 2 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,12 @@ guling-trader 与同花顺、MCP 三合一,是这一范式落地 A 股的开

## 怎样才能让 AI 帮我交易 A 股?

三条路都能到达,按你的隐私诉求和技术门槛选一条
两条路都能到达,按你的技术门槛选一条

| 场景 | 路径 | 数据流向 | 难度 |
|------|------|--------|------|
| 最简单,已有 guling.pro 邀请码 | [**A · 托管版**](#路径-a--gulingpro-托管版) | 经 guling.pro 云 | ★ |
| 用 Claude / Cursor / openclaw 等任意 AI | [**B · 云端自助**](#路径-b--任意-ai-客户端通过-mcpgulingpro-自助接入) | 经 mcp.guling.pro 云 | ★★ |
| 极客用户,要求数据不出自己设备 | [**C · 本地直连**](#路径-c--本地-stdio--tailscale-规划中) 🚧 | 仅你的设备 | ★★★ |

> **第一步对所有路径相同**:先把 Windows 端跑起来。

Expand Down Expand Up @@ -87,25 +86,6 @@ AI 会自动抓取该网址的安装向导,一步步完成配对和接入—

**为什么要经过 mcp.guling.pro?** 你家里的 Windows 端和 AI 客户端通常各自在内网,彼此找不到——需要一台公网服务器当"汇合点"。guling.pro 免费提供这条中转隧道,只加密转发你的指令,让你免去自建公网服务器的麻烦,开箱即用、安全又简单。

如果连这条隧道也不想经过,请走下面的 [路径 C](#路径-c--本地-stdio--tailscale-规划中)。

---

## 路径 C · 本地 stdio + Tailscale(规划中)

🚧 **状态:设计已定,代码尚未入库。** 本节为预览;落地后转正。完整设计见 [`docs/local_only_stdio_mcp_setup.md`](docs/local_only_stdio_mcp_setup.md)。

面向隐私要求最高的用户:**交易数据全程不经过任何云服务器**。

- **拓扑**:Windows 交易端 ↔ 你的 Mac(通过 Tailscale 私有网络直连)→ 本地 AI 客户端(Cursor / Claude)通过 stdio 与轻量 relay 进程通信。
- **规划提供**:`mcp/` 文件夹 + Python relay 脚本(`mcp_local_relay.py`),帮你本地把 stdio ↔ WebSocket 桥接。
- **你需做**:安装并配置 Tailscale;编辑 `guling-trader-data\config.json`,把 `ws_endpoint` 填成 Mac 的 Tailscale 地址(格式:`100.x.x.x:8080`)。

### 待落地的清单
- [ ] 新增 `mcp/` 目录与 `mcp_local_relay.py`
- [ ] relay 安装/运行说明与 Cursor / Claude 的 stdio 对接示例
- [ ] Tailscale 内网端到端联调,本节转正

---

## 如何确保交易安全?
Expand Down Expand Up @@ -260,16 +240,14 @@ guling-trader/
├── docs/
│ ├── PROTOCOL.md # MCP 帧协议文档
│ ├── tools_schema.json # 工具 Schema
│ ├── local_only_stdio_mcp_setup.md # 路径 C 设计稿(规划中
│ ├── local_only_stdio_mcp_setup.md # 本地私有化接入设计稿(暂未开放
│ └── specs/ # 规格文档
├── pyproject.toml # 项目元数据和依赖
├── LICENSE # GPL-3.0
└── guling-trader-data/ # 运行时数据目录
└── trader.log # 诊断日志输出位置
```

**注**:MCP 网关、relay 与 `mcp/` 目录为路径 C(本地直连)落地时新增。

</details>

---
Expand Down
183 changes: 0 additions & 183 deletions docs/specs/desktop_rpa_copilot_suite.md

This file was deleted.

6 changes: 0 additions & 6 deletions src/trader/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ class TraderConfig:
xiadan_path_manual: Optional[str] = None # 用户手动指定的 xiadan.exe 路径
ws_endpoint: Optional[str] = None # 自定义中转地址:只填域名或 IP[:端口],协议和路径自动补全
enable_ths_plugin: bool = True # 是否启用同花顺实盘交易插件,默认启用
enable_rpa_suite: bool = False # 是否启用可选的桌面 RPA 扩展模块
chrome_cdp_port: int = 9222 # 本地 Edge/Chrome CDP 端口,默认 9222
order_watch_idle_secs: int = 300 # order_watch 空闲轮询周期(秒):默认 5 分钟
order_watch_active_secs: int = 60 # 有未完成委托时的提速周期(秒):默认 1 分钟
enable_watchlist_watch: bool = True # 是否定时同步自选股并推变化事件(新版 xiadan)
Expand Down Expand Up @@ -78,8 +76,6 @@ def load() -> TraderConfig:
xiadan_path_manual=data.get("xiadan_path_manual"),
ws_endpoint=data.get("ws_endpoint"),
enable_ths_plugin=data.get("enable_ths_plugin", True),
enable_rpa_suite=data.get("enable_rpa_suite", False),
chrome_cdp_port=data.get("chrome_cdp_port", 9222),
order_watch_idle_secs=data.get("order_watch_idle_secs", 300),
order_watch_active_secs=data.get("order_watch_active_secs", 60),
enable_watchlist_watch=data.get("enable_watchlist_watch", True),
Expand All @@ -101,8 +97,6 @@ def save(config: TraderConfig) -> None:
"xiadan_path_manual": config.xiadan_path_manual,
"ws_endpoint": config.ws_endpoint,
"enable_ths_plugin": config.enable_ths_plugin,
"enable_rpa_suite": config.enable_rpa_suite,
"chrome_cdp_port": config.chrome_cdp_port,
"order_watch_idle_secs": config.order_watch_idle_secs,
"order_watch_active_secs": config.order_watch_active_secs,
"enable_watchlist_watch": config.enable_watchlist_watch,
Expand Down
34 changes: 0 additions & 34 deletions src/trader/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,27 +144,6 @@
]
}

XUEQIU_RPA_TOOL = {
"name": "xueqiu_publish_review",
"description": "通过本地已登录的浏览器(Edge/Chrome),在雪球网发布实盘复盘、调仓日志或运营推文(安全拟真,免账号密码)",
"inputSchema": {
"type": "object",
"properties": {
"content": {
"type": "string",
"description": "发布的内容文案。支持包含 $个股名称(代码)$ 格式的雪球 Hashtag 标签。"
},
"semi_manual": {
"type": "boolean",
"default": True,
"description": "是否开启半人工模式。为 true 时在发帖框填入文案后悬停并弹窗提示用户确认;为 false 时自动点击发布。"
}
},
"required": ["content"],
"additionalProperties": False
}
}

from . import config as _config

def load_tools_schema() -> dict[str, Any]:
Expand All @@ -188,9 +167,6 @@ def load_tools_schema() -> dict[str, Any]:
trading_names = {"balance", "position", "orders_active", "orders_filled", "settlement", "watchlist", "buy", "sell", "cancel"}
schema["tools"] = [t for t in schema["tools"] if t.get("name") not in trading_names]

if cfg.enable_rpa_suite:
schema["tools"].append(XUEQIU_RPA_TOOL)

return schema

METHOD_WHITELIST = {
Expand All @@ -204,7 +180,6 @@ def load_tools_schema() -> dict[str, Any]:
"buy",
"sell",
"cancel",
"xueqiu_publish_review",
}


Expand Down Expand Up @@ -289,15 +264,6 @@ async def handle_call(
elif method == "cancel":
entrust_no = params.get("entrust_no")
result = await backend.cancel(entrust_no)
elif method == "xueqiu_publish_review":
if not cfg.enable_rpa_suite:
result = {"code": 1, "error": "RPA 模块未启用,请先开启配置中的 enable_rpa_suite 开关"}
else:
from .rpa.xueqiu import XueqiuRpaBackend
content = params.get("content")
semi_manual = params.get("semi_manual", True)
rpa_backend = XueqiuRpaBackend()
result = await rpa_backend.publish_review(content, semi_manual)
else:
result = {"code": 1, "error": "内部错误"}

Expand Down
1 change: 0 additions & 1 deletion src/trader/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,6 @@ def run() -> None:
account_name=result.config.account_name or "",
agent_token=result.config.agent_token or None,
enable_ths_plugin=result.config.enable_ths_plugin,
enable_rpa_suite=result.config.enable_rpa_suite,
)

def on_open_xiadan() -> None:
Expand Down
Loading
Loading