Skip to content

快速开始

本套接口为标准 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_timelisting_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

bash
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"
        }'

响应示例:

json
{
  "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 后,开发者需要生成并临时保存 statecode_verifier,再自行拼接授权 URL,引导用户在浏览器中打开并完成授权。

code_verifier 应为高熵随机字符串;code_challengecode_verifier 计算得到:

text
code_challenge = BASE64URL-ENCODE(SHA256(code_verifier))

请将 statecode_verifier 临时保存到当前授权会话中,后续回调校验和换取 Token 时会用到。

请求地址:

text
GET https://webapi.moomoo.com/oauth2/authorize/confirm

该地址是浏览器授权页地址。用户会在授权页完成登录、选择授权范围并授权;开发者无需直接调用后端内部授权接口。

Query 参数:

参数是否必填示例值说明来源
client_id4a8bcd69-e915-4778-9583-17ad0e9e6a80OAuth 客户端 ID,用于标识当前应用注册 OAuth 客户端接口返回
code_challengestlSAHmH-iuYaK76djkKQpu7Jk1uAh_Dq09M_EYXDXkPKCE 校验值,用于防止授权码被拦截后滥用code_verifier 计算得到,计算方式为 BASE64URL-ENCODE(SHA256(code_verifier))
code_challenge_methodS256code_challenge 的计算方式固定传 S256
redirect_urihttp://localhost:60355/callback用户授权完成后的回调地址必须与注册 OAuth 客户端时传入的 redirect_uris 之一完全一致
response_typecodeOAuth 响应类型固定传 code
state{random_state}防止 CSRF 攻击的随机字符串,也可用于保存业务上下文由开发者生成,并在回调时校验是否一致

拼接并编码后的授权 URL 示例(为便于阅读,按参数换行展示;实际访问时请去掉换行和缩进):

text
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 请求,并在查询参数中携带 codestate

text
http://localhost:60355/callback?code={authorization_code}&state={state}

你的应用只需要按普通 HTTP 请求处理:

  1. 监听 localhost:60355/callback 路由。
  2. 从 query 中读取 codestate
  3. 校验回调中的 state 是否等于发起授权前保存的值。
  4. 校验通过后,把 code 和之前保存的 code_verifier 传给第三步换取 Token。

伪代码:

text
on GET /callback:
  code = query["code"]
  state = query["state"]

  if state != saved_state:
    return "invalid state"

  使用 code 和 saved_code_verifier 换取 Token

authorization_code 只能用于换取 Token,不是调用 OpenAPI 的访问令牌。授权码有效期为 5 分钟,且只能成功使用一次;请在收到回调后立即换取 Token,过期或重复使用都需要重新发起授权。

第三步:使用授权码换取 Token

Body 参数:

参数是否必填示例值说明
grant_typeauthorization_code固定传 authorization_code
code{authorization_code}授权回调中返回的授权码
client_id4a8bcd69-e915-4778-9583-17ad0e9e6a80OAuth 客户端 ID
redirect_urihttp://localhost:60355/callback必须与授权 URL 中的 redirect_uri 完全一致
code_verifier{code_verifier}生成 code_challenge 时使用的原始随机字符串

请求示例:

bash
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}"

响应示例:

json
{
  "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_inaccess_token 有效期,单位为秒
refresh_token刷新令牌,用于在 access_token 过期后换取新的 access_token
scope用户已授权的权限范围,多个 scope 以空格分隔

第四步:刷新 Access Token

access_token 过期时,可以使用 refresh_token 换取新的 access_token

Body 参数:

参数是否必填示例值说明
grant_typerefresh_token固定传 refresh_token
refresh_token{refresh_token}换取 Token 时返回的刷新令牌
client_id4a8bcd69-e915-4778-9583-17ad0e9e6a80OAuth 客户端 ID

请求示例:

bash
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

响应示例:

json
{
  "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:

text
Authorization: Bearer {access_token}

不需要再计算请求签名,也不需要在 REST API 请求中额外传入 client_id。服务端会从 access_token 中识别用户、OAuth 客户端和授权范围,并根据当前接口所需权限进行校验。

以下以查询港股交易日历为例:

bash
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}"

参数说明:

参数位置示例值说明
marketQueryHK市场前缀
startQuery2025-12-22起始日期,格式 yyyy-MM-dd
endQuery2025-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 连接,等价表达式如下:

text
{timestamp_ms} + "\n" +
{http_method} + "\n" +
{request_path} + "\n" +
{query_string} + "\n" +
{body_part}

不要省略中间的换行符。即使 query_stringbody_part 为空,也要保留对应字段位置和字段之间的 \n

字段说明:

字段说明
timestamp_ms当前毫秒时间戳,对应请求头 X-Timestamp
http_methodHTTP 方法,使用大写,例如 GETPOST
request_pathURL 路径,不包含域名和查询参数,例如 /api/v1.0/quote/trading-days
query_string最终请求中的原始查询串,不包含开头的 ?;没有查询参数时传空字符串
body_part请求原始 body 字节的 SHA256 小写十六进制摘要;没有请求体时传空字符串

签名必须基于最终发出的请求内容:query_string 的参数顺序和 URL 编码要与实际请求完全一致;body_part 使用原始请求体字节计算,不要重新格式化 JSON 后再计算。

以查询港股交易日历为例:

text
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 请求没有请求体,精确的签名原文为:

text
1782357937000\nGET\n/api/v1.0/quote/trading-days\nmarket=HK&start=2025-12-22&end=2025-12-26\n

按行展开后是:

text
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-KeyAppKey ID
AuthorizationBase64 编码后的签名结果。AppKey 场景请直接填写签名字符串,不要添加 Bearer 前缀
X-Timestamp客户端当前毫秒时间戳,需与签名原文中的 timestamp_ms 一致
X-Nonce客户端随机字符串,用于防重放;仅支持字母、数字、下划线和连字符,长度 1-64

以下使用 AppKey 方式调用交易日历接口:

bash
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 错误码。客户端可以通过以下接口获取服务端时间戳

bash
curl -X GET https://webapi.moomoo.com/api/v1.0/server-time

Response
{"server_time_ms":"1782971427455"}

通用约定

  • 证券标识{market}.{code},如 HK.00700US.AAPL
  • 时间:多为 Unix 毫秒时间戳,部分秒级;日期字段为标的市场时区 YYYY-MM-DD
  • 比率:百分比数值(1.23 表示 1.23%)。
  • 分页:列表类接口用 next_key / limit,详见 分页约定

下一步