-
Notifications
You must be signed in to change notification settings - Fork 56
Open
Description
[Bug] Undocumented per-symbol rate limit on Candlesticks API causes 301606 errors
问题描述
在使用 Longbridge OpenAPI SDK 调用 Candlesticks 接口时,发现存在一个未记录在文档中的 per-symbol 频率限制:当同一 symbol 在约 57ms 内被请求两次时,第二次会返回 code:301606 message:request rate limit。
这个限制与官方文档中的全局频率限制(10 req/s)相互独立,即使全局窗口远未到达上限(本次复现时仅使用 6/10 的请求量),也会被触发。
具体场景(可在低延迟服务器上稳定复现):
- 对同一 symbol(如
TSLA.US)同时发起两个 Candlesticks 请求(并发/串行均可) - 第一个请求成功返回(约 7-11ms)
- 第二个请求在第一个完成约 57ms 后发出,被返回
301606(4ms 内即拒绝,为服务端主动限流)
问题:
- per-symbol 的 Candlesticks 调用冷却时间到底是多少毫秒?
- 这个限制是否有官方文档说明?
- 对同一 symbol 同时请求不同 count(如 count=5 和 count=1),是否应该受此限制?
代码例子
package main
import (
"context"
"fmt"
"sync"
"time"
lbconfig "github.com/longportapp/openapi-go/config"
"github.com/longportapp/openapi-go/quote"
)
func candlesticks(client *quote.QuoteContext, cycleStart time.Time, label, symbol string, limit int32) error {
t := time.Now()
result, err := client.Candlesticks(context.Background(), symbol, quote.Period(1), limit, quote.AdjustTypeNo)
elapsed := time.Since(t)
total := time.Since(cycleStart)
icon := "✅"
detail := fmt.Sprintf("count=%d", len(result))
if err != nil {
icon = "❌"
detail = fmt.Sprintf("err=%v", err)
}
fmt.Printf(" [T+%6.1fms] %s %-30s %s (API耗时=%.0fms)\n",
float64(total.Microseconds())/1000, icon, label, detail,
float64(elapsed.Microseconds())/1000)
return err
}
func main() {
cfg := &lbconfig.Config{
AppKey: "YOUR_APP_KEY",
AppSecret: "YOUR_APP_SECRET",
AccessToken: "YOUR_ACCESS_TOKEN",
}
client, err := quote.NewFromCfg(cfg)
if err != nil {
panic(err)
}
defer client.Close()
fmt.Println("=== Reproducing per-symbol rate limit (301606) ===")
cycleStart := time.Now()
var wg sync.WaitGroup
// 并发:独立请求 TSLA.US(limit=5) + 9988.HK(limit=5)
for _, sym := range []string{"TSLA.US", "9988.HK"} {
sym := sym
wg.Add(1)
go func() {
defer wg.Done()
candlesticks(client, cycleStart, "concurrent "+sym+" limit=5", sym, 5)
}()
}
// 串行批量:NVDA.US → 700.HK → 9988.HK → TSLA.US
// 模拟批量接口内部对多个 symbol 依次调用 Candlesticks(等每个响应才发下一个)
wg.Add(1)
go func() {
defer wg.Done()
for _, sym := range []string{"NVDA.US", "700.HK", "9988.HK", "TSLA.US"} {
candlesticks(client, cycleStart, "serial batch "+sym+" limit=1", sym, 1)
}
}()
wg.Wait()
}注意:此问题需在低延迟网络环境下才能稳定复现(服务器靠近长桥节点,API 响应时间约 7-11ms)。
在高延迟网络(如本地开发机,响应时间约 70ms)下,串行到 TSLA.US 时已超出冷却窗口,不会触发。
错误信息
在服务器(香港/新加坡节点)上运行的实际输出:
=== Reproducing per-symbol rate limit (301606) ===
[T+ 7.4ms] ✅ concurrent NVDA.US limit=1 count=1 (API耗时=7ms)
[T+ 11.3ms] ✅ concurrent TSLA.US limit=5 count=5 (API耗时=11ms)
[T+ 11.4ms] ✅ concurrent 9988.HK limit=5 count=5 (API耗时=11ms)
[T+ 52.0ms] ✅ serial batch 700.HK limit=1 count=1 (API耗时=45ms)
[T+ 68.3ms] ✅ serial batch 9988.HK limit=1 count=1 (API耗时=16ms)
[T+ 72.5ms] ❌ serial batch TSLA.US limit=1 err=longbridge protocol api error, status:3 code:301606 message:request rate limit (API耗时=4ms)
时序分析:
| 事件 | 时间 |
|---|---|
| 第 1 次 TSLA.US (limit=5) 完成 | T+11.3ms |
| 第 2 次 TSLA.US (limit=1) 发出 | T+68.5ms |
| 两次请求间隔 | ~57ms |
| 第 2 次响应耗时 | 4ms(服务端立即拒绝,非超时) |
| 全局请求数(1秒窗口内) | 6 / 10(未超限) |
关键点:
- 第 1 次和第 2 次调用的是完全相同的 API(Candlesticks),仅 count 参数不同(5 vs 1)
- 两次请求间隔仅约 57ms,未超过任何已知文档限制
- 全局 10 req/s 窗口内总请求数为 6,远未到达上限
- 301606 在 4ms 内即返回,确认为服务端主动限流(非网络问题)
你的环境信息
- 操作系统:Linux (x86_64)
- 开发语言:Go
- SDK 版本号:
github.com/longportapp/openapi-go v0.17.1
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels