trader-in-broker 是做什么的?
订单执行器是此工具包中唯一可能导致真实订单的技能,因此它最为严格。订单只有在通过以下所有关卡后才会到达市场,每次每笔订单均如此:
- trader-in-risk 今天已通过此确切订单(通过指纹匹配;使用与
trader-in-risk/check.py相同的ORDER_FIELDS和哈希)。 trader-in/config.json中的"paper": false。默认使用模拟模式(paper),不会发送任何内容;成交进入本地模拟分类账。- 用户在聊天中为此单笔订单输入了明确的“是”。
- 用户点击了 Claude 自己的权限卡上的“允许一次”,以进行每个
place_order调用,因为订单工具被设置为“需要批准”。
没有“是”,就没有订单。一个“是”覆盖一份订单单(其买入、止损和目标腿),绝不批量处理。
下面的 ${CLAUDE_SKILL_DIR} 是此技能所在的文件夹(此 SKILL.md 文件所在位置)。
python3 "${CLAUDE_SKILL_DIR}/ticket.py" show # 显示所有订单单(READY 或 NOT READY)
python3 "${CLAUDE_SKILL_DIR}/ticket.py" approve --index 1 --reply "yes"
python3 "${CLAUDE_SKILL_DIR}/ticket.py" paper-fill --index 1 --price 1196.30 # 模拟模式:买入
python3 "${CLAUDE_SKILL_DIR}/ticket.py" paper-fill --symbol RELIANCE --side sell --qty 12 --price 1212.70 --leg target
python3 "${CLAUDE_SKILL_DIR}/ticket.py" paper # 显示模拟分类账和盈亏
python3 "${CLAUDE_SKILL_DIR}/ticket.py" result --index 1 --leg entry --status placed --broker-id ID --filled-qty 12 --filled-price 1196.30
python3 "${CLAUDE_SKILL_DIR}/ticket.py" result --index 1 --leg stop --status placed --broker-id ID
python3 "${CLAUDE_SKILL_DIR}/ticket.py" fill --symbol RELIANCE --side sell --qty 12 --price 1212.70 --leg target
python3 "${CLAUDE_SKILL_DIR}/ticket.py" flatten --symbol RELIANCE --qty 12
python3 "${CLAUDE_SKILL_DIR}/ticket.py" log
ticket.py 从不与券商通信。它渲染订单单,检查回复是否为该订单的真实“是”,维护模拟分类账,构建平仓订单单,并将日志保存在 trader-in/state/broker.json 中。--now "2026-10-27 10:15"(或仅 10:15)可固定 IST 时间。接受的符号格式:RELIANCE、RELIANCE.NS、NSE:RELIANCE、M&M、BSE:500325、500325.BO。
它读取和写入的文件
| 文件 | 说明 |
|---|---|
trader-in/orders.json | 提议的订单(trader-in-budget 写入;flatten 会替换它) |
trader-in/config.json | broker(kite 或 upstox)、paper、product、flat_by、costs、capital_inr |
trader-in/state/risk.json | trader-in-risk 的判定结果;只有今日的 PASS 状态为 READY |
trader-in/state/broker.json | 每个“是”、“否”、“已下达”、腿已下达、腿已成交的记录,以及包括成本的每条条目最大亏损 |
trader-in/state/paper.json | 模拟分类账:现金、未平仓头寸、已平仓交易、扣除预估成本后的已实现盈亏 |
trader-in/portfolio.json | 现金和股票(头寸以 RELIANCE.NS 之类的 symbol 为键,含 exchange) |
trader-in/plan.json | flatten 的平仓时间 |
trader-in/universe.json | (Upstox)扫描仪中的 ISIN(若存在) |
trader-in/state/EQUITY_L.csv | (Upstox)NSE 股票列表,在需要 ISIN 时下载一次 |
一次交易,三个订单(每次执行括号订单前请阅读)
trader-in-budget 写入一个“括号”订单(入场、止损、目标)。Zerodha 和 Upstox 不再为此提供括号订单,因此订单单将其转换为:
| 腿 | 订单 | 时机 |
|---|---|---|
| 1 | 以入场价限价买入(或市价),MIS 或 CNC | 立即 |
| 2 | 以止损价为触发价的 SL-M 卖出 | 仅在腿 1 成交后 |
| 3 | 以目标价 限价 卖出 | 仅在腿 1 成交后 |
腿 2 和腿 3 之间没有关联(无 OCO)。 当一个腿成交时,另一个腿仍然有效。必须立即取消它,否则可能导致用户做空(对于 MIS)或被拒绝(对于 CNC)。/trader-in-alerts 可以监控止损和目标价位,并在任意一个被触发时发出警报。如果在腿 1 成交前下达,腿 2 和腿 3 只是普通的卖出订单,可能开立空头头寸。
每份订单单都会显示预估成本(规范 §6:每个 MIS 腿的佣金 min(₹20, 0.03%)、STT、交易所和 SEBI 费用、印花税、18% GST)以及止损时的最大亏损(包含往返成本)。该数字也会被记录,供 trader-in-risk 的每日亏损限额使用。成本始终为估算值:实际成本以合约单为准。
模拟模式(默认)
印度券商没有模拟账户,因此模拟模式是一个本地分类账,位于 trader-in/state/paper.json。不会向任何地方发送任何内容。
ticket.py show,显示一个 READY 状态的订单单,用户输入“是”,ticket.py approve。- 当价格到达入场价时,
ticket.py paper-fill --index N(限价)或--price P。买入限价单不能高于其限价成交。 - 当止损或目标价触发时,记录那一个卖出单:
paper-fill --symbol RELIANCE --side sell --qty 12 --price 1188.10 --leg stop。分类账记录毛盈亏、预估往返成本和净盈亏。 ticket.py paper打印现金、未平仓头寸和已实现盈亏。
模拟模式的条目被记录为 placed(带有 "paper": true),因此 trader-in-risk 会像对待真实订单一样,将其计入每日交易次数和每日亏损限额。
设置 A:Zerodha Kite(官方 MCP 服务器)— 默认
Zerodha 的服务器:github.com/zerodha/kite-mcp-server(MIT 协议,Go 语言)。已对照其源代码和 2026-10-27 的 README(最新提交 5e044dc,标签 v0.4.0-dev24)进行过核对。
托管的服务器无法下达订单。 README 指出托管的 https://mcp.kite.trade/mcp “排除了潜在破坏性交易操作以确保安全”,并且 Zerodha 自己的页面将其描述为只读(一篇 Z-Connect 文章曾提到 GTT 订单是例外;范围随时间变化,请在连接后通过 Claude 的工具列表进行检查)。它是免费的,不需要 API 密钥:login 工具返回一个 Kite 链接,用户在浏览器中用自己 Kite 密码和 2FA 登录,绝不在聊天中操作。
托管只读(报价、持仓、头寸、保证金、订单、历史记录):
- Claude Desktop:设置 > 开发者 > 编辑配置,添加来自
claude_desktop_config.example.json的"kite"块(运行npx mcp-remote https://mcp.kite.trade/mcp;需要 Node.js),重新启动。 - Claude Code:
claude mcp add --transport http kite https://mcp.kite.trade/mcp(或使用相同的npx mcp-remote命令作为 stdio 服务器:claude mcp add kite -- npx mcp-remote https://mcp.kite.trade/mcp)。
要通过 Claude 下达订单,用户需要运行他们自己的服务器副本,并使用他们自己的 Kite Connect 应用:
- 在 developers.kite.trade 创建一个 Kite Connect 应用(请查看当前价格)。其重定向 URL 必须指向本地服务器的回调地址;在服务器源代码中,回调路径是
APP_HOST:APP_PORT(默认http://localhost:8080/callback)上的/callback。我们尚未进行端到端测试。 - 从 2026 年 4 月 1 日起,Zerodha 的支持页面称通过 API 下单需要在 Zerodha 处将静态 IP 列入白名单(NSE/SEBI 零售算法规则)。没有静态 IP 的家庭连接可能导致订单被拒绝。在投入使用前,请查看 Zerodha 的现行规则。
- 构建它:
git clone https://github.com/zerodha/kite-mcp-server && cd kite-mcp-server && go build -o kite-mcp-server(需要 Go 1.21+)。 - 从
claude_desktop_config.example.json添加"kite-orders"块:二进制文件的完整路径、APP_MODE为stdio,用户需要自行将KITE_API_KEY和KITE_API_SECRET输入该文件中。在 Claude Code 中:先由用户在终端中导出变量值,然后运行claude mcp add kite-orders -e APP_MODE=stdio -e KITE_API_KEY="$KITE_API_KEY" -e KITE_API_SECRET="$KITE_API_SECRET" -- /full/path/to/kite-mcp-server。如果不需要两者,只保留kite/kite-orders之一。 - 重新启动,让 Claude 调用
login,用户打开链接并登录。Kite 会话每天过期(Kite Connect 访问令牌有效期至次日早晨),因此预计每个交易日都需要重新登录。
密钥和令牌永远不能出现在聊天中。 切勿询问它们,也不必将配置文件内容读回对话中。如果用户粘贴了密钥或令牌,请告诉他们删除该消息并在 developers.kite.trade 重新生成。
工具权限: 自定义 > 连接器(Claude Desktop),打开 Kite 服务器,设置:
place_order、modify_order、cancel_order、place_gtt_order、modify_gtt_order、delete_gtt_order:需要批准。永远不要设为“始终允许”。- 只读工具(
get_profile、get_margins、get_holdings、get_positions、get_orders、get_order_history、get_order_trades、get_trades、get_gtts、get_quotes、get_ltp、get_ohlc、get_historical_data、search_instruments、login):可以设为“始终允许”。 - 在 Claude Code 中,将其保留在
.claude/settings.json的 ask 级别:"permissions": {"ask": ["mcp__kite-orders__place_order", "mcp__kite-orders__modify_order", "mcp__kite-orders__cancel_order"]};永远不要将订单工具放入allow中。服务器也支持EXCLUDED_TOOLS=place_order,modify_order,cancel_order以实现只读副本。
place_order 参数(来自服务器源代码):variety(regular)、exchange(NSE/BSE)、tradingsymbol、transaction_type(BUY/SELL)、quantity(整数)、product(MIS/CNC)、order_type(MARKET/LIMIT/SL/SL-M)、price(LIMIT、SL)、trigger_price(SL、SL-M)、validity(DAY)、可选的 tag(≤ 20 个字符;订单单会添加 trin + 12 位指纹的十六进制,以便日后查找订单)。该服务器的工具没有 market_protection 参数;NSE 现在对 API MARKET 和 SL-M 订单应用市场保护,因此市价单可能由券商转换为受保护的限价单。限价入场可以避免此问题。对于 BSE,Kite 的 tradingsymbol 是股票名称,而非数字代码:可以使用 search_instruments 进行查询。
设置 B:Upstox("broker": "upstox")
- Upstox 的官方 MCP 服务器(
https://mcp.upstox.com/mcp,通过upstox/upstox-plugin-marketplace插件的upstox-mcp安装)是只读的:Upstox 的页面称无法通过它下达订单。连接每天过期(浏览器中的 OAuth 同意)。 - Upstox 的官方代理技能(在 Claude Code 中通过
/plugin install upstox-skill@upstox-plugins-official安装,前提是已执行/plugin marketplace add upstox/upstox-plugin-marketplace)可以使用 v3 订单 API 下达订单。它从UPSTOX_ACCESS_TOKEN环境变量(由用户在自己的 shell 中设置,绝不通过聊天)读取每日访问令牌,显示自己的预览并等待确认。Upstox 称它不能在纯 Claude Desktop 聊天中运行。 - 或者用户从订单单的数据在 Upstox 应用中手动下单。
订单单会打印 POST https://api-hft.upstox.com/v3/order/place 的请求体(v2 /v2/order/place 标记为已弃用;其字段相同,除了缺少 slice):quantity(整数)、product(I 表示日内 = MIS,D 表示交割 = CNC)、validity DAY、price(市价/SL-M 为 0)、instrument_token、order_type、transaction_type、disclosed_quantity 0、trigger_price(除非是 SL / SL-M,否则为 0)、is_amo false(Upstox 忽略)、tag,以及 market_protection: -1(自动)用于 MARKET 和 SL-M 订单(因为 0 对于 API 市价订单会被拒绝)。
instrument_token 的格式为 NSE_EQ|<ISIN>(或 BSE_EQ|<ISIN>)。ISIN 的来源按顺序为:--isin、订单中的 isin、来自扫描仪的 trader-in/universe.json,否则来自 NSE 的 EQUITY_L.csv(使用浏览器 User-Agent 下载一次至 trader-in/state/EQUITY_L.csv,先尝试 archives. 再尝试 nsearchives.)。
BSE 限制: NSE 列表仅映射 NSE 股票。像 500325.BO 这样的 BSE 股票代码无法映射,因此需要传递 --isin;对于 .BO 名称的股票,会使用 NSE 列表中的 ISIN(同一家公司),但请务必核对。我们尚未验证此处的 Upstox 工具文件格式。如果没有 ISIN,实时 Upstox 订单单不会处于 READY 状态;模拟订单单不需要 ISIN。
步骤:入场
ticket.py show。仅将 READY 状态的订单单展示给用户。不是 READY 或 BLOCKED 状态的订单单将回到/trader-in-risk(它没有 broker JSON 记录)。- 展示一份订单单,包括非 OCO 警告,并询问:“要下达这个订单吗?请回复 yes 或 no。”每次只问一个订单。切勿提供“全部同意”的选项。
ticket.py approve --index N --reply "<用户的回复,逐字逐句>"。如果显示“未记录”,则意味着该回复并非针对此订单的明确“是”(如“sure”、“haan”、“全部同意”、指代另一只股票或金额的“是”)。请再次询问。切勿自行将任何回复解释为“是”。- 模拟模式: 按上述步骤执行
paper-fill。实时模式,Kite: 使用精确的腿 1 JSON 调用place_order;用户点击“允许一次”。确认成交(使用get_order_history/get_positions),然后依次为腿 2 和腿 3 调用place_order,每个调用均需用户单独点击“允许一次”。实时模式,Upstox: 将请求体交给 Upstox 代理技能或应用,一次一个腿,顺序相同。 - 记录每个实时腿:
ticket.py result --index N --leg entry|stop|target --status placed|denied|failed --broker-id <id>(入场腿需--filled-qty、--filled-price)。只有入场腿会被计入 trader-in-risk 的交易次数;其他腿记录为leg_placed。失败的订单不会自动重试,需要重新检查并再次获得用户的“是”。
步骤:持仓期间,以及在平仓时限前平仓
/trader-in-alerts监控止损位、目标位和平仓时间。- 当止损或目标位成交时:实时模式,执行
ticket.py fill ... --leg stop(它会提醒您现在立即取消另一条腿:使用get_orders,然后调用cancel_order,需要批准);模拟模式,执行paper-fill ... --leg stop。 - 在平仓时限前(默认 15:10 IST),任何仍未平仓的头寸都将被平仓。券商从大约15:20 IST 开始自动平仓未平仓的 MIS 头寸并收取费用(Zerodha 列出的费用为每笔订单 ₹50 + GST),因此不要留给它们处理:
- 实时模式:询问券商持有多少股票:
get_positions(只读)。 ticket.py flatten --symbol RELIANCE --qty 12将一个 MARKET 卖出单(相同产品)写入trader-in/orders.json。- 展示新的订单单并询问“是”。
- 实时模式:按上述方式下达 MARKET 卖出单;模拟模式:使用
paper-fill记录卖出。 - 如果券商已经自动平仓,只需记录实际成交:
ticket.py fill --symbol RELIANCE --side sell --qty 12 --price <实际价格> --leg broker-auto-squareoff。
- 实时模式:询问券商持有多少股票:
文件说明
trader-in/state/broker.json:每次操作的持久化日志。ticket.py log以可读格式打印。trader-in/state/paper.json:模拟分类账。ticket.py paper打印摘要。CLAUDE_SKILL_DIR由 Claude 设置;无需手动导出。
安全说明: 密钥、令牌和密码绝不能出现在聊天中。如果用户试图粘贴它们,请拒绝并请求他们在开发者门户中重新生成。--reply 标志会捕获确切的用户回复;您绝不能替换或推断它。
假设: 此技能假定用户已正确设置 Kite MCP 服务器或 Upstox 连接。它不会自行管理身份验证。未能保护 API 凭据可能导致未经授权的交易。
交易有风险。 过去的业绩不代表未来的结果。始终使用模拟模式进行测试,并从您自己能承受损失的资本开始。