输入/搜索内容
欢迎使用发明者量化交易平台
编程语言
JavaScript
TypeScript
Python
Rust
C++
My语言(麦语言)
PINE语言
Blockly可视化
Workflow工作流
密钥安全性
实盘
策略库
托管者
部署托管者
一键租用托管者
手动部署托管者
托管者操作注意事项
全局指定IP地址
命令行版本托管者程序的参数
实盘数据迁移
托管者监控
交易所
策略编辑器
回测系统
策略入口函数
策略框架与API函数
模板类库
策略参数
交互控件
期权交易
Rust策略编写说明
C++策略编写说明
JavaScript策略编写说明
Web3
内置库
扩展API接口
MCP 服务
交易终端
数据探索
Alpha因子分析工具
通用协议
调试工具
远程编辑
完整策略的导入与导出
多语言支持
实盘、策略分组
实盘展示
策略分享与出租
实盘消息推送
实盘报错、异常退出的常见原因
交易所特殊说明

功能概述

API限流控制功能用于限制策略对交易所API的调用频率,防止因触发交易所的频率限制而导致账号被封禁或临时受限。FMZ平台提供了灵活的限流配置方式,支持两种限流模式和多种配置策略。

为什么需要API限流

  • 避免触发交易所限制:大多数交易所对API调用频率有严格限制,一旦超限,可能导致账号被临时或永久封禁。

  • 合理分配API配额:在多策略、多交易对场景下,需要合理分配API调用资源。

  • 提高策略稳定性:通过主动限流,避免因频繁调用导致的连接失败和数据获取异常。

  • 符合交易所规范:遵守交易所的API使用规范,维护良好的API使用关系。

两种限流模式

rate模式(平滑限流)

  • 适用于一般的限流需求

  • 不严格对齐时间窗口

  • 调用分布相对平滑

  • 推荐用于日常的API调用限制

quota模式(额度限流)

  • 严格对齐时间窗口

  • 例如:设置"1s"时,窗口对齐到整秒;设置"1m"时,窗口对齐到整分钟

  • 适用于需要严格控制时间窗口的场景

  • 推荐用于日内配额管理

基本用法

rate模式基本示例

