Toss 证券 Open API 开放了什么
API 是让程序代替人去敲的窗口。可以把它理解成券商开的一扇门,平时在 App 里用手点的查询和下单,现在可以按固定格式发送请求来完成。与自动点击 App 界面的取巧做法不同,这是官方通道,不必担心账号被限制。
功能分为五类:认证(Auth)、行情与个股信息(Market Data、Stock Info、Market Info、Market Indicators、Ranking)、账户与资产(Account、Asset)、订单(Order、Order History、Order Info)、条件单(Conditional Order、Conditional Order History)。覆盖韩国(KRX)与美国股票。
行情与个股信息对所有用户一致,只要有令牌就能调用:现价、盘口、成交、K 线(1 分钟与日线)、涨跌停价、个股主数据、买入注意事项、汇率、韩美市场日历、成交额与涨跌幅排行,以及指数与分投资者成交额。
账户与资产、订单、条件单会直接影响自己的账户,因此除令牌外还需要账户识别请求头。本文真正要讲的正是这一半。
目前只提供 REST。用于实时推送的 WebSocket 标注为后续支持,所以现阶段需要按需轮询。
在哪里、怎么申请
申请入口不是开发者表单,而是 Toss 证券的网页交易端 WTS(tossinvest.com)。用已有的 Toss 证券账户登录后进入设置,就能看到 Open API 项,在那里自行签发 client_id 与 client_secret。没有审核排队,当场完成。
client_id 相当于账号,client_secret 相当于密码。离开签发页面后通常无法再次查看 secret,请当场复制保存到安全的地方。
第二步才是真正的关口。在同一页面下方的允许 IP 管理里,登记将要调用 API 的 IP。不在列表中的 IP 即使密钥正确也会被 403 拦截。公网 IP 可以在终端用一行 curl ifconfig.me 查到。
家庭或办公室线路的公网 IP 可能变动,这点最好提前知道。某天忽然出现 403,多半不是密钥问题而是地址变了。如果打算在服务器或云上运行自动化,请登记那台机器的出口 IP。
开放是按账户逐步进行的,如果设置里看不到 Open API 菜单,说明还没轮到。此时可以通过页面横幅的预约申请登记,开放时会收到通知。
取得令牌并完成第一次调用
所有调用都需要 OAuth 2.0 访问令牌,签发方式是 Client Credentials Grant,即由程序用自己的 id 与 secret 换取令牌,而不是让人走登录界面。这正是它适合无人值守自动化的原因。
记住三点即可。有效期为 86400 秒,也就是 24 小时。没有刷新令牌,过期后向同一端点重新申请即可。每个客户端同时只有一个有效令牌,重新签发会立即让此前的令牌失效。若多个脚本各自申请令牌就会互相顶掉,因此应把令牌缓存到文件中共享使用直到过期。
官方指南的示例是把 client_id 与 client_secret 放在请求体里。不过在我的环境中请求体方式返回 invalid_client,改用 HTTP Basic 认证请求头才签发成功。哪种可用就用哪种。
拿到令牌后,先从不触及账户的查询开始。个股信息与现价只要令牌即可。随后查询账户列表可以拿到 accountSeq,这个值就是之后持仓、订单、条件单调用中 X-Tossinvest-Account 请求头的内容。
# 1) 令牌签发(官方示例:请求体方式)
curl -s -X POST 'https://openapi.tossinvest.com/oauth2/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials' \
-d 'client_id=YOUR_CLIENT_ID' \
-d 'client_secret=YOUR_CLIENT_SECRET'
# 若返回 invalid_client,改用 Basic 请求头
curl -s -X POST 'https://openapi.tossinvest.com/oauth2/token' \
-u "$TOSS_API_KEY:$TOSS_SECRET_KEY" \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials'
# 2) 个股信息(仅需令牌)
curl -s 'https://openapi.tossinvest.com/api/v1/stocks?symbols=005930' \
-H "Authorization: Bearer $TOKEN"
# 3) 持仓(令牌 + 账户请求头)
curl -s 'https://openapi.tossinvest.com/api/v1/holdings' \
-H "Authorization: Bearer $TOKEN" \
-H 'X-Tossinvest-Account: 1'Claude Code 与 Codex 是什么,如何安装
Claude Code 出自 Anthropic,Codex 出自 OpenAI,都是运行在终端里的 AI 编码代理。不是在聊天窗口给你代码让你粘贴,而是由代理直接在你的电脑上读写文件、执行命令。因此特别适合 API 对接这种读文档、写代码、运行、核对结果的循环。
只要装有 Node.js,安装就是一行:npm install -g @anthropic-ai/claude-code 或 npm install -g @openai/codex,之后用 claude 或 codex 启动。首次运行需要登录或登记密钥,Claude Code 用付费 Claude 订阅账户,Codex 用 ChatGPT 账户或 OpenAI API 密钥。
两者装一个就够。若都装,意义在于交叉复核:让一方审阅另一方写的代码。涉及下单的代码,这种复核很值。
有一条原则不可妥协。签发的密钥要放进 .env 文件,并把该文件写入 .gitignore,避免进入代码仓库。不要把密钥直接写进聊天窗口或代码。券商密钥一旦泄露,别人就能在你的账户里下单。
还有一点,不要在代理可以访问下单 API 的情况下,开启无需确认就执行一切命令的模式。很多人为了省事这么用,但在可能产生真实成交的环境里,逐条确认才是正确的默认值。
# 终端 AI 代理(需要 Node.js)
npm install -g @anthropic-ai/claude-code # 运行:claude
npm install -g @openai/codex # 运行:codex
# 密钥放在 .env 并排除出仓库
cat >> .env <<'EOF'
TOSS_API_KEY=你的_client_id
TOSS_SECRET_KEY=你的_client_secret
EOF
echo '.env' >> .gitignore该让代理做什么
第一件事是让它读官方文档。Toss 证券另外提供了适合机器阅读的版本,公开了规范原始 JSON 与 Markdown 概览,把地址告诉代理,它就不会去猜端点与请求格式。
接着从查询开始。让它写一个从 .env 读取密钥、把持仓与浮动盈亏输出成表格的脚本,得到的就是令牌签发与缓存、账户查询、持仓查询的组合。运行后用肉眼与 App 界面核对数字。跳过这一步,之后所有自动化都建立在未经验证的地基上。
查询对上之后,用自然语言描述交易规则,例如自最高价回落 20% 就全部卖出。关键不在于规则如何编码,而在于你能否说清楚它在什么时点、以哪个价格为准判定:按收盘价还是盘中价,一天检查几次。
最后,把反复使用的工作固化成代理的技能或命令文件。既不用每次重复解释,也能把安全规则一并写进去。
把下单交出去之前必须设好的闸门
查询一旦打通,下单也随之打通。用同样的令牌与请求头发一次 POST,就是真实成交。所以在写下单代码之前先定好安全装置更稳妥。
把安全装置分成两层来想会更清楚:API 本身提供的一层,以及自己在脚本里加的一层。
API 一侧最具代表性的是幂等键。在下单请求里放入 clientOrderId,即使因网络重试发送两次,订单也只受理一次;用同一个键发送内容不同的订单会被拒绝,因此也能拦住失误。另外还有一条:订单金额达到 1 亿韩元以上时,必须把 confirmHighValueOrder 设为 true 才会受理。
我加的一层是这样。默认始终是演练模式,仅凭参数不会真正下单。真实下单同时要求执行标志与标的一致性确认。订单金额上限写在文件里,超过就必须另加标志才放行。默认限价,市价只有明确指定时才开启。下单前买入先查可用金额、卖出先查可卖数量。
这一层按自己的代码来设计即可。形式不重要,原则才重要:真实下单必须由人再明确确认一次,自动化不能自行越过上限。
| 层 | 装置 | 防止什么 |
|---|---|---|
| API | clientOrderId 幂等键 | 网络重试导致同一笔订单被受理两次 |
| API | confirmHighValueOrder | 1 亿韩元以上的订单未经确认发出 |
| API | 可用金额与可卖数量查询 | 直接发出超过余额的订单 |
| 我的脚本 | 默认演练模式 | 参数输错就产生真实下单 |
| 我的脚本 | 执行标志加标的确认 | 订单落到错误的标的上 |
| 我的脚本 | 订单金额上限 | 自动化执行超出预期的金额 |
| 我的脚本 | 默认限价,市价需显式指定 | 盘口很薄时以市价被推着成交 |
curl -s -X POST 'https://openapi.tossinvest.com/api/v1/orders' \
-H "Authorization: Bearer $TOKEN" \
-H 'X-Tossinvest-Account: 1' \
-H 'Content-Type: application/json' \
-d '{
"symbol": "005930",
"side": "BUY",
"orderType": "LIMIT",
"quantity": 10,
"price": "70000",
"clientOrderId": "my-order-20260725-001"
}'条件单 — 把监视交给券商服务器
要自动止损或止盈,通常需要一个持续盯价的程序,而那台机器休眠或关机时监视就中断了。条件单把这份监视交给券商服务器。
类型有三种。SINGLE 只监视一个条件。OCO 同时监视两个条件,其中之一触发后自动撤销另一个,也就是止损与止盈成对的经典用法;两条腿都是卖出,第一个触发价要高于现价,第二个要低于现价。OTO 则在第一个条件成交之后才开始监视第二个,第一腿买入、第二腿卖出,可以把入场与离场一次登记。
限制也要知道。OCO 与 OTO 只支持限价,同一标的只能有一个组合条件单,若设定的价格已经满足条件则会被拒绝。SINGLE 没有每标的数量限制。
与自建监视程序相比,取舍很清楚。条件单由服务器监视,与自己电脑的状态无关,反应也更快,但条件仅限于单纯的价格水平。需要计算的条件,例如均线或突破新高,仍要在自己这边判定后再下单。实务上比较顺手的分工是:止损止盈这类防线交给条件单,需要计算的入场判断留给自己的脚本。
curl -s -X POST 'https://openapi.tossinvest.com/api/v1/conditional-orders' \
-H "Authorization: Bearer $TOKEN" \
-H 'X-Tossinvest-Account: 1' \
-H 'Content-Type: application/json' \
-d '{
"symbol": "005930",
"type": "SINGLE",
"quantity": 100,
"orderType": "LIMIT",
"clientOrderId": "my-cond-20260725-001",
"expireDate": "2026-09-10",
"first": {
"orderSide": "SELL",
"triggerPrice": "295",
"orderPrice": "295"
}
}'如何应对调用限额与错误
所有 API 都按客户端与 API 分组限制每秒请求数。行情为每秒 10 次,订单为每秒 6 次,而开盘后的 09:00 至 09:10 降为每秒 3 次。账户列表查询最紧,为每秒 1 次,因此账户编号这类几乎不变的值应取一次并缓存。
超限会返回 429。按响应头 Retry-After 等待后重试,若反复出现则以 1 秒、2 秒、4 秒的方式退避并加入少量随机延迟。正常响应也会带回剩余额度,额度下降时提前放慢速度更安全。
错误格式统一,按 code 分支即可:令牌过期为 expired-token,余额不足为 insufficient-buying-power,非受理时间为 order-hours-closed,价格超出涨跌停为 price-out-of-range,同一幂等键内容不同为 idempotency-key-conflict。需要咨询时附上响应中的 requestId。
把脚本交给代理时,最好一开始就要求写好这些错误处理。若只说做出来,往往只写成功路径,那样接到定时任务上就会静默失败。
总结:按这个顺序开始
第一,在 Toss 证券 WTS 设置里签发 Open API 密钥并登记允许 IP。第二,在终端用 curl 取得令牌并查询一条个股信息,这一步确认连通。
第三,安装 Claude Code 或 Codex,把密钥放进 .env,让它写出持仓查询脚本,并与 App 界面核对数字。第四,编写下单脚本,默认演练模式,并从一开始就装好真实下单的闸门。第五,用极小数量真实下单一次,并确认改单与撤单。第六,把止损止盈这类防线迁移到条件单。
最后一点虽然显而易见仍要说明。自动交易会把错误的规则又快又忠实地重复执行。开始时务必用小额,充分演练之后再实盘,结果责任完全由本人承担。
至于如何验证规则过去是否真的赚钱,也就是用历史数据检验交易规则的回测,将在下一篇讨论。
