快速开始
本套接口为标准 REST / HTTP,任意语言用 HTTP 客户端即可调用,无需安装专用 SDK。
API Host
- HTTP API —
https://webapi.moomoo.com - WebSocket Quote —
wss://webapi-quote.moomoo.com - WebSocket Trade —
wss://webapi-trade.moomoo.com
INFO
时间字段多为 Unix 毫秒时间戳(如 update_time、listing_date),部分为秒级(如 wrt_maturity_date);data_date 等日期为标的市场时区的 YYYY-MM-DD。
选择认证方式
moomoo OpenAPI 支持两种认证方式。推荐优先使用方式一:OAuth 2.1 + PKCE。
| 认证方式 | 推荐程度 | 适用场景 | 请求认证方式 |
|---|---|---|---|
| 方式一:OAuth 2.1 + PKCE | 推荐 | 第三方应用、用户授权、需要代表用户访问账户或交易资源 | Authorization: Bearer {access_token} |
| 方式二:传统 API Key | 兼容 | 服务端自有系统、后端任务、兼容传统接入方式 | X-Api-Key + Authorization: {signature_base64} |
方式一:OAuth 2.1 + PKCE(推荐)
OAuth 2.1 + PKCE 是推荐认证方式。它使用 Bearer Token 调用接口,无需保存 API 私钥,也无需为每个 REST 请求计算签名。
适用场景
适合第三方应用、桌面应用、移动端应用、Web 应用等需要用户授权的场景。
第一步:注册 OAuth 客户端
执行以下命令注册 OAuth 客户端,获取 client_id:
curl -X POST https://webapi.moomoo.com/oauth2/register \
-H "Content-Type: application/json" \
-d '{
"redirect_uris": ["http://localhost:60355/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code","refresh_token"],
"response_types": ["code"],
"client_name": "My moomoo OpenAPI"
}'响应示例:
{
"client_id": "4a8bcd69-e915-4778-9583-17ad0e9e6a80",
"client_id_issued_at": 1782357937,
"client_name": "My moomoo OpenAPI",
"redirect_uris": ["http://localhost:60355/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"token_endpoint_auth_method": "none",
"response_types": ["code"],
"registration_access_token": "2827551884d13cbed3ea58280b44765a56eae0cca39587b732bda239b322a35a",
"registration_client_uri": "https://webapi.moomoo.com/oauth2/register/4a8bcd69-e915-4778-9583-17ad0e9e6a80",
"scope": "quote:read quote:write trade:read trade:write accid:*",
"pkce_required": true
}保存 client_id 供后续使用。
第二步:引导用户授权并获取授权码
获取 client_id 后,开发者需要生成并临时保存 state 和 code_verifier,再自行拼接授权 URL,引导用户在浏览器中打开并完成授权。
code_verifier 应为高熵随机字符串;code_challenge 由 code_verifier 计算得到:
code_challenge = BASE64URL-ENCODE(SHA256(code_verifier))请将 state 和 code_verifier 临时保存到当前授权会话中,后续回调校验和换取 Token 时会用到。
请求地址:
GET https://webapi.moomoo.com/oauth2/authorize/confirm该地址是浏览器授权页地址。用户会在授权页完成登录、选择授权范围并授权;开发者无需直接调用后端内部授权接口。
Query 参数:
| 参数 | 是否必填 | 示例值 | 说明 | 来源 |
|---|---|---|---|---|
client_id | 是 | 4a8bcd69-e915-4778-9583-17ad0e9e6a80 | OAuth 客户端 ID,用于标识当前应用 | 注册 OAuth 客户端接口返回 |
code_challenge | 是 | stlSAHmH-iuYaK76djkKQpu7Jk1uAh_Dq09M_EYXDXk | PKCE 校验值,用于防止授权码被拦截后滥用 | 由 code_verifier 计算得到,计算方式为 BASE64URL-ENCODE(SHA256(code_verifier)) |
code_challenge_method | 是 | S256 | code_challenge 的计算方式 | 固定传 S256 |
redirect_uri | 是 | http://localhost:60355/callback | 用户授权完成后的回调地址 | 必须与注册 OAuth 客户端时传入的 redirect_uris 之一完全一致 |
response_type | 是 | code | OAuth 响应类型 | 固定传 code |
state | 是 | {random_state} | 防止 CSRF 攻击的随机字符串,也可用于保存业务上下文 | 由开发者生成,并在回调时校验是否一致 |
拼接并编码后的授权 URL 示例(为便于阅读,按参数换行展示;实际访问时请去掉换行和缩进):
https://webapi.moomoo.com/oauth2/authorize/confirm?
client_id=4a8bcd69-e915-4778-9583-17ad0e9e6a80&
code_challenge=stlSAHmH-iuYaK76djkKQpu7Jk1uAh_Dq09M_EYXDXk&
code_challenge_method=S256&
redirect_uri=http%3A%2F%2Flocalhost%3A60355%2Fcallback&
response_type=code&
state={random_state}授权回调:
redirect_uri 是你的应用提供的 HTTP 接收地址,不是 OpenAPI 接口。以 http://localhost:60355/callback 为例,用户完成授权后,浏览器会向你的应用发起一次 GET 请求,并在查询参数中携带 code 和 state:
http://localhost:60355/callback?code={authorization_code}&state={state}你的应用只需要按普通 HTTP 请求处理:
- 监听
localhost:60355的/callback路由。 - 从 query 中读取
code和state。 - 校验回调中的
state是否等于发起授权前保存的值。 - 校验通过后,把
code和之前保存的code_verifier传给第三步换取 Token。
伪代码:
on GET /callback:
code = query["code"]
state = query["state"]
if state != saved_state:
return "invalid state"
使用 code 和 saved_code_verifier 换取 Tokenauthorization_code 只能用于换取 Token,不是调用 OpenAPI 的访问令牌。授权码有效期为 5 分钟,且只能成功使用一次;请在收到回调后立即换取 Token,过期或重复使用都需要重新发起授权。
第三步:使用授权码换取 Token
Body 参数:
| 参数 | 是否必填 | 示例值 | 说明 |
|---|---|---|---|
grant_type | 是 | authorization_code | 固定传 authorization_code |
code | 是 | {authorization_code} | 授权回调中返回的授权码 |
client_id | 是 | 4a8bcd69-e915-4778-9583-17ad0e9e6a80 | OAuth 客户端 ID |
redirect_uri | 是 | http://localhost:60355/callback | 必须与授权 URL 中的 redirect_uri 完全一致 |
code_verifier | 是 | {code_verifier} | 生成 code_challenge 时使用的原始随机字符串 |
请求示例:
curl -X POST https://webapi.moomoo.com/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code={authorization_code}" \
-d "client_id=4a8bcd69-e915-4778-9583-17ad0e9e6a80" \
-d "redirect_uri=http://localhost:60355/callback" \
-d "code_verifier={code_verifier}"响应示例:
{
"access_token": "xxxx",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "yyyy",
"scope": "quote:read trade:read accid:123456"
}响应字段:
| 字段 | 说明 |
|---|---|
access_token | 用于调用 OpenAPI 的访问令牌 |
token_type | 固定为 Bearer |
expires_in | access_token 有效期,单位为秒 |
refresh_token | 刷新令牌,用于在 access_token 过期后换取新的 access_token |
scope | 用户已授权的权限范围,多个 scope 以空格分隔 |
第四步:刷新 Access Token
当 access_token 过期时,可以使用 refresh_token 换取新的 access_token。
Body 参数:
| 参数 | 是否必填 | 示例值 | 说明 |
|---|---|---|---|
grant_type | 是 | refresh_token | 固定传 refresh_token |
refresh_token | 是 | {refresh_token} | 换取 Token 时返回的刷新令牌 |
client_id | 是 | 4a8bcd69-e915-4778-9583-17ad0e9e6a80 | OAuth 客户端 ID |
请求示例:
curl -X POST https://webapi.moomoo.com/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token={refresh_token}" \
-d "client_id=4a8bcd69-e915-4778-9583-17ad0e9e6a80"以上为 Public Client + PKCE 主流程。若使用 token_endpoint_auth_method=client_secret_post 的 Confidential Client,刷新时还需要在 Body 中传入 client_secret。
响应示例:
{
"access_token": "zzzz",
"token_type": "Bearer",
"expires_in": 7200,
"scope": "quote:read trade:read accid:123456"
}刷新时不会轮换 refresh_token;请继续安全保存原 refresh_token。
第五步:调用 REST API
拿到 access_token 后,后续 REST API 请求只需要通过 Authorization 请求头携带 Bearer Token:
Authorization: Bearer {access_token}不需要再计算请求签名,也不需要在 REST API 请求中额外传入 client_id。服务端会从 access_token 中识别用户、OAuth 客户端和授权范围,并根据当前接口所需权限进行校验。
以下以查询港股交易日历为例:
curl -X GET "https://webapi.moomoo.com/api/v1.0/quote/trading-days?market=HK&start=2025-12-22&end=2025-12-26" \
-H "Authorization: Bearer {access_token}"参数说明:
| 参数 | 位置 | 示例值 | 说明 |
|---|---|---|---|
market | Query | HK | 市场前缀 |
start | Query | 2025-12-22 | 起始日期,格式 yyyy-MM-dd |
end | Query | 2025-12-26 | 结束日期,格式 yyyy-MM-dd |
如果 access_token 过期或无效,请使用 refresh_token 刷新后重试;如果返回权限不足,请确认用户授权的 scope 是否覆盖当前接口。
OAuth 优势
- 无需保存 API 私钥
- 无需为每个 REST 请求计算签名
- 基于 Token 授权,更适合用户授权给第三方应用的场景
Token 安全
OAuth Token 应安全存储在应用程序中(如加密文件、安全密钥链),不要存储在环境变量中。
方式二:传统 API Key(兼容)
传统 API Key 主要用于兼容已有服务端接入方式。每次调用 REST API 前,需要使用私钥对请求内容签名。
适用场景
适合服务端自有系统、后端定时任务、内部工具等由开发者自行管理密钥的场景。
第一步:创建 AppKey
请登录 https://open.moomoo.com/dashboard,进入用户中心,创建 AppKey 并上传公钥。创建 AppKey 时需要选择签名算法,并在本地安全保存对应私钥。
传统 API Key 使用非对称密钥签名认证。创建 AppKey 时需要选择签名算法并上传对应公钥;客户端调用 API 时使用本地私钥对请求内容签名,服务端会根据 AppKey 查询公钥和算法后完成验签。
当前支持的签名算法:
| 算法 | 说明 |
|---|---|
Ed25519 | 使用 Ed25519 私钥直接对签名原文签名 |
RSA-SHA256 | 使用 RSA 私钥按 PKCS#1 v1.5 + SHA256 对签名原文签名 |
私钥安全
私钥只应保存在开发者自己的安全环境中,请勿上传到平台、提交到代码仓库,或以明文形式写入日志和配置文件。
第二步:构造签名
每次调用 REST API 前,需要使用 AppKey 对应的私钥对本次请求内容签名。签名原文由 5 个字段组成,字段之间必须使用换行符 \n 连接,等价表达式如下:
{timestamp_ms} + "\n" +
{http_method} + "\n" +
{request_path} + "\n" +
{query_string} + "\n" +
{body_part}不要省略中间的换行符。即使 query_string 或 body_part 为空,也要保留对应字段位置和字段之间的 \n。
字段说明:
| 字段 | 说明 |
|---|---|
timestamp_ms | 当前毫秒时间戳,对应请求头 X-Timestamp |
http_method | HTTP 方法,使用大写,例如 GET、POST |
request_path | URL 路径,不包含域名和查询参数,例如 /api/v1.0/quote/trading-days |
query_string | 最终请求中的原始查询串,不包含开头的 ?;没有查询参数时传空字符串 |
body_part | 请求原始 body 字节的 SHA256 小写十六进制摘要;没有请求体时传空字符串 |
签名必须基于最终发出的请求内容:query_string 的参数顺序和 URL 编码要与实际请求完全一致;body_part 使用原始请求体字节计算,不要重新格式化 JSON 后再计算。
以查询港股交易日历为例:
GET https://webapi.moomoo.com/api/v1.0/quote/trading-days?market=HK&start=2025-12-22&end=2025-12-26如果 timestamp_ms=1782357937000,该 GET 请求没有请求体,精确的签名原文为:
1782357937000\nGET\n/api/v1.0/quote/trading-days\nmarket=HK&start=2025-12-22&end=2025-12-26\n按行展开后是:
1782357937000
GET
/api/v1.0/quote/trading-days
market=HK&start=2025-12-22&end=2025-12-26
<空 body_part>其中最后一个 \n 用于连接 query_string 和空的 body_part。签名后,将签名字节做 Base64 编码,作为 Authorization 请求头的值。
算法使用:
| 算法 | 签名方式 |
|---|---|
Ed25519 | 使用 Ed25519 私钥直接签名上述签名原文 |
RSA-SHA256 | 先对签名原文计算 SHA256,再使用 RSA 私钥按 PKCS#1 v1.5 签名 |
第三步:调用 REST API
调用 REST API 时需要携带以下认证信息:
| Header | 是否必填 | 说明 |
|---|---|---|
X-Api-Key | 是 | AppKey ID |
Authorization | 是 | Base64 编码后的签名结果。AppKey 场景请直接填写签名字符串,不要添加 Bearer 前缀 |
X-Timestamp | 是 | 客户端当前毫秒时间戳,需与签名原文中的 timestamp_ms 一致 |
X-Nonce | 是 | 客户端随机字符串,用于防重放;仅支持字母、数字、下划线和连字符,长度 1-64 |
以下使用 AppKey 方式调用交易日历接口:
curl -X GET "https://webapi.moomoo.com/api/v1.0/quote/trading-days?market=HK&start=2025-12-22&end=2025-12-26" \
-H "X-Api-Key: {app_key}" \
-H "X-Timestamp: {timestamp_ms}" \
-H "X-Nonce: {nonce}" \
-H "Authorization: {signature_base64}"其中 {timestamp_ms} 必须使用当前毫秒时间戳,并与第二步签名原文中的 timestamp_ms 保持一致;{signature_base64} 是第二步签名结果的 Base64 编码。服务端会根据 X-Api-Key 查询已上传的公钥和签名算法,并用同样的签名原文完成验签。
如果客户端时间戳与服务端时间戳偏移量超过阈值(默认5秒),接口会返回 -12006 错误码。客户端可以通过以下接口获取服务端时间戳
curl -X GET https://webapi.moomoo.com/api/v1.0/server-time
Response
{"server_time_ms":"1782971427455"}通用约定
- 证券标识:
{market}.{code},如HK.00700、US.AAPL。 - 时间:多为 Unix 毫秒时间戳,部分秒级;日期字段为标的市场时区
YYYY-MM-DD。 - 比率:百分比数值(
1.23表示 1.23%)。 - 分页:列表类接口用
next_key/limit,详见 分页约定。