示例

  • undefined
    javascript
    function main() { // Limit GetTicker to maximum 10 times per second exchange.IO("rate", "GetTicker", 10, "1s") // Normal API calls for (var i = 0; i < 20; i++) { var ticker = exchange.GetTicker("BTC_USDT") if (ticker) { Log("Success:", ticker.Last) } else { Log("Rate limit exceeded") // Returns null when exceeding 10 times/second } Sleep(50) } }
    python
    def main(): # Limit GetTicker to maximum 10 times per second exchange.IO("rate", "GetTicker", 10, "1s") # Normal API calls for i in range(20): ticker = exchange.GetTicker("BTC_USDT") if ticker: Log("Success:", ticker["Last"]) else: Log("Rate limit exceeded") # Returns None when exceeding 10 times/second Sleep(50)
    rust
    fn main() { // Limit GetTicker to maximum 10 times per second let _ = exchange.IO(("rate", "GetTicker", 10, "1s")); // Normal API calls for _i in 0..20 { match exchange.GetTicker("BTC_USDT") { Ok(ticker) => Log!("Success:", ticker.Last), Err(_) => Log!("Rate limit exceeded"), // Returns Err when exceeding 10 times/second } Sleep(50); } }
    c++
    // C++暂不支持
  • quota模式基本示例

    javascript
    function main() { // Strict limit, time window aligned to whole seconds exchange.IO("quota", "GetTicker", 5, "1s") for (var i = 0; i < 10; i++) { var ticker = exchange.GetTicker("BTC_USDT") Log(_D(), "Call", i+1, ticker ? "Success" : "Quota exceeded") Sleep(150) // About 6-7 calls per second, will trigger limit } }
    python
    def main(): # Strict limit, time window aligned to whole seconds exchange.IO("quota", "GetTicker", 5, "1s") for i in range(10): ticker = exchange.GetTicker("BTC_USDT") Log(_D(), "Call", i+1, "Success" if ticker else "Quota exceeded") Sleep(150) # About 6-7 calls per second, will trigger limit
    rust
    fn main() { // Strict limit, time window aligned to whole seconds let _ = exchange.IO(("quota", "GetTicker", 5, "1s")); for i in 0..10 { match exchange.GetTicker("BTC_USDT") { Ok(_) => Log!(_D(None), "Call", i + 1, "Success"), Err(_) => Log!(_D(None), "Call", i + 1, "Quota exceeded"), } Sleep(150); // About 6-7 calls per second, will trigger limit } }
    c++
    // C++暂不支持
  • 函数名配置

    单个函数限流

    javascript
    function main() { // Only limit GetTicker function exchange.IO("rate", "GetTicker", 10, "1s") // GetTicker is limited, GetDepth is not limited exchange.GetTicker("BTC_USDT") exchange.GetDepth("BTC_USDT") }
    python
    def main(): # Only limit GetTicker function exchange.IO("rate", "GetTicker", 10, "1s") # GetTicker is limited, GetDepth is not limited exchange.GetTicker("BTC_USDT") exchange.GetDepth("BTC_USDT")
    rust
    fn main() { // Only limit GetTicker function let _ = exchange.IO(("rate", "GetTicker", 10, "1s")); // GetTicker is limited, GetDepth is not limited let _ = exchange.GetTicker("BTC_USDT"); let _ = exchange.GetDepth("BTC_USDT"); }
    c++
    // C++暂不支持
  • 多个函数联合限流

    javascript
    function main() { // GetTicker and GetDepth share quota, total 10 times per second exchange.IO("rate", "GetTicker,GetDepth", 10, "1s") for (var i = 0; i < 15; i++) { if (i % 2 == 0) { exchange.GetTicker("BTC_USDT") // Counted in shared quota } else { exchange.GetDepth("BTC_USDT") // Counted in shared quota } } }
    python
    def main(): # GetTicker and GetDepth share quota, total 10 times per second exchange.IO("rate", "GetTicker,GetDepth", 10, "1s") for i in range(15): if i % 2 == 0: exchange.GetTicker("BTC_USDT") # Counted in shared quota else: exchange.GetDepth("BTC_USDT") # Counted in shared quota
    rust
    fn main() { // GetTicker and GetDepth share quota, total 10 times per second let _ = exchange.IO(("rate", "GetTicker,GetDepth", 10, "1s")); for i in 0..15 { if i % 2 == 0 { let _ = exchange.GetTicker("BTC_USDT"); // Counted in shared quota } else { let _ = exchange.GetDepth("BTC_USDT"); // Counted in shared quota } } }
    c++
    // C++暂不支持
  • 使用通配符限制所有函数

    javascript
    function main() { // Limit all API calls to total 100 times per minute exchange.IO("rate", "*", 100, "1m") // All calls are counted in total quota exchange.GetTicker("BTC_USDT") exchange.GetDepth("BTC_USDT") exchange.GetAccount() exchange.CreateOrder("BTC_USDT", "buy", 50000, 0.001) }
    python
    def main(): # Limit all API calls to total 100 times per minute exchange.IO("rate", "*", 100, "1m") # All calls are counted in total quota exchange.GetTicker("BTC_USDT") exchange.GetDepth("BTC_USDT") exchange.GetAccount() exchange.CreateOrder("BTC_USDT", "buy", 50000, 0.001)
    rust
    fn main() { // Limit all API calls to total 100 times per minute let _ = exchange.IO(("rate", "*", 100, "1m")); // All calls are counted in total quota let _ = exchange.GetTicker("BTC_USDT"); let _ = exchange.GetDepth("BTC_USDT"); let _ = exchange.GetAccount(); let _ = exchange.CreateOrder("BTC_USDT", "buy", 50000, 0.001); }
    c++
    // C++暂不支持
  • 时间周期配置

    支持的时间单位

    • ns:纳秒

    • usµs:微秒

    • ms:毫秒

    • s:秒

    • m:分钟

    • h:小时

    • d:天

    示例:"100ms", "1s", "5m", "1h", "1d"

    javascript
    function main() { // Different time period configurations exchange.IO("rate", "GetTicker", 10, "1s") // 10 times per second exchange.IO("rate", "GetDepth", 30, "1m") // 30 times per minute exchange.IO("rate", "GetAccount", 100, "1h") // 100 times per hour exchange.IO("rate", "CreateOrder", 500, "1d") // 500 times per day }
    python
    def main(): # 不同时间周期的配置 exchange.IO("rate", "GetTicker", 10, "1s") # 每秒10次 exchange.IO("rate", "GetDepth", 30, "1m") # 每分钟30次 exchange.IO("rate", "GetAccount", 100, "1h") # 每小时100次 exchange.IO("rate", "CreateOrder", 500, "1d") # 每天500次
    rust
    fn main() { // 不同时间周期的配置 let _ = exchange.IO(("rate", "GetTicker", 10, "1s")); // 每秒10次 let _ = exchange.IO(("rate", "GetDepth", 30, "1m")); // 每分钟30次 let _ = exchange.IO(("rate", "GetAccount", 100, "1h")); // 每小时100次 let _ = exchange.IO(("rate", "CreateOrder", 500, "1d")); // 每天500次 }
    c++
    // C++暂不支持
  • 重置时间点配置

    使用 @HHMM@HHMMSS 格式指定每日的重置时间点,仅在 quota 模式下有效。

    javascript
    function main() { // Reset quota daily at 08:15 exchange.IO("quota", "GetTicker", 1000, "@0815") // Reset quota daily at 00:00 exchange.IO("quota", "CreateOrder", 500, "@0000") // Reset quota daily at 23:59:59 exchange.IO("quota", "*", 5000, "@235959") }
    python
    def main(): # Reset quota daily at 08:15 exchange.IO("quota", "GetTicker", 1000, "@0815") # Reset quota daily at 00:00 exchange.IO("quota", "CreateOrder", 500, "@0000") # Reset quota daily at 23:59:59 exchange.IO("quota", "*", 5000, "@235959")
    rust
    fn main() { // Reset quota daily at 08:15 let _ = exchange.IO(("quota", "GetTicker", 1000, "@0815")); // Reset quota daily at 00:00 let _ = exchange.IO(("quota", "CreateOrder", 500, "@0000")); // Reset quota daily at 23:59:59 let _ = exchange.IO(("quota", "*", 5000, "@235959")); }
    c++
    // C++暂不支持
  • 行为模式

    默认模式(超限返回null)

    javascript
    function main() { exchange.IO("rate", "GetTicker", 5, "1s") // 不指定 behavior 参数 for (var i = 0; i < 10; i++) { var ticker = exchange.GetTicker("BTC_USDT") if (ticker) { Log("Call", i+1, "Success:", ticker.Last) } else { Log("Call", i+1, "Failed: rate limit exceeded") // 可选择 Sleep 等待,或跳过本次调用 Sleep(200) } } }
    python
    def main(): exchange.IO("rate", "GetTicker", 5, "1s") # 不指定 behavior 参数 for i in range(10): ticker = exchange.GetTicker("BTC_USDT") if ticker: Log("Call", i+1, "Success:", ticker["Last"]) else: Log("Call", i+1, "Failed: rate limit exceeded") # 可选择 Sleep 等待,或跳过本次调用 Sleep(200)
    rust
    fn main() { let _ = exchange.IO(("rate", "GetTicker", 5, "1s")); // 不指定 behavior 参数 for i in 0..10 { match exchange.GetTicker("BTC_USDT") { Ok(ticker) => Log!("Call", i + 1, "Success:", ticker.Last), Err(_) => { Log!("Call", i + 1, "Failed: rate limit exceeded"); // 可选择 Sleep 等待,或跳过本次调用 Sleep(200); } } } }
    c++
    // C++暂不支持
  • delay模式(超限自动等待)

    javascript
    function main() { exchange.IO("rate", "GetTicker", 5, "1s", "delay") // 指定delay参数 // 调用超限时会自动等待,确保每次调用都成功 for (var i = 0; i < 10; i++) { var ticker = exchange.GetTicker("BTC_USDT") Log("Call", i+1, "Success:", ticker.Last) // ticker不会为null } }
    python
    def main(): exchange.IO("rate", "GetTicker", 5, "1s", "delay") # 指定delay参数 # 调用超限时会自动等待,确保每次调用都成功 for i in range(10): ticker = exchange.GetTicker("BTC_USDT") Log("Call", i+1, "Success:", ticker["Last"]) # ticker不会为None
    rust
    fn main() { let _ = exchange.IO(("rate", "GetTicker", 5, "1s", "delay")); // 指定delay参数 // 调用超限时会自动等待,确保每次调用都成功 for i in 0..10 { let ticker = exchange.GetTicker("BTC_USDT").unwrap(); Log!("Call", i + 1, "Success:", ticker.Last); // ticker不会返回Err } }
    c++
    // C++暂不支持
  • 支持的函数列表

    交易类函数

    • CreateOrder:创建订单
    • CancelOrder:取消订单
    • Buy:买入(受CreateOrder限制)
    • Sell:卖出(受CreateOrder限制)
    • CreateConditionOrder:创建条件单
    • CancelConditionOrder:取消条件单

    账户类函数

    • GetAccount:获取账户信息
    • GetAssets:获取资产信息
    • GetPositions:获取持仓信息

    订单类函数

    • GetOrder:获取单个订单
    • GetOrders:获取所有订单
    • GetHistoryOrders:获取历史订单
    • GetConditionOrder:获取单个条件单
    • GetConditionOrders:获取所有条件单
    • GetHistoryConditionOrders:获取历史条件单

    行情类函数

    • GetTicker:获取单个行情(ticker)
    • GetTickers:获取多个行情(ticker)
    • GetDepth:获取市场深度
    • GetRecords:获取K线数据
    • GetTrades:获取最新成交记录

    其它函数

    • GetMarkets:获取市场列表
    • GetFundings:获取资金费率
    • SetMarginLevel:设置杠杆倍数
    • Go:并发调用(受实际调用函数限制)
    • IO/api:自定义API调用(仅限exchange.IO("api", ...))
  • 实际应用场景

    场景1:防止触发交易所的频率限制

    javascript
    function main() { // 假设交易所限制:GetTicker 每秒 20 次,CreateOrder 每秒 5 次 // 将频率设置为略低于交易所限制的值,以预留安全余量 exchange.IO("rate", "GetTicker", 15, "1s") exchange.IO("rate", "CreateOrder", 4, "1s") while (true) { var ticker = exchange.GetTicker("BTC_USDT") if (ticker && ticker.Last < 50000) { exchange.CreateOrder("BTC_USDT", "buy", ticker.Last, 0.001) } Sleep(100) } }
    python
    def main(): # 假设交易所限制:GetTicker 每秒 20 次,CreateOrder 每秒 5 次 # 将频率设置为略低于交易所限制的值,以预留安全余量 exchange.IO("rate", "GetTicker", 15, "1s") exchange.IO("rate", "CreateOrder", 4, "1s") while True: ticker = exchange.GetTicker("BTC_USDT") if ticker and ticker["Last"] < 50000: exchange.CreateOrder("BTC_USDT", "buy", ticker["Last"], 0.001) Sleep(100)
    rust
    fn main() { // 假设交易所限制:GetTicker 每秒 20 次,CreateOrder 每秒 5 次 // 将频率设置为略低于交易所限制的值,以预留安全余量 let _ = exchange.IO(("rate", "GetTicker", 15, "1s")); let _ = exchange.IO(("rate", "CreateOrder", 4, "1s")); loop { if let Ok(ticker) = exchange.GetTicker("BTC_USDT") { if ticker.Last < 50000.0 { let _ = exchange.CreateOrder("BTC_USDT", "buy", ticker.Last, 0.001); } } Sleep(100); } }
    c++
    // C++ 暂不支持
  • 场景2:多交易所对象统一限流

    javascript
    function main() { // 为每个交易所对象设置限流 for (var i = 0; i < exchanges.length; i++) { exchanges[i].IO("rate", "GetTicker", 10, "1s") exchanges[i].IO("rate", "CreateOrder", 2, "1s") } // 并发获取多个交易所的行情 while (true) { for (var i = 0; i < exchanges.length; i++) { var ticker = exchanges[i].GetTicker("BTC_USDT") if (ticker) { Log(exchanges[i].GetName(), "Price:", ticker.Last) } } Sleep(1000) } }
    python
    def main(): # 为每个交易所对象设置限流 for i in range(len(exchanges)): exchanges[i].IO("rate", "GetTicker", 10, "1s") exchanges[i].IO("rate", "CreateOrder", 2, "1s") # 并发获取多个交易所的行情 while True: for i in range(len(exchanges)): ticker = exchanges[i].GetTicker("BTC_USDT") if ticker: Log(exchanges[i].GetName(), "Price:", ticker["Last"]) Sleep(1000)
    rust
    fn main() { // 为每个交易所对象设置限流 for e in exchanges.iter() { let _ = e.IO(("rate", "GetTicker", 10, "1s")); let _ = e.IO(("rate", "CreateOrder", 2, "1s")); } // 并发获取多个交易所的行情 loop { for e in exchanges.iter() { if let Ok(ticker) = e.GetTicker("BTC_USDT") { Log!(e.GetName(), "Price:", ticker.Last); } } Sleep(1000); } }
    c++
    // C++ 暂不支持
  • 场景3:日内配额管理

    javascript
    function main() { // 每天最多 1000 次 API 调用,每天早上 8 点重置 exchange.IO("quota", "*", 1000, "@0800") var callCount = 0 while (true) { var ticker = exchange.GetTicker("BTC_USDT") if (ticker) { callCount++ Log("Call count:", callCount, "Price:", ticker.Last) } else { Log("Daily quota exceeded, waiting for tomorrow 08:00") Sleep(60000) // 等待 1 分钟后重试 } Sleep(10000) } }
    python
    def main(): # 每天最多 1000 次 API 调用,每天早上 8 点重置 exchange.IO("quota", "*", 1000, "@0800") callCount = 0 while True: ticker = exchange.GetTicker("BTC_USDT") if ticker: callCount += 1 Log("Call count:", callCount, "Price:", ticker["Last"]) else: Log("Daily quota exceeded, waiting for tomorrow 08:00") Sleep(60000) # 等待 1 分钟后重试 Sleep(10000)
    rust
    fn main() { // 每天最多 1000 次 API 调用,每天早上 8 点重置 let _ = exchange.IO(("quota", "*", 1000, "@0800")); let mut callCount = 0; loop { match exchange.GetTicker("BTC_USDT") { Ok(ticker) => { callCount += 1; Log!("Call count:", callCount, "Price:", ticker.Last); } Err(_) => { Log!("Daily quota exceeded, waiting for tomorrow 08:00"); Sleep(60000); // 等待 1 分钟后重试 } } Sleep(10000); } }
    c++
    // C++ 暂不支持
  • 场景4:组合限流策略

    javascript
    function main() { // 组合使用多种限流策略 // 1. 行情类API每秒限流 exchange.IO("rate", "GetTicker,GetDepth", 20, "1s") // 2. 交易类API每秒限流 exchange.IO("rate", "CreateOrder,CancelOrder", 5, "1s") // 3. 账户查询类API每分钟限流 exchange.IO("rate", "GetAccount,GetPositions", 30, "1m") // 4. 所有API每日总配额 exchange.IO("quota", "*", 10000, "@0000") Log("Multi-level rate limiting configured") // 策略主循环 while (true) { // 获取行情数据 var ticker = exchange.GetTicker("BTC_USDT") var depth = exchange.GetDepth("BTC_USDT") // 查询账户信息 if (Date.now() % 60000 < 1000) { // 每分钟查询一次 var account = exchange.GetAccount() Log("Account:", account) } // 交易逻辑 if (ticker && ticker.Last < 50000) { exchange.CreateOrder("BTC_USDT", "buy", ticker.Last, 0.001) } Sleep(500) } }
    python
    import time def main(): # 组合使用多种限流策略 # 1. 行情类API每秒限流 exchange.IO("rate", "GetTicker,GetDepth", 20, "1s") # 2. 交易类API每秒限流 exchange.IO("rate", "CreateOrder,CancelOrder", 5, "1s") # 3. 账户查询类API每分钟限流 exchange.IO("rate", "GetAccount,GetPositions", 30, "1m") # 4. 所有API每日总配额 exchange.IO("quota", "*", 10000, "@0000") Log("Multi-level rate limiting configured") # 策略主循环 while True: # 获取行情数据 ticker = exchange.GetTicker("BTC_USDT") depth = exchange.GetDepth("BTC_USDT") # 查询账户信息 if int(time.time() * 1000) % 60000 < 1000: # 每分钟查询一次 account = exchange.GetAccount() Log("Account:", account) # 交易逻辑 if ticker and ticker["Last"] < 50000: exchange.CreateOrder("BTC_USDT", "buy", ticker["Last"], 0.001) Sleep(500)
    rust
    fn main() { // 组合使用多种限流策略 // 1. 行情类API每秒限流 let _ = exchange.IO(("rate", "GetTicker,GetDepth", 20, "1s")); // 2. 交易类API每秒限流 let _ = exchange.IO(("rate", "CreateOrder,CancelOrder", 5, "1s")); // 3. 账户查询类API每分钟限流 let _ = exchange.IO(("rate", "GetAccount,GetPositions", 30, "1m")); // 4. 所有API每日总配额 let _ = exchange.IO(("quota", "*", 10000, "@0000")); Log!("Multi-level rate limiting configured"); // 策略主循环 loop { // 获取行情数据 let ticker = exchange.GetTicker("BTC_USDT"); let depth = exchange.GetDepth("BTC_USDT"); // 查询账户信息 if UnixNano() / 1000000 % 60000 < 1000 { // 每分钟查询一次 let account = exchange.GetAccount(); Log!("Account:", account); } // 交易逻辑 if let Ok(t) = ticker { if t.Last < 50000.0 { let _ = exchange.CreateOrder("BTC_USDT", "buy", t.Last, 0.001); } } Sleep(500); } }
    c++
    // C++ 暂不支持
  • 注意事项

    1. quota模式时间窗口对齐

    quota模式严格对齐时间窗口:

    • "1s":对齐到整秒(例如:12:00:00、12:00:01、12:00:02……)
    • "1m":对齐到整分钟(例如:12:00:00、12:01:00、12:02:00……)
    • "1h":对齐到整小时(例如:12:00:00、13:00:00、14:00:00……)

    这意味着即使从12:00:00.500开始计数,到12:00:01.000时,当前时间窗口也会重置。

    javascript
    function main() { // quota模式:严格对齐到整秒 exchange.IO("quota", "GetTicker", 3, "1s") // 假设当前时间为 12:00:00.500 exchange.GetTicker("BTC_USDT") // 第1次,成功 exchange.GetTicker("BTC_USDT") // 第2次,成功 exchange.GetTicker("BTC_USDT") // 第3次,成功 exchange.GetTicker("BTC_USDT") // 第4次,失败(超限) Sleep(500) // 等待500ms,此时时间为 12:00:01.000 // 窗口已重置 exchange.GetTicker("BTC_USDT") // 新窗口第1次,成功 }
    python
    def main(): # quota模式:严格对齐到整秒 exchange.IO("quota", "GetTicker", 3, "1s") # 假设当前时间为 12:00:00.500 exchange.GetTicker("BTC_USDT") # 第1次,成功 exchange.GetTicker("BTC_USDT") # 第2次,成功 exchange.GetTicker("BTC_USDT") # 第3次,成功 exchange.GetTicker("BTC_USDT") # 第4次,失败(超限) Sleep(500) # 等待500ms,此时时间为 12:00:01.000 # 窗口已重置 exchange.GetTicker("BTC_USDT") # 新窗口第1次,成功
    rust
    fn main() { // quota模式:严格对齐到整秒 let _ = exchange.IO(("quota", "GetTicker", 3, "1s")); // 假设当前时间为 12:00:00.500 let _ = exchange.GetTicker("BTC_USDT"); // 第1次,成功 let _ = exchange.GetTicker("BTC_USDT"); // 第2次,成功 let _ = exchange.GetTicker("BTC_USDT"); // 第3次,成功 let _ = exchange.GetTicker("BTC_USDT"); // 第4次,失败(超限) Sleep(500); // 等待500ms,此时时间为 12:00:01.000 // 窗口已重置 let _ = exchange.GetTicker("BTC_USDT"); // 新窗口第1次,成功 }
    c++
    // C++暂不支持
  • 2. delay模式下的时间差异

    使用"delay"参数时,实际的API调用时间与日志记录的时间可能并不一致。这是因为触发限流时程序会进入等待,而日志记录的是等待结束后的时间。

    javascript
    function main() { exchange.IO("rate", "GetTicker", 2, "1s", "delay") Log(_D(), "Call 1") // 12:00:00.000 exchange.GetTicker("BTC_USDT") Log(_D(), "Call 2") // 12:00:00.100 exchange.GetTicker("BTC_USDT") Log(_D(), "Call 3") // 12:00:00.200,但实际会等待到12:00:01.000 exchange.GetTicker("BTC_USDT") // 触发限流,自动等待 Log(_D(), "Call 3 completed") // 日志显示12:00:01.000+ // 看起来一秒内调用了3次,但实际第3次是在新窗口执行的 }
    python
    def main(): exchange.IO("rate", "GetTicker", 2, "1s", "delay") Log(_D(), "Call 1") # 12:00:00.000 exchange.GetTicker("BTC_USDT") Log(_D(), "Call 2") # 12:00:00.100 exchange.GetTicker("BTC_USDT") Log(_D(), "Call 3") # 12:00:00.200,但实际会等待到12:00:01.000 exchange.GetTicker("BTC_USDT") # 触发限流,自动等待 Log(_D(), "Call 3 completed") # 日志显示12:00:01.000+ # 看起来一秒内调用了3次,但实际第3次是在新窗口执行的
    rust
    fn main() { let _ = exchange.IO(("rate", "GetTicker", 2, "1s", "delay")); Log!(_D(None), "Call 1"); // 12:00:00.000 let _ = exchange.GetTicker("BTC_USDT"); Log!(_D(None), "Call 2"); // 12:00:00.100 let _ = exchange.GetTicker("BTC_USDT"); Log!(_D(None), "Call 3"); // 12:00:00.200,但实际会等待到12:00:01.000 let _ = exchange.GetTicker("BTC_USDT"); // 触发限流,自动等待 Log!(_D(None), "Call 3 completed"); // 日志显示12:00:01.000+ // 看起来一秒内调用了3次,但实际第3次是在新窗口执行的 }
    c++
    // C++暂不支持
  • 3. Buy/Sell函数的限流

    BuySell函数在底层均调用CreateOrder,因此其限流规则遵循CreateOrder的设置。

    javascript
    function main() { // 设置CreateOrder限流 exchange.IO("rate", "CreateOrder", 5, "1s") // Buy和Sell也会受到此限制 for (var i = 0; i < 10; i++) { if (i % 2 == 0) { exchange.Buy(50000, 0.001) // 受CreateOrder限制 } else { exchange.Sell(51000, 0.001) // 受CreateOrder限制 } } }
    python
    def main(): # 设置CreateOrder限流 exchange.IO("rate", "CreateOrder", 5, "1s") # Buy和Sell也会受到此限制 for i in range(10): if i % 2 == 0: exchange.Buy(50000, 0.001) # 受CreateOrder限制 else: exchange.Sell(51000, 0.001) # 受CreateOrder限制
    rust
    fn main() { // 设置CreateOrder限流 let _ = exchange.IO(("rate", "CreateOrder", 5, "1s")); // Buy和Sell也会受到此限制 for i in 0..10 { if i % 2 == 0 { let _ = exchange.Buy(50000, 0.001); // 受CreateOrder限制 } else { let _ = exchange.Sell(51000, 0.001); // 受CreateOrder限制 } } }
    c++
    // C++暂不支持
  • 4. Go函数的限流

    Go函数的限流取决于实际被并发调用的函数。

    javascript
    function main() { // 限制GetTicker exchange.IO("rate", "GetTicker", 5, "1s") // 并发调用GetTicker时受限 var tasks = [] for (var i = 0; i < 10; i++) { tasks.push(exchange.Go("GetTicker", "BTC_USDT")) } for (var i = 0; i < tasks.length; i++) { var ticker = tasks[i].wait() Log("Task", i, ticker ? "Success" : "Rate limited") } }
    python
    def main(): # 限制GetTicker exchange.IO("rate", "GetTicker", 5, "1s") # 并发调用GetTicker时受限 tasks = [] for i in range(10): tasks.append(exchange.Go("GetTicker", "BTC_USDT")) for i in range(len(tasks)): ticker = tasks[i].wait() Log("Task", i, "Success" if ticker else "Rate limited")
    rust
    fn main() { // 限制GetTicker let _ = exchange.IO(("rate", "GetTicker", 5, "1s")); // 并发调用GetTicker时受限 // Rust中exchange.Go为类型化写法,使用Go::GetTicker token let mut tasks = Vec::new(); for _i in 0..10 { tasks.push(exchange.Go(Go::GetTicker, ("BTC_USDT",))); } for (i, task) in tasks.iter().enumerate() { match task.wait(0) { Ok(_) => Log!("Task", i, "Success"), Err(_) => Log!("Task", i, "Rate limited"), } } }
    c++
    // C++暂不支持
  • 5. IO/api的限流

    IO/api 限流仅对 exchange.IO("api", ...) 调用生效,不会影响其他 exchange.IO 功能。

    javascript
    function main() { // 限制exchange.IO("api", ...)调用 exchange.IO("rate", "IO/api", 10, "1s") // 受限制 for (var i = 0; i < 15; i++) { var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "") Log("API call", i, ret ? "Success" : "Rate limited") } // 不受限制 exchange.IO("currency", "LTC_USDT") // 切换交易对,不受限 exchange.IO("rate", "GetDepth", 5, "1s") // 设置其它限流,不受限 }
    python
    def main(): # 限制exchange.IO("api", ...)调用 exchange.IO("rate", "IO/api", 10, "1s") # 受限制 for i in range(15): ret = exchange.IO("api", "GET", "/api/v5/account/balance", "") Log("API call", i, "Success" if ret else "Rate limited") # 不受限制 exchange.IO("currency", "LTC_USDT") # 切换交易对,不受限 exchange.IO("rate", "GetDepth", 5, "1s") # 设置其它限流,不受限
    rust
    fn main() { // 限制exchange.IO("api", ...)调用 let _ = exchange.IO(("rate", "IO/api", 10, "1s")); // 受限制 for i in 0..15 { match exchange.IO(("api", "GET", "/api/v5/account/balance", "")) { Ok(_) => Log!("API call", i, "Success"), Err(_) => Log!("API call", i, "Rate limited"), } } // 不受限制 let _ = exchange.IO(("currency", "LTC_USDT")); // 切换交易对,不受限 let _ = exchange.IO(("rate", "GetDepth", 5, "1s")); // 设置其它限流,不受限 }
    c++
    // C++暂不支持
  • 最佳实践

    1. 根据交易所限制设置:请参考交易所的 API 文档,将限流值设置为略低于交易所限制的水平。

    2. 留出安全余量:请勿将限流值设置为交易所允许的最大值,建议设置为最大值的 70%-80%。

    3. 分层限流:针对不同类型的 API 设置不同的限流值,并为重要 API 保留更多余量。

    4. 使用 delay 模式处理关键调用:对于必须成功的 API 调用,请使用 "delay" 模式以确保调用成功。

    5. 监控 API 使用情况:定期检查策略的 API 调用频率,并持续优化调用逻辑。

    6. 避免过度调用:合理设计策略逻辑,避免不必要的 API 调用。

    7. 测试限流配置:在实盘运行前,先在模拟环境中测试限流配置是否合理。

参考