diff --git a/api/changelog.md b/api/changelog.md index 45e2413..650fb89 100644 --- a/api/changelog.md +++ b/api/changelog.md @@ -5,49 +5,3 @@ slug: changelog sidebar_position: 7 --- -## 2023-08-17 - -- 更新获取账户资金接口 - - `GET /v1/asset/account` 增加入参 (currency) 字段 - -## 2023-04-12 - -- 更新获取股票持仓接口 - - `GET /v1/asset/stock` 增加开盘前初始持仓 (init_quantity) 字段 - - -## 2023-04-11 - -- 新增订单详情查询接口 - - `GET /v1/trade/order` 获取订单详情 -- 新增预估最大购买数量接口 - - `GET /v1/trade/estimate/buy_limit` 获取预估最大购买数量接口 -- 美股期权添加市价单和条件单支持 - -## 2022-07-18 - -- 更新标的基础信息接口 - - 长连接 `Business Command: 10` 响应增加 `board` 字段 - -## 2022-07-14 - -- 新增获取保证金比例接口 - - `GET /v1/risk/margin-ratio` 获取保证金比例 - -## 2022-06-30 - -- 新增获取关注分组接口 - - `GET /v1/watchlist/groups` 获取关注分组 - -## 2022-06-20 - -- 更新账号资金接口 - - `GET /v1/asset/account` 响应增加净资产 (net_assets)、初始保证金 (init_margin)、维持保证金 (maintenance_margin) 字段 -- 更新持仓接口 - - `GET /v1/asset/stock` 支持用户获取期权持仓 - -## 2022-06-15 - -- 新增行情资金流接口 - - 长连接 `Business Command:24` 获取标的当日资金流向 - - 长连接 `Business Command:25` 获取标的当日资金分布 diff --git a/api/getting-developed/error-codes.md b/api/getting-developed/error-codes.md index 61ed963..6a65c41 100644 --- a/api/getting-developed/error-codes.md +++ b/api/getting-developed/error-codes.md @@ -10,10 +10,9 @@ sidebar_position: 10 | HTTP Status | code | message | 说明 | | ----------- | ------ | ---------------------- | ---------------------------------------- | | 403 | 403201 | signature invalid | 签名无效 | -| 403 | 403202 | duplicate request | 重复请求,同一个请求没有更换 X-Timestamp | | 403 | 403203 | apikey illegal | App Key 无效 | -| 403 | 403205 | ip is not allowed | IP 地址无权访问 | -| 401 | 401003 | token expired | Access Token 已过期,请刷新 Access Token | -| 429 | 429001 | ip request ratelimit | IP 访问过于频繁,请稍后再试 | +| 403 | 403305 | ip is not allowed | IP 地址无权访问 | +| 401 | 401003 | token expired | Access Token 已过期 | +| 401 | 401004 | token invalid | token 不正确 | | 429 | 429002 | api request is limited | 接口访问过于频繁,请稍后再试 | -| 500 | 500000 | internal error | 服务内部错误,请联系客户经理进行处理 | +| 500 | 500000 | internal error | 服务内部错误,请联系客户经理进行处理 | diff --git a/api/getting-developed/how-to-access-api.md b/api/getting-developed/how-to-access-api.md index d2aa249..21b04c3 100644 --- a/api/getting-developed/how-to-access-api.md +++ b/api/getting-developed/how-to-access-api.md @@ -10,8 +10,6 @@ sidebar_position: 1 | 注意事项 | 参考文档 | | -------------------------------------------- | ------------------------------------------------- | | 推荐使用各自语言的 SDK,而不是调用原生的接口 | [SDK 快速开始页面](../docs/getting-started) | -| 阅读 OpenAPI 介绍中开通相应服务 | [OpenAPI 如何开通](../docs/#如何开通) | -| 阅读 OpenAPI 介绍中使用权限及限制 | [OpenAPI 使用权限及限制](../docs/#使用权限及限制) | | 了解通用错误码,便于查找调用接口出错的原因 | [通用错误码](../docs/error-codes) | ## REST API 文档约定格式 @@ -57,27 +55,21 @@ GET 请求时默认所有参数为查询参数,非 GET 请求时默认所有 ## API 调用流程 -### 1. 开通服务 +### 1. 获取调用 Access Token -参考 [OpenAPI 介绍](../docs/#如何开通) 开通相应服务。 +连接商务获取测试使用的 Access Token -### 2. 获取 App Key 信息及 Access Token - -在 [开发者后台](https://open.longportapp.com/account) 中获取 **Access Token**, **App Key** 以及 **App Secret**。 - -**Access Token** 的有效期是三个月,失效后可以在开发者后台重置。在失效之前,可以通过调用 [刷新 Access Token](./refresh-token-api) API 进行刷新。 - -### 3. 生成签名 +### 2. 生成签名 :::tip -本页介绍的内容大部分,我们的 [OpenAPI SDK](/sdk) 已经完整实现了,你如果是 [SDK](/sdk) 用户,可以直接忽略签名认证部分。 +本页介绍的内容大部分,我们的 [SDK](/sdk) 已经完整实现了,你如果是 [SDK](/sdk) 用户,可以直接忽略签名认证部分。 此部分内容是为了给非 SDK 用户提供参考。 ::: -先根据相应的 API 文档构造请求后,通过 OpenAPI SDK 直接调用 API,SDK 会帮助生成签名,或者通过以下流程创建签名。 +先根据相应的 API 文档构造请求后,通过 SDK 直接调用 API,SDK 会帮助生成签名,或者通过以下流程创建签名。 #### 添加 `X-Api-Key`、`X-Timestamp`、`Authorization` @@ -132,15 +124,10 @@ headers['X-Api-Signature'] = sign(method, uri, headers, params, body, secret) ``` -### 4. 调用 API +### 3. 调用 API 使用 HTTP 客户端发送签名过后的请求。 -## 基本路径 - -- HTTP API - `https://openapi.longportapp.com` -- WebSocket - `wss://openapi-quote.longportapp.com` - ## API Request 调用服务端接口需要是用 HTTPS 协议,JSON 格式,并是用 `UTF-8` 编码。 @@ -148,15 +135,15 @@ headers['X-Api-Signature'] = sign(method, uri, headers, params, body, secret) 测试接口示例如下: ```bash -curl -v https://openapi.longportapp.com/v1/test \ +curl -i -v https://openapi.longbridge.xyz/v1/test \ -H "X-Api-Signature: {签名}" -H "X-Api-Key: {Appkey}" \ -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" ``` -获取股票持仓接口是`GET`请求并需要传递参数,示例如下: +获取账户资产信息是 `GET` 请求并需要传递参数,示例如下: ```bash -curl -v https://openapi.longportapp.com/v1/asset/stock?symbol=700.HK&symbol=BABA.US \ +curl -i -v https://openapi.longbridge.xyz/v1/whaleapi/asset/detail_info?currency=HKD&account_no=xxx \ -H "X-Api-Signature: {签名}" -H "X-Api-Key: {AppKey}" \ -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" ``` @@ -164,8 +151,8 @@ curl -v https://openapi.longportapp.com/v1/asset/stock?symbol=700.HK&symbol=BABA 委托下单接口是`POST`请求并需要传递`Body`参数,示例如下: ```bash -curl -v -XPOST https://openapi.longportapp.com/v1/trade/order \ - -d '{ "side": "Buy", symbol": "700.HK", "order_type": "LO", "submitted_price": "50", "submitted_quantity": "200", "time_in_force": "Day", remark": "Hello from Shell"}' \ +curl -i -v -X POST https://openapi.longportapp.com/v1/whaleapi/trade/order \ + -d '{ "side": "Buy", symbol": "700.HK", "order_type": "LO", "submitted_price": "50", "submitted_quantity": "200", "time_in_force": "Day", "remark": "Hello from Shell", "account_no": "xxx"}' \ -H "X-Api-Signature: {签名}" -H "X-Api-Key: {AppKey}" \ -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" -H "Content-Type: application/json; charset=utf-8" @@ -219,13 +206,13 @@ import hmac # request 请求信息 # 请求方法 -method = "POST" +method = "DELETE" # 请求路径 -uri = "/v1/trade/order/submit" -# 请求参数 如 member_id=1&account_channel=2 +uri = "/v1/whalapi/trade/order" +# url query params params = "" # 请求 body -body = json.dumps({ "order_id": '683615454870679552' }) +body = json.dumps({ "order_id": '683615454870679552', "account_no": 'xxx' }) # 请求头部信息 headers = {} headers['X-Api-Key'] = '${app_key}' @@ -255,7 +242,7 @@ def sign(method, uri, headers, params, body, secret): headers['X-Api-Signature'] = sign(method, uri, headers, params, body, app_secret) # 请求接口 -response = requests.request(method, "https://openapi.longportapp.com" + uri + '?' + params, headers=headers, data=body) +response = requests.request(method, "https://openapi.longbridge.xyz" + uri + '?' + params, headers=headers, data=body) print(response.text) diff --git a/api/getting-developed/refresh-token-api.md b/api/getting-developed/refresh-token-api.md deleted file mode 100644 index cad73b6..0000000 --- a/api/getting-developed/refresh-token-api.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: 刷新 Token -id: refresh-token-api -slug: /refresh-token-api -sidebar_position: 2 ---- - -# 刷新 Access Token - -在老的 `access_token` 过期之前,通过调用此接口获取新的 `access_token`。调用成功后老的 `access_token` 就会作废。 - -> 最后更新于 2022-04-21 - -## 请求 - -| 基本信息 | | -| ----------- | ----------------- | -| HTTP URL | /v1/token/refresh | -| HTTP Method | GET | - -### 请求头 - -| 名称 | 类型 | 必须 | 描述 | -| ------------- | ------ | ---- | ---- | -| Authorization | string | 是 | | - -### 请求参数 - -| 名称 | 类型 | 必须 | 描述 | 默认值 | 示例 | -| ---------- | ------ | ---- | ---- | --------------------------------------------------------------------------- | ------------------------ | -| expired_at | string | 是 | 格式 | 过期时间戳,格式遵循 [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) 规范 | 2023-04-14T12:13:57.859Z | - -## 响应 - -### 响应体 - -| 名称 | 类型 | 描述 | -| ----------------- | ------ | --------------------- | -| code | int | 错误码,非 0 表示失败 | -| msg | string | 错误描述 | -| data | object | | -| ∟token | string | 新的 access_token | -| ∟expired_at | string | 过期的时间戳 | -| ∟issued_at | string | 颁发时间 | -| ∟account_info | object | 用户信息 | -| ∟∟member_id | string | 用户 id | -| ∟∟aaid | string | aaid | -| ∟∟account_channel | string | account_channel | - -### 响应体示例 - -```json -{ - "code": 0, - "message": "", - "data": { - "token": "xxxxxx", - "expired_at": "2022-05-14T12:13:57.859Z", - "issued_at": "2022-04-14T12:13:57.859Z", - "account_info": { - "member_id": 123, - "aaid": 13, - "account_channel": "lb" - } - } -} -``` diff --git a/api/getting-started.md b/api/getting-started.md index 3ce4e13..7e920dc 100644 --- a/api/getting-started.md +++ b/api/getting-started.md @@ -10,17 +10,7 @@ import TabItem from '@theme/TabItem'; ## 前言 -[LongPort OpenAPI SDK](https://github.com/longbridgeapp/openapi-sdk) 基于 Rust 底层提供标准实现,目前我们已经发布了 Python、Node.js、Rust、C++ 的 SDK,其他语言的支持后面会陆续推出。 - -## API Host - -- HTTP API - `https://openapi.longportapp.com` -- WebSocket Quote - `wss://openapi-quote.longportapp.com` -- WebSocket Trade - `wss://openapi-trade.longportapp.com` - -:::info -中国大陆地区访问,建议采用 `openapi.longportapp.cn`, `openapi-quote.longportapp.cn`, `openapi-trade.longportapp.cn` 以提升访问速度。 -::: +[Whale API SDK](https://github.com/longbridgeapp/openapi-sdk) 基于 Rust 底层提供标准实现,目前我们已经发布了 Python、Node.js、Rust、C++、[Golang](https://github.com/longbridgeapp/openapi-go) 的 SDK,其他语言的支持后面会陆续推出。 ## 环境需求 @@ -29,7 +19,7 @@ import TabItem from '@theme/TabItem';
  • Python 3
  • Pip
  • - +
  • Node.js
  • Yarn
  • @@ -40,6 +30,9 @@ import TabItem from '@theme/TabItem';
  • JDK
  • Maven
  • + +
  • Golang
  • +
    ## 安装 SDK @@ -52,7 +45,7 @@ pip3 install longbridge ``` - + ```bash yarn install longbridge @@ -81,156 +74,99 @@ tokio = { version = "1", features = "rt-multi-thread" } ``` - - -下面我们以获取资产为例,演示一下如何使用 SDK。 - -## 配置开发者账户 + -1. 下载 [LongPort](https://longportapp.com/download),并完成开户 -2. 完成 Python 3 环境安装,并安装 Pip -3. 从 [LongPort OpenAPI](https://open.longportapp.com) 官网获取 ` App Key`, `App Secret`, `Access Token` 等信息。 - -**_获取 App Key, App Secret, Access Token 等信息_** - -访问 [LongPort OpenAPI](https://open.longportapp.com) 网站,登录后,进入“个人中心”。 - -在页面上会给出“应用凭证”凭证信息,我们拿到以后设置环境变量,便于后面开发使用方便。 - -### macOS / Linux 环境下设置环境变量 - -打开终端,输入下面的命令即可: - -```bash -$ export LONGBRIDGE_APP_KEY="从页面上获取到的 App Key" -$ export LONGBRIDGE_APP_SECRET="从页面上获取到的 App Secret" -$ export LONGBRIDGE_ACCESS_TOKEN="从页面上获取到的 Access Token" +```shell +go get github.com/longbridgeapp/openapi-go ``` -### Windows 下设置环境变量 - -Windows 要稍微复杂一些,按下 `Win + R` 快捷键,输入 `cmd` 命令启动命令行(建议使用 [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701) 获得更好的开发体验)。 - -在命令行里面输入下面的命令设置环境变量: - -```bash -C:\Users\jason> setx LONGBRIDGE_APP_KEY "从页面上获取到的 App Key" -成功:指定的值已得到保存。 - -C:\Users\jason> setx LONGBRIDGE_APP_SECRET "从页面上获取到的 App Secret" -成功:指定的值已得到保存。 - -C:\Users\jason> setx LONGBRIDGE_ACCESS_TOKEN "从页面上获取到的 Access Token" -成功:指定的值已得到保存。 -``` - -:::caution - -Windows 环境变量限制,当上面 3 条命令执行成功以后,你需要重新启动 Windows 或者注销后重新登录一次,才可以读取到。 - -::: + -注销或重新启动后,再次打开命令行,输入下面的命令验证一下环境变量是否设置正确: + -```bash -C:\Users\jason> set LONGBRIDGE -LONGBRIDGE_APP_KEY=xxxxxxx -LONGBRIDGE_APP_SECRET=xxxxxx -LONGBRIDGE_ACCESS_TOKEN=xxxxxxx -``` +下面我们以获取资产为例,演示一下如何使用 SDK。 -如果能正确打印你刚才设置的值,那么环境变量就是对了。 +## 获取 Access Token -:::tip -建议您设置好 `LONGBRIDGE_APP_KEY`, `LONGBRIDGE_APP_SECRET`, `LONGBRIDGE_ACCESS_TOKEN` 这几个环境变量。我们为了演示方便,后面各章节文档中的示例代码都会使用这几个环境变量。 +请联系商务来获取 Whale API 的测试 Access Token -如您在 Windows 环境不方便使用环境变量,可根据个人需要,修改代码。 -::: +配置 Access Token 和请求 Endpoint 有两种方式: -:::caution -请注意保护好您的 **Access Token** 信息,任何人获得到它,都可以通过 OpenAPI 来交易你的账户! -::: +- 代码里面构造配置对象 +- 环境变量 -## 场景示范 +### 构造配置对象 -### 获取资产总览 +SDK 提供了配置的构造方法: -创建 `account_asset.py` 贴入下面的代码: - ```python -from longbridge.openapi import TradeContext, Config +from longbridge.openapi import TradeContext, Config, HttpClient -config = Config.from_env() -ctx = TradeContext(config) +# get config fields from config file or env or some secret management system +key = "xxx" +secret = "xxx" +token = "xxx" +http_url = "https://openapi.longbridge.xyz" +trade_url = "wss://openapi-trade.longbridge.xyz" -resp = ctx.account_balance() -print(resp) -``` - -运行 - -```bash -python account_asset.py +conf = Config(app_key = key, app_secret = secret, access_token = token, http_url = http_url, trade_ws_url = trade_url) +http_cli = HttpClient(app_key = conf.app_key, app_secret = conf.app_secret, http_url = conf.http_url) +ctx = TradeContext(conf) ``` - + -创建 `account_asset.js` 贴入下面的代码: - -```js -const { Config, TradeContext } = require('longbridge') - -let config = Config.fromEnv() -TradeContext.new(config) - .then((ctx) => ctx.accountBalance()) - .then((resp) => { - for (let obj of resp) { - console.log(obj.toString()) - } - }) -``` +```javascript +import { Config, HttpClient, TradeContext } from 'longbridge' + +const conf = new Config({ + appKey: 'xxx', + appSecret: 'xxx', + accessToken: 'xxx', + httpUrl: 'https://openapi.longbridge.xyz', + tradeWsUrl: 'wss://openapi-trade.longbridge.xyz' +}) -运行 +const httpClient = new HttpClient(conf.httpUrl, conf.appKey, conf.appSecret, conf.accessToken) -```bash -node account_asset.js +try { + const ctx = TradeContext.new(conf) +} catch (e) { + ... +} ``` - - - -创建 `main.rs` 贴入下面的代码: + + ```rust use std::sync::Arc; +use serde_json::json; -use longbridge::{trade::TradeContext, Config}; +use longbridge::trade::{TradeContext}; +use longbridge::{httpclient::HttpClient, Config}; -#[tokio::main] -async fn main() -> Result<(), Box> { - let config = Arc::new(Config::from_env()?); - let (ctx, _) = TradeContext::try_new(config).await?; +# [tokio::main] - let resp = ctx.account_balance().await?; - println!("{:?}", resp); - Ok(()) +async fn main() -> Result<(), Box> { + let conf = Config::new("appKey", "appSecret", "accessToken") + .http_url("https://openapi.longbridge.xyz") + .trade_ws_url("wss://openapi-trade.longbridge-xyz"); + let http_cli = conf.create_http_client(); + + let (ctx, receiver) = TradeContext::try_new(Arc::new(conf)).await?; + // do sth + Ok(()); } -``` - -运行 -```bash -cargo run ``` - - -创建 `Main.java` 贴入下面的代码: + ```java import com.longbridge.*; @@ -238,295 +174,224 @@ import com.longbridge.trade.*; class Main { public static void main(String[] args) throws Exception { - try (Config config = Config.fromEnv(); TradeContext ctx = TradeContext.create(config).get()) { - for (AccountBalance obj : ctx.getAccountBalance().get()) { - System.out.println(obj); - } + try ( + Config config = new ConfigBuilder("appkey", "appsecret", "accessToken") + .HttpUrl("https://openapi.longbridge.xyz") + .tradeWebsocketUrl("wss://openapi-trade.longbridge.xyz") + .build(); + TradeContext ctx = TradeContext.create(config).get(); + HttpClient cli = new HttpClient("https://openapi.longbridge.xyz", "appkey", "appsecret", "accesstoken"); + ) { + ctx.subscribe(new TopicType[] { TopicType.Private}); + ctx.setOnOrderChange((PushOrderChanged orderEvent) -> { + logger.info("receive order change event: {}", orderEvent); + }); + // do sth } } } -``` - -运行 - -```bash -mvn compile exec:exec ``` - - -运行后,会输出如下: - -``` -[ - AccountBalance { - total_cash: 503898884.81, - max_finance_amount: 0.00, - remaining_finance_amount: 501403229.49, - risk_level: Some(1), - margin_call: 0, - currency: "HKD", - cash_infos: [ - CashInfo { - withdraw_cash: 501214985.15, - available_cash: 501214985.15, - frozen_cash: 584438.25, - settling_cash: -3897793.90, - currency: "HKD", - }, - CashInfo { - withdraw_cash: -25546.89, - available_cash: -25546.89, - frozen_cash: 295768.57, - settling_cash: 2326.60, - currency: "USD", - } - ] - } -] -``` - -### 订阅实时行情 - -订阅行情数据请检查 [开发者中心](https://open.longportapp.com/account) - “行情权限”是否正确 - -- 港股 - BMP 基础报价,无实时行情推送,无法用 WebSocket 订阅 -- 美股 - LV1 纳斯达克最优报价 (只限 Open API) - -运行前访问 [开发者中心](https://open.longportapp.com/account),检查确保账户有正确的行情权限。 - -:::info - -如没有开通行情权限,可以通过“LongPort”手机客户端,并进入“我的 - 我的行情 - 行情商城”购买开通行情权限。 - -https://longportapp.com/download -::: - -当你有正确的行情权限,看起来可能会是这样: + - +```go +package main - - +import ( + "context" + "log" + "time" + "encoding/json" -创建 `subscribe_quote.py` 贴入下面的代码: + "github.com/longbridgeapp/openapi-go/config" + "github.com/longbridgeapp/openapi-go/http" + "github.com/longbridgeapp/openapi-go/trade" +) -```python -from time import sleep -from longbridge.openapi import QuoteContext, Config, SubType, PushQuote +func main() { + + conf := Config{ + HttpURL: "https://openapi.longbridge.xyz", + AppKey: "appkey", + AppSecret: "appsecret", + AccessToken: "accesstoken", + TradeUrl: "wss://openapi-trade.longbridge.xyz", + } -def on_quote(symbol: str, quote: PushQuote): - print(symbol, quote) + tctx, err := trade.NewFromCfg(conf) + if err != nil { + log.Fatal(err) + } -config = Config.from_env() -ctx = QuoteContext(config) -ctx.set_on_quote(on_quote) + httpcli, err := http.NewFromCfg(conf) + if err != nil { + log.Fatal(err) + } +} -symbols = ["700.HK", "AAPL.US", "TSLA.US", "NFLX.US"] -ctx.subscribe(symbols, [SubType.Quote], True) -sleep(30) ``` -运行 + -```bash -python subscribe_quote.py -``` + - - +### 环境变量 -创建 `subscribe_quote.js` 贴入下面的代码: +环境变量说明 -```javascript -const { Config, QuoteContext, SubType } = require('longbridge') +| 环境变量| 说明 | 例子 | +|---------------- | --------------- | :--------------- | +| LONGBRIDGE_APP_KEY | access key | access_key | +| LONGBRIDGE_APP_SECRET | access secret key | access_secret_key | +| LONGBRIDGE_ACCESS_TOKEN | access token | tn_xxx | +| LONGBRIDGE_HTTP_URL | API Endpoint | | +| LONGBRIDGE_TRADE_WS_URL | Websocket Endpoint | wss://openapi-trade.longbridge.xyz | -let config = Config.fromEnv() -QuoteContext.new(config).then((ctx) => { - ctx.setOnQuote((_, event) => console.log(event.toString())) - ctx.subscribe(['700.HK', 'AAPL.US', 'TSLA.US', 'NFLX.US'], [SubType.Quote], true) -}) -``` +#### macOS / Linux 环境下设置环境变量 -运行 +打开终端,输入下面的命令即可: ```bash -node subscribe_quote.js +export LONGBRIDGE_APP_KEY="获取到的 Access Key" +export LONGBRIDGE_APP_SECRET="获取到 的 Access Secret Key" +export LONGBRIDGE_ACCESS_TOKEN="获取到的 Access Token" +export LONGBRIDGE_HTTP_URL="https://openapi.longbridge.xyz" # 测试 Whale API +export LONGBRIDGE_TRADE_WS_URL="wss://openapi-trade.longbridge.xyz" # 测试 Whale API Websocket ``` - - +#### Windows 下设置环境变量 -创建 `main.rs` 贴入下面的代码: +Windows 要稍微复杂一些,按下 `Win + R` 快捷键,输入 `cmd` 命令启动命令行(建议使用 [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701) 获得更好的开发体验)。 -```rust -use std::sync::Arc; +在命令行里面输入下面的命令设置环境变量: -use longbridge::{ - quote::{QuoteContext, SubFlags}, - Config, -}; +```bash +C:\Users\jason> setx LONGBRIDGE_APP_KEY "获取到的 App Key" +成功:指定的值已得到保存。 -#[tokio::main] -async fn main() -> Result<(), Box> { - let config = Arc::new(Config::from_env()?); - let (ctx, mut receiver) = QuoteContext::try_new(config).await?; +C:\Users\jason> setx LONGBRIDGE_APP_SECRET "获取到的 App Secret" +成功:指定的值已得到保存。 - ctx.subscribe( - ["700.HK", "AAPL.US", "TSLA.US", "NFLX.US"], - SubFlags::QUOTE, - true, - ) - .await?; +C:\Users\jason> setx LONGBRIDGE_ACCESS_TOKEN "获取到的 Access Token" +成功:指定的值已得到保存。 - while let Some(event) = receiver.recv().await { - println!("{:?}", event); - } - Ok(()) -} -``` +C:\Users\jason> setx LONGBRIDGE_HTTP_URL "https://openapi.longbridge.xyz" +成功:指定的值已得到保存。 -运行 +C:\Users\jason> setx LONGBRIDGE_TRADE_WS_URL "https://openapi-trade.longbridge.xyz" +成功:指定的值已得到保存。 -```bash -cargo run ``` - - +:::caution -创建 `Main.java` 贴入下面的代码: +Windows 环境变量限制,当上面命令都执行成功以后,你需要重新启动 Windows 或者注销后重新登录一次,才可以读取到。 -```java -import com.longbridge.*; -import com.longbridge.quote.*; - -class Main { - public static void main(String[] args) throws Exception { - try (Config config = Config.fromEnv(); QuoteContext ctx = QuoteContext.create(config).get()) { - ctx.setOnQuote((symbol, quote) -> { - System.out.printf("%s\t%s\n", symbol, quote); - }); - ctx.subscribe(new String[] { "700.HK", "AAPL.US", "TSLA.US", "NFLX.US" }, SubFlags.Quote, true).get(); - Thread.sleep(30000); - } - } -} -``` +::: -运行 +注销或重新启动后,再次打开命令行,输入下面的命令验证一下环境变量是否设置正确: ```bash -mvn compile exec:exec +C:\Users\jason> set LONGBRIDGE +LONGBRIDGE_APP_KEY=xxxxxxx +LONGBRIDGE_APP_SECRET=xxxxxx +LONGBRIDGE_ACCESS_TOKEN=xxxxxxx +LONGBRIDGE_HTTP_URL=https://openapi.longbridge.xyz +LONGBRIDGE_TRADE_WS_URL=https://openapi-trade.longbridge.xyz ``` - - +如果能正确打印你刚才设置的值,那么环境变量就是对了。 -运行后,会输出如下: +:::tip +建议您设置好 `LONGBRIDGE_APP_KEY`, `LONGBRIDGE_APP_SECRET`, `LONGBRIDGE_ACCESS_TOKEN`, `LONGBRIDGE_HTTP_URL`, `LONGBRIDGE_TRADE_WS_URL` 这几个环境变量。我们为了演示方便,后面各章节文档中的示例代码都会使用这几个环境变量。 -``` -700.HK PushQuote { - last_done: 367.000, - open: 362.000, - high: 369.400, - low: 356.000, - timestamp: "2022-06-06T08:10:00Z", - volume: 22377421, - turnover: 8081883405.000, - trade_status: Normal, - trade_session: Normal -} -AAPL.US PushQuote { - last_done: 147.350, - open: 150.700, - high: 151.000, - low: 146.190, - timestamp: "2022-06-06T11:57:36Z", - volume: 3724407, - turnover: 550606662.815, - trade_status: Normal, - trade_session: Pre -} -NFLX.US PushQuote { - last_done: 201.250, - open: 205.990, - high: 205.990, - low: 200.110, - timestamp: "2022-06-06T11:57:26Z", - volume: 137821, - turnover: 27888085.590, - trade_status: Normal, - trade_session: Pre -} -``` +如您在 Windows 环境不方便使用环境变量,可根据个人需要,修改代码。 +::: -### 委托下单 +## 调用例子 -下面我们做一次 [委托下单](https://open.longportapp.com/docs/trade/order/submit) 动作,我们假设要以 50 HKD 买入 `700.HK` 的数量为 `100`。 +### 下单 -> NOTE: 为了防止测试买入成功,这里演示给了一个较低的价格,避免成交。OpenAPI 操作均等同与线上交易,请谨慎操作,开发调试注意参数细节。 +我们下单通过 HTTP Client 调用 HTTP API,通过通过 Websocket 订阅订单的状态变更。 -创建 `submit_order.py` 贴入下面的代码: +创建 `whale.py` 贴入下面的代码: ```python -from decimal import Decimal -from longbridge.openapi import TradeContext, Config, OrderSide, OrderType, TimeInForceType +from longbridge.openapi import TradeContext, Config, HttpClient, PushOrderChanged config = Config.from_env() +httpcli = HttpClient.from_env() ctx = TradeContext(config) -resp = ctx.submit_order( - side=OrderSide.Buy, - symbol="700.HK", - order_type=OrderType.LO, - submitted_price=Decimal("50"), - submitted_quantity=200, - time_in_force=TimeInForceType.Day, - remark="Hello from Python SDK", -) -print(resp) +ctx.subscribe(["private"]) + + +def on_order_changed(event: PushOrderChanged): + print() + +ctx.set_on_order_changed(on_order_changed) + +resp = httpcli.request("POST", "/v1/whaleapi/trade/order", { + "symbol": "TSLA", + "side": "Buy", + "order_type": "MO", + "submitted_quantity": "20", + "time_in_force": "Day", + "account_no": "L6VQEU00121996" +}) + ``` 运行 ```bash -python submit_order.py +python whale.py ``` - + -创建 `submit_order.js` 贴入下面的代码: +创建 `whale.js` 贴入下面的代码: + +```js +import { Config, TradeContext, HttpClient, TopicType } from 'longbridge' + +const config = Config.fromEnv() +const httpcli = HttpClient.fromEnv() + +try { + const ctx = await TradeContext.new(config) + ctx.subscribe([TopicType.Private]) + ctx.setOnOrderChanged((event) => { + // handle order changed event + console.dir(event) + }) + + const resp = await httpcli.request("POST", "/v1/whaleapi/trade/order", { + "symbol": "TSLA", + "side": "Buy", + "order_type": "MO", + "submitted_quantity": "20", + "time_in_force": "Day", + "account_no": "L6VQEU00121996" + }) + +} catch(e) { + // handle error +} -```javascript -const { Config, TradeContext, OrderType, OrderSide, Decimal, TimeInForceType } = require('longbridge') - -let config = Config.fromEnv() -TradeContext.new(config) - .then((ctx) => - ctx.submitOrder({ - symbol: '700.HK', - orderType: OrderType.LO, - side: OrderSide.Buy, - timeInForce: TimeInForceType.Day, - submittedQuantity: 200, - submittedPrice: new Decimal('300'), - }) - ) - .then((resp) => console.log(resp.toString())) ``` 运行 ```bash -node submit_order.js +node whale.js ``` @@ -536,29 +401,37 @@ node submit_order.js ```rust use std::sync::Arc; +use serde_json::json; -use longbridge::{ - decimal, - trade::{OrderSide, OrderType, SubmitOrderOptions, TimeInForceType, TradeContext}, - Config, -}; +use longbridge::trade::{TradeContext, TopicType}; +use longbridge::{httpclient::HttpClient, Config}; #[tokio::main] async fn main() -> Result<(), Box> { let config = Arc::new(Config::from_env()?); - let (ctx, _) = TradeContext::try_new(config).await?; - - let opts = SubmitOrderOptions::new( - "700.HK", - OrderType::LO, - OrderSide::Buy, - 200, - TimeInForceType::Day, - ) - .submitted_price(decimal!(50i32)); - let resp = ctx.submit_order(opts).await?; - println!("{:?}", resp); - Ok(()) + let httpcli = HttpClient::from_env()?; + let (ctx, receiver) = TradeContext::try_new(config).await?; + ctx.subscribe([TopicType.Private]).await?; + + let resp = httpcli.request("POST".parse()?, "/v1/whaleapi/trade/order") + .body(json!{ + "symbol": "TSLA", + "side": "Buy", + "order_type": "MO", + "submitted_quantity": "20", + "time_in_force": "Day", + "account_no": "L6VQEU00121996" + }) + .response::() + .send() + .await?; + println!("{}", resp); + + while let Some(event) = receiver.recv().await { + println!("{:?}", event); + } + + Ok(()); } ``` @@ -576,18 +449,28 @@ cargo run ```java import com.longbridge.*; import com.longbridge.trade.*; -import java.math.BigDecimal; -public class Main { +class Main { public static void main(String[] args) throws Exception { - try (Config config = Config.fromEnv(); TradeContext ctx = TradeContext.create(config).get()) { - SubmitOrderOptions opts = new SubmitOrderOptions("700.HK", - OrderType.LO, - OrderSide.Buy, - 200, - TimeInForceType.Day).setSubmittedPrice(new BigDecimal(50)); - SubmitOrderResponse resp = ctx.submitOrder(opts).get(); - System.out.println(resp); + try ( + Config config = Config.fromEnv(); + TradeContext ctx = TradeContext.create(config).get(); + HttpClient cli = HttpClient.fromEnv() + ) { + ctx.subscribe(new TopicType[] { TopicType.Private}); + ctx.setOnOrderChange((PushOrderChanged orderEvent) -> { + logger.info("receive order change event: {}", orderEvent); + }); + + HashMap req = new HashMap(); + req.put("symbol", "TSLA.US"); + req.put("order_type", "MO"); // Market Order + req.put("side", "Buy"); + req.put("submitted_quantity", "20"); + req.put("time_in_force", "Day"); + req.put("account_no", "L6VQEU00121996"); // Test Account Number + + HashMap submitRes = cli.request(HashMap.class, "POST", "/v1/whaleapi/trade/order", req).get(); } } } @@ -600,168 +483,92 @@ mvn compile exec:exec ``` - + -运行后,会输出如下: +创建 whale 目录,执行 -``` -SubmitOrderResponse { order_id: "718437534753550336" } +```shell +cd whale +go mod init whale +go get github.com/longbridgeapp/openapi-go ``` -### 获取当日订单 +创建 `main.go`,贴入一下内容: - - - -创建 `today_orders.py` 贴入下面的代码: - -```python -from longbridge.openapi import TradeContext, Config - -config = Config.from_env() -ctx = TradeContext(config) - -resp = ctx.today_orders() -print(resp) -``` +```go +package main -运行 +import ( + "context" + "log" + "time" + "encoding/json" -```bash -python today_orders.py -``` + "github.com/longbridgeapp/openapi-go/config" + "github.com/longbridgeapp/openapi-go/http" + "github.com/longbridgeapp/openapi-go/trade" +) - - -创建 `today_orders.js` 贴入下面的代码: +func main() { + conf, err := config.NewFromEnv() -```js -const { Config, TradeContext } = require('longbridge') - -let config = Config.fromEnv() -TradeContext.new(config) - .then((ctx) => ctx.todayOrders()) - .then((resp) => { - for (let obj of resp) { - console.log(obj.toString()) + if err != nil { + log.Fatal(err) } - }) -``` -运行 - -```bash -node today_orders.js -``` - - - - -创建 `main.rs` 贴入下面的代码: - -```rust -use std::sync::Arc; - -use longbridge::{trade::TradeContext, Config}; - -#[tokio::main] -async fn main() -> Result<(), Box> { - let config = Arc::new(Config::from_env()?); - let (ctx, _) = TradeContext::try_new(config).await?; + tctx, err := trade.NewFromCfg(cfg) - let resp = ctx.today_orders(None).await?; - for obj in resp { - println!("{:?}", obj); + if err != nil { + log.Fatal(err) } - Ok(()) -} -``` -运行 - -```bash -cargo run -``` - - - + httpcli, err := http.NewFromCfg(cfg) + if err != nil { + log.Fatal(err) + } -创建 `Main.java` 贴入下面的代码: + if _, err = tctx.Subscribe(context.Background(), []string{"private"}); err != nil { + log.Fatal(err) + } -```java -import com.longbridge.*; -import com.longbridge.trade.*; + tctx.OnTrade(func(ev *trade.PushEvent) { + log.Printf("got event: %+v\n", ev.Data) + }) -class Main { - public static void main(String[] args) throws Exception { - try (Config config = Config.fromEnv(); TradeContext ctx = TradeContext.create(config).get()) { - Order[] orders = ctx.getTodayOrders(null).get(); - for (Order order : orders) { - System.out.println(order); - } - } + var resp json.RawMessage + if err := httpcli.Call(context.Background(), "POST", "/v1/whaleapi/trade/order", nil, map[string]interface{ + "symbol": "TSLA", + "side": "Buy", + "order_type": "MO", + "submitted_quantity": "20", + "time_in_force": "Day", + "account_no": "L6VQEU00121996", + }, &resp); err != nil { + log.Fatal(err) } + + time.Sleep(time.Second * 5) } ``` 运行 -```bash -mvn compile exec:exec -``` +```shell +go run ./ - - - -运行后,会输出如下: - -``` -Order { - order_id: "718437534753550336", - status: NotReported, - stock_name: "腾讯控股 1", - quantity: 200, - executed_quantity: None, - price: Some(50.000), - executed_price: None, - submitted_at: 2022-06-06T12:14:16Z, - side: Buy, - symbol: "700.HK", - order_type: LO, - last_done: None, - trigger_price: Some(0.000), - msg: "", - tag: Normal, - time_in_force: Day, - expire_date: Some(NaiveDate(Date { year: 2022, ordinal: 158 })), - updated_at: Some(2022-06-06T12:14:16Z), - trigger_at: None, - trailing_amount: None, - trailing_percent: None, - limit_offset: None, - trigger_status: None, - currency: "HKD", - outside_rth: nonce -} ``` -上面例子已经完整演示了如何使用 SDK 访问 OpenAPI 的接口,更多其他接口请详细阅读 [LongPort OpenAPI 文档](https://longbridgeapp.github.io/openapi-sdk/),根据不同的接口使用。 - -## 更多例子 + -我们在 LongPort OpenAPI Python SDK 的 GitHub 仓库中提供了上面几个例子的完整代码,当然后期我们也会持续往里面补充或更新。 + -https://github.com/longbridgeapp/openapi-sdk/tree/master/examples +上面例子已经完整演示了如何使用 SDK 访问 Whale API 的接口。 ## SDK API 文档 SDK 的详细 API 文档请访问: -https://longbridgeapp.github.io/openapi-sdk/ + ## 反馈及沟通 - -- 可以给 LongPort 服务邮箱发送反馈,邮箱地址是:service@longbridge.global -- 加入 LongPort OpenAPI 微信沟通群,二维码如下: - diff --git a/api/index.md b/api/index.md index 2b1d766..a21ec0b 100644 --- a/api/index.md +++ b/api/index.md @@ -1,7 +1,7 @@ --- sidebar_position: -999 slug: / -title: OpenAPI 介绍 +title: Whale API 介绍 id: getting_started_introduce --- @@ -10,53 +10,8 @@ import TabItem from '@theme/TabItem'; ## 简介 -LongPort OpenAPI 为有研发能力的投资者提供程序化行情交易接口,助力投资者根据自身投资策略搭建交易或行情策略分析工具。覆盖以下类别功能: - -- 交易类 - 创建、修改、撤销订单,当日/历史订单及成交记录的查询等 -- 行情类 - 实时行情报价、历史行情数的获取等 -- 资产类 - 实时账户资产、持仓、现金查询等 -- 实时订阅 - 提供行情实时报价以及订单状态实时变更信息推送 +Whale API 是面向券商提供的一套高级接口能力,券商可以选择通过自研或者采购第三方研发平台完成开发对接 Whale API 实现展业能力。 ## 接口类型 -LongPort 提供接入底层服务的 HTTP / WebSockets 接口以及封装在上层的 SDK(Python / C++ ...)等多种接入方式,灵活选择。 - -## 如何开通 - -1. 登录 [LongPort App](https://longportapp.com/download) 完成开户; -2. 登录 [longportapp.com](https://longportapp.com) 进入开发者平台,完成开发者认证即 OpenAPI 权限申请,获取令牌。 - -## 使用权限及限制 - -:::caution - -所有的接口都是有最小间隔限制的,所以理论上同一个接口都是不支持并发调用。 - -::: - -### 交易类 - -| 市场 | 股票 ETF | 权证 | 期权 | -| -------- | -------- | ---- | ---- | -| 香港市场 | ✓ | ✓ | | -| 美国市场 | ✓ | ✓ | ✓ | - -#### 频次限制 - -:::caution - -- 30 秒内不超过 30 次调用,且每两次调用之间间隔不小于 0.02 秒 - -::: - -### 行情类 - -请访问阅读:[行情权限与限制](/api/quote/level) - -## 使用费用 - -LongPort 不针对接口服务额外收取开通或使用费用,只需开通 LongPort 账户及 OpenAPI 服务权限后即可免费使用。实际交易产生佣金费用或高级行情产品费用参考 [官网收费](https://longbridge.hk/rate) 说明或咨询线上客服。 - -## 其他 - -OpenAPI 服务由 LongPort 及其适用的关联公司提供(具体以协议为准)。 +Whale API 提供接入底层服务的 HTTP 接口,同时提供 WebSockets 长连接来同步订单状态。 diff --git a/api/qa/_category_.json b/api/qa/_category_.json deleted file mode 100644 index d256a72..0000000 --- a/api/qa/_category_.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "label": "Q&A", - "collapsible": true, - "collapsed": true, - "link": null, - "position": 6 -} diff --git a/api/qa/quote.md b/api/qa/quote.md deleted file mode 100644 index a81b933..0000000 --- a/api/qa/quote.md +++ /dev/null @@ -1,151 +0,0 @@ ---- -id: quote_qa -title: 行情相关 -slug: broker -sidebar_position: 1 ---- - -## Q1:订阅额度怎么算的,同一个标的订阅盘口,经济队列,是算 1 个还是多个? - -A:仅按照标的维度计算订阅额度,同一个标的同时订阅多种行情,算同一个订阅额度。 - -## Q2:请求限频的具体限制逻辑是怎样? - -A:使用令牌桶进行限流,控制请求速率。1 秒内不超过 10 次调用,并发请求数不超过 5。 - -## Q3:目前可以订阅的标的(包括指数)和对应的 symbol 格式? - -A:标的代码使用 `ticker.region` 格式,`ticker` 表示标的代码。支持订阅的标的如下: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    市场标的TickerRegion
    港股市场证券类产品(含股票、ETFs、窝轮、牛熊、界内证)标的在交易所的官方代码HK
    恒生指数HSIHK
    国企指数HSCEIHK
    恒生科技指数HSTECHHK
    美股市场证券类产品(含纽交所、美交所、纳斯达克上市的股票、ETFs)标的在交易所的官方代码US
    纳斯达克指数.IXICUS
    道琼斯指数.DJIUS
    A 股市场证券类产品(含股票、ETFs)标的在交易所的官方代码SH 或 SZ
    指数标的在交易所的官方代码SH 或 SZ
    - -可以使用 LongPort App 查看标的的 symbol - - -## Q4:OpenAPI 的行情权限是怎么样?如何购买行情卡? - -A: - -- 行情权限 - 应交易所规则,OpenAPI 的权限是独立的,和 LongPort 的 App、PC、Web 权限不共享。比如,你在 Longbrdge App 上拥有的港股 Level 2 权限并不能同样代入 OpenAPI 端使用。LongPort 也给 OpenAPI 用户赠送了基础的行情权益,如你需要更高级别的行情,可以通过购买行情卡激活高级别行情权限。 -- 如何购买行情卡 - LongPort 用户可以通过 LongPort App 中的「行情商店」自行选择想要购买的行情卡。 -- 行情权限一览请见下表 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    市场标的权限获取方式
    港股市场证券类产品(含股票、ETFs、窝轮、牛熊、界内证) - -
    恒生指数
    美股市场证券类产品(含纽交所、美交所、纳斯达克上市的股票、ETFs) - -
    纳斯达克指数
    OPRA 期权 - -
    A 股市场证券类产品(含股票、ETFs) -
      -
    • 中国大陆个人客户:免费获取 Lv1 行情
    • -
    • 非中国大陆客户 / 机构客户:暂不支持
    • -
    -
    指数
    - -## Q5:各个市场的清盘时间 - -A: - -- 美股市场:09:20:00 EST -- 港股市场:08:50:00 CST -- A 股市场:09:00:00 CST -- 新加坡市场:08:20:00 CST diff --git a/docusaurus.config.js b/docusaurus.config.js index e96c92a..458e51a 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -19,7 +19,7 @@ const config = { markdown: { mermaid: true, }, - themes: ['@docusaurus/theme-mermaid'], + themes: ['@docusaurus/theme-mermaid', '@saucelabs/theme-github-codeblock'], i18n, customFields: { isDev: process.env.STAGE === 'dev', diff --git a/package.json b/package.json index f8d5035..f8f8abb 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,8 @@ "react": "17.0.2", "react-dom": "17.0.2", "react-photo-view": "^1.0.0", - "tailwindcss": "^3.3.0" + "tailwindcss": "^3.3.0", + "url": "^0.11.3" }, "devDependencies": { "@docusaurus/module-type-aliases": "^2.4.3", diff --git a/yarn.lock b/yarn.lock index 0e8928e..74891e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3913,20 +3913,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001317: - version "1.0.30001331" - resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001331.tgz#41048f2a5cf0c3c6198f40207cd323388b3d4399" - integrity sha512-Y1xk6paHpUXKP/P6YjQv1xqyTbgAP05ycHBcRdQjTcyXlWol868sJJPlmk5ylOekw2BrucWes5jk+LvVd7WZ5Q== - -caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.30001335: - version "1.0.30001346" - resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001346.tgz#e895551b46b9cc9cc9de852facd42f04839a8fbe" - integrity sha512-q6ibZUO2t88QCIPayP/euuDREq+aMAxFE5S70PkrLh0iTDj/zEhgvJRKC2+CvXY6EWc6oQwUR48lL5vCW6jiXQ== - -caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001464: - version "1.0.30001472" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001472.tgz#3f484885f2a2986c019dc416e65d9d62798cdd64" - integrity sha512-xWC/0+hHHQgj3/vrKYY0AAzeIUgr7L9wlELIcAvZdDUHlhL/kNxMdnQLOSOQfP8R51ZzPhmHdyMkI0MMpmxCfg== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001317, caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.30001335, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001464: + version "1.0.30001561" + resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz" + integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw== ccount@^1.0.0: version "1.1.0" @@ -7406,6 +7396,11 @@ object-hash@^3.0.0: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== +object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -8275,7 +8270,7 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^1.3.2: +punycode@^1.3.2, punycode@^1.4.1: version "1.4.1" resolved "https://registry.npmmirror.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== @@ -8302,6 +8297,13 @@ qs@6.9.7: resolved "https://registry.npmmirror.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== +qs@^6.11.2: + version "6.11.2" + resolved "https://registry.npmmirror.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + dependencies: + side-channel "^1.0.4" + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -9205,6 +9207,15 @@ should@^13.2.1: should-type-adaptors "^1.0.1" should-util "^1.0.0" +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.7" resolved "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" @@ -10004,6 +10015,14 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" +url@^0.11.3: + version "0.11.3" + resolved "https://registry.npmmirror.com/url/-/url-0.11.3.tgz#6f495f4b935de40ce4a0a52faee8954244f3d3ad" + integrity sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw== + dependencies: + punycode "^1.4.1" + qs "^6.11.2" + use-composed-ref@^1.0.0: version "1.2.1" resolved "https://registry.npmmirror.com/use-composed-ref/-/use-composed-ref-1.2.1.tgz#9bdcb5ccd894289105da2325e1210079f56bf849"