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

功能概述

优宽量化平台支持对商品期货交易所的 API 调用进行频率限制,以防止触发交易所的频率限制。通过合理配置 API 限流,可以有效避免因频繁调用而导致的接口限制问题,从而保障策略稳定运行。

API 限流功能支持两种限流模式:

  • rate 模式(平滑限流):不严格对齐时间窗口,适用于一般的限流需求。例如设置为每秒 10 次时,系统会平滑地控制调用频率。

  • quota 模式(额度限流):严格对齐时间窗口,例如 1m 对齐到整分钟,1s 对齐到整秒。适用于需要严格控制时间窗口的场景。

基础用法

函数签名

javascript
exchange.IO("rate", functionNames, maxCalls, period, [behavior]) exchange.IO("quota", functionNames, maxCalls, period, [behavior])

参数说明

参数类型必填说明
modestring限流模式:"rate"(平滑限流)或 "quota"(额度限流)
functionNamesstring需要限制的函数名,支持单个函数、多个函数(以逗号分隔)以及通配符(* 表示所有函数)
maxCallsnumber时间周期内允许的最大调用次数
periodstring时间周期或重置时间点。支持的时间单位:ns, us, µs, ms, s, m, h, d(例如:"1s"、"1m"、"1h")。支持的重置时间点:@HHMM 或 @HHMMSS(例如:"@0815" 表示每天 08:15 重置)
behaviorstring超限行为。默认为空(超限时返回 null 并报错);设置为 "delay" 时,超限则等待

支持的函数列表

优宽量化平台的 API 限流功能支持以下函数:

交易类(2 个):

  • CreateOrder - 创建订单

  • CancelOrder - 撤销订单

账户类(2 个):

  • GetAccount - 获取账户信息

  • GetPositions - 获取持仓信息

订单类(3 个):

  • GetOrder - 获取订单信息

  • GetOrders - 获取订单列表

  • GetHistoryOrders - 获取历史订单

行情类(3 个):

  • GetTicker - 获取行情 Tick 数据

  • GetDepth - 获取深度数据

  • GetRecords - 获取 K 线数据

其它(1 个):

  • IO/api - 仅对 exchange.IO("api", ...) 调用生效

函数名称配置

单个函数限流

限制单个函数的调用频率:

示例

  • undefined
    javascript
    function main() { while (!exchange.IO("status")) { Sleep(1000) } // 限制 GetTicker 每秒最多调用 3 次 exchange.IO("rate", "GetTicker", 3, "1s") for (var i = 0; i < 10; i++) { if (!exchange.IO("status")) { Sleep(5000) continue } var ticker = exchange.GetTicker("rb888") if (ticker) { Log("Success:", ticker.Last) } else { Log("Rate limit exceeded", "#FF0000") } Sleep(100) } }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) # 限制 GetTicker 每秒最多调用 3 次 exchange.IO("rate", "GetTicker", 3, "1s") for i in range(10): if not exchange.IO("status"): Sleep(5000) continue ticker = exchange.GetTicker("rb888") if ticker: Log("Success:", ticker["Last"]) else: Log("Rate limit exceeded", "#FF0000") Sleep(100)
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 限制 GetTicker 每秒最多调用 3 次 let _ = exchange.IO(("rate", "GetTicker", 3, "1s")); for _i in 0..10 { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(5000); continue; } match exchange.GetTicker("rb888") { Ok(ticker) => Log!("Success:", ticker.Last), Err(_) => Log!("Rate limit exceeded", "#FF0000"), } Sleep(100); } }
    c++
    // C++ 暂不支持
  • 多个函数联合限流

    多个函数共享同一限流配额:

    javascript
    function main() { while (!exchange.IO("status")) { Sleep(1000) } // GetTicker 和 GetDepth 共享同一限流配额,合计每秒最多 5 次 exchange.IO("rate", "GetTicker,GetDepth", 5, "1s") for (var i = 0; i < 10; i++) { if (!exchange.IO("status")) { Sleep(5000) continue } if (i % 2 == 0) { var ticker = exchange.GetTicker("m888") Log("GetTicker:", ticker ? "Success" : "Failed") } else { var depth = exchange.GetDepth("m888") Log("GetDepth:", depth ? "Success" : "Failed") } Sleep(100) } }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) # GetTicker 和 GetDepth 共享同一限流配额,合计每秒最多 5 次 exchange.IO("rate", "GetTicker,GetDepth", 5, "1s") for i in range(10): if not exchange.IO("status"): Sleep(5000) continue if i % 2 == 0: ticker = exchange.GetTicker("m888") Log("GetTicker:", "Success" if ticker else "Failed") else: depth = exchange.GetDepth("m888") Log("GetDepth:", "Success" if depth else "Failed") Sleep(100)
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // GetTicker 和 GetDepth 共享同一限流配额,合计每秒最多 5 次 let _ = exchange.IO(("rate", "GetTicker,GetDepth", 5, "1s")); for i in 0..10 { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(5000); continue; } if i % 2 == 0 { let ticker = exchange.GetTicker("m888"); Log!("GetTicker:", if ticker.is_ok() { "Success" } else { "Failed" }); } else { let depth = exchange.GetDepth("m888"); Log!("GetDepth:", if depth.is_ok() { "Success" } else { "Failed" }); } Sleep(100); } }
    c++
    // C++ 暂不支持
  • 通配符限流

    使用通配符*限制所有 API 调用:

    javascript
    function main() { while (!exchange.IO("status")) { Sleep(1000) } // 限制所有 API 调用每秒最多 10 次 exchange.IO("mode", 0) // 建议配合立即返回模式使用 exchange.IO("rate", "*", 10, "1s") var symbols = ["rb888", "m888", "i888"] for (var i = 0; i < 5; i++) { if (!exchange.IO("status")) { Sleep(5000) continue } var symbol = symbols[i % symbols.length] var ticker = exchange.GetTicker(symbol) var account = exchange.GetAccount() Log("Round", i+1, "Ticker:", ticker ? "✓" : "✗", "Account:", account ? "✓" : "✗") Sleep(500) } }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) # 限制所有 API 调用每秒最多 10 次 exchange.IO("mode", 0) # 建议配合立即返回模式使用 exchange.IO("rate", "*", 10, "1s") symbols = ["rb888", "m888", "i888"] for i in range(5): if not exchange.IO("status"): Sleep(5000) continue symbol = symbols[i % len(symbols)] ticker = exchange.GetTicker(symbol) account = exchange.GetAccount() Log("Round", i+1, "Ticker:", "✓" if ticker else "✗", "Account:", "✓" if account else "✗") Sleep(500)
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 限制所有 API 调用每秒最多 10 次 let _ = exchange.IO(("mode", 0)); // 建议配合立即返回模式使用 let _ = exchange.IO(("rate", "*", 10, "1s")); let symbols = ["rb888", "m888", "i888"]; for i in 0..5 { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(5000); continue; } let symbol = symbols[i % symbols.len()]; let ticker = exchange.GetTicker(symbol); let account = exchange.GetAccount(); Log!("Round", i + 1, "Ticker:", if ticker.is_ok() { "✓" } else { "✗" }, "Account:", if account.is_ok() { "✓" } else { "✗" }); Sleep(500); } }
    c++
    // C++ 暂不支持
  • 时间周期配置

    固定时间周期

    支持多种时间单位:ns(纳秒)、us/µs(微秒)、ms(毫秒)、s(秒)、m(分钟)、h(小时)、d(天)。

    javascript
    function main() { while (!exchange.IO("status")) { Sleep(1000) } // 不同时间周期的限流配置 exchange.IO("rate", "GetTicker", 10, "1s") // 每秒 10 次 exchange.IO("rate", "GetDepth", 60, "1m") // 每分钟 60 次 exchange.IO("rate", "GetAccount", 100, "1h") // 每小时 100 次 Log("Rate limits configured") }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) # 不同时间周期的限流配置 exchange.IO("rate", "GetTicker", 10, "1s") # 每秒 10 次 exchange.IO("rate", "GetDepth", 60, "1m") # 每分钟 60 次 exchange.IO("rate", "GetAccount", 100, "1h") # 每小时 100 次 Log("Rate limits configured")
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 不同时间周期的限流配置 let _ = exchange.IO(("rate", "GetTicker", 10, "1s")); // 每秒 10 次 let _ = exchange.IO(("rate", "GetDepth", 60, "1m")); // 每分钟 60 次 let _ = exchange.IO(("rate", "GetAccount", 100, "1h")); // 每小时 100 次 Log!("Rate limits configured"); }
    c++
    // C++ 暂不支持
  • 日内重置时间点

    使用@HHMM@HHMMSS格式指定每天的重置时间:

    javascript
    function main() { while (!exchange.IO("status")) { Sleep(1000) } // 每天 08:15 重置配额,上限 1000 次 exchange.IO("quota", "GetTicker", 1000, "@0815") Log("Daily quota configured: 1000 calls, reset at 08:15") }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) # 每天 08:15 重置配额,上限 1000 次 exchange.IO("quota", "GetTicker", 1000, "@0815") Log("Daily quota configured: 1000 calls, reset at 08:15")
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 每天 08:15 重置配额,上限 1000 次 let _ = exchange.IO(("quota", "GetTicker", 1000, "@0815")); Log!("Daily quota configured: 1000 calls, reset at 08:15"); }
    c++
    // C++ 暂不支持
  • 行为模式配置

    默认模式(返回null)

    当超过频率限制时,API 调用将立即返回 null,而不会等待:

    javascript
    function main() { while (!exchange.IO("status")) { Sleep(1000) } // 默认模式:超过频率限制时返回 null exchange.IO("rate", "GetTicker", 3, "1s") for (var i = 0; i < 10; i++) { if (!exchange.IO("status")) { Sleep(5000) continue } var ticker = exchange.GetTicker("rb888") if (ticker) { Log("Call", i+1, "Success") } else { Log("Call", i+1, "Rate limit exceeded, returned null", "#FF0000") } Sleep(100) } }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) # 默认模式:超过频率限制时返回 null exchange.IO("rate", "GetTicker", 3, "1s") for i in range(10): if not exchange.IO("status"): Sleep(5000) continue ticker = exchange.GetTicker("rb888") if ticker: Log("Call", i+1, "Success") else: Log("Call", i+1, "Rate limit exceeded, returned null", "#FF0000") Sleep(100)
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 默认模式:超过频率限制时返回错误 let _ = exchange.IO(("rate", "GetTicker", 3, "1s")); for i in 0..10 { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(5000); continue; } match exchange.GetTicker("rb888") { Ok(_) => Log!("Call", i + 1, "Success"), Err(_) => Log!("Call", i + 1, "Rate limit exceeded, returned error", "#FF0000"), } Sleep(100); } }
    c++
    // C++ 暂不支持
  • delay模式(自动等待)

    当调用频率超出限制时自动等待,直到可以再次调用:

    javascript
    function main() { while (!exchange.IO("status")) { Sleep(1000) } // delay模式:超限后自动等待 exchange.IO("rate", "GetTicker", 3, "1s", "delay") Log("Testing delay mode", "#00FF00") for (var i = 0; i < 10; i++) { if (!exchange.IO("status")) { Sleep(5000) continue } var startTime = new Date().getTime() var ticker = exchange.GetTicker("m888") var endTime = new Date().getTime() Log("Call", i+1, "Time cost:", endTime - startTime, "ms") } }
    python
    import time def main(): while not exchange.IO("status"): Sleep(1000) # delay模式:超限后自动等待 exchange.IO("rate", "GetTicker", 3, "1s", "delay") Log("Testing delay mode", "#00FF00") for i in range(10): if not exchange.IO("status"): Sleep(5000) continue startTime = time.time() * 1000 ticker = exchange.GetTicker("m888") endTime = time.time() * 1000 Log("Call", i+1, "Time cost:", endTime - startTime, "ms")
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // delay模式:超限后自动等待 let _ = exchange.IO(("rate", "GetTicker", 3, "1s", "delay")); Log!("Testing delay mode", "#00FF00"); for i in 0..10 { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(5000); continue; } let startTime = UnixNano() / 1000000; let _ticker = exchange.GetTicker("m888"); let endTime = UnixNano() / 1000000; Log!("Call", i + 1, "Time cost:", endTime - startTime, "ms"); } }
    c++
    // C++暂不支持
  • 限流模式对比

    rate模式 vs quota模式

    javascript
    function main() { while (!exchange.IO("status")) { Sleep(1000) } exchange.IO("mode", 0) // rate 模式:平滑限流,不严格对齐时间窗口 // exchange.IO("rate", "GetTicker", 3, "1s") // quota 模式:严格对齐时间窗口,例如将 1s 对齐到整秒 exchange.IO("quota", "GetTicker", 3, "1s") for (var i = 0; i < 8; i++) { if (!exchange.IO("status")) { Sleep(5000) continue } var ticker = exchange.GetTicker("c888") Log(_D(), "Call", i+1, ticker ? "Success" : "Quota exceeded") Sleep(150) // 每 150ms 调用一次 } }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) exchange.IO("mode", 0) # rate 模式:平滑限流,不严格对齐时间窗口 # exchange.IO("rate", "GetTicker", 3, "1s") # quota 模式:严格对齐时间窗口,例如将 1s 对齐到整秒 exchange.IO("quota", "GetTicker", 3, "1s") for i in range(8): if not exchange.IO("status"): Sleep(5000) continue ticker = exchange.GetTicker("c888") Log(_D(), "Call", i+1, "Success" if ticker else "Quota exceeded") Sleep(150) # 每 150ms 调用一次
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } let _ = exchange.IO(("mode", 0)); // rate 模式:平滑限流,不严格对齐时间窗口 // let _ = exchange.IO(("rate", "GetTicker", 3, "1s")); // quota 模式:严格对齐时间窗口,例如将 1s 对齐到整秒 let _ = exchange.IO(("quota", "GetTicker", 3, "1s")); for i in 0..8 { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(5000); continue; } let ticker = exchange.GetTicker("c888"); Log!(_D(None), "Call", i + 1, if ticker.is_ok() { "Success" } else { "Quota exceeded" }); Sleep(150); // 每 150ms 调用一次 } }
    c++
    // C++ 暂不支持
  • 实际应用场景

    场景1:单品种行情监控

    监控单个合约的行情,同时避免频繁调用接口:

    javascript
    function main() { while (!exchange.IO("status")) { LogStatus("Waiting for connection...") Sleep(1000) } // 设置行情获取频率限制 exchange.IO("rate", "GetTicker", 5, "1s", "delay") Log("Monitoring rb888 (rebar) price") while (true) { if (!exchange.IO("status")) { Sleep(5000) continue } var ticker = exchange.GetTicker("rb888") LogStatus(_D(), "rb888 Price:", ticker.Last, "Buy:", ticker.Buy, "Sell:", ticker.Sell) Sleep(200) } }
    python
    def main(): while not exchange.IO("status"): LogStatus("Waiting for connection...") Sleep(1000) # 设置行情获取频率限制 exchange.IO("rate", "GetTicker", 5, "1s", "delay") Log("Monitoring rb888 (rebar) price") while True: if not exchange.IO("status"): Sleep(5000) continue ticker = exchange.GetTicker("rb888") LogStatus(_D(), "rb888 Price:", ticker["Last"], "Buy:", ticker["Buy"], "Sell:", ticker["Sell"]) Sleep(200)
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { LogStatus!("Waiting for connection..."); Sleep(1000); } // 设置行情获取频率限制 let _ = exchange.IO(("rate", "GetTicker", 5, "1s", "delay")); Log!("Monitoring rb888 (rebar) price"); loop { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(5000); continue; } if let Ok(ticker) = exchange.GetTicker("rb888") { LogStatus!(_D(None), "rb888 Price:", ticker.Last, "Buy:", ticker.Buy, "Sell:", ticker.Sell); } Sleep(200); } }
    c++
    // C++暂不支持
  • 场景2:多品种轮询策略

    轮询多个合约的行情,并控制整体的调用频率:

    javascript
    function main() { while (!exchange.IO("status")) { Sleep(1000) } exchange.IO("mode", 0) // 所有行情函数共享配额 exchange.IO("rate", "GetTicker,GetDepth", 10, "1s") var symbols = ["rb888", "m888", "i888", "c888"] Log("Monitoring multiple symbols:", symbols.join(", ")) while (true) { if (!exchange.IO("status")) { Sleep(5000) continue } for (var i = 0; i < symbols.length; i++) { var ticker = exchange.GetTicker(symbols[i]) if (ticker) { Log(symbols[i], "Price:", ticker.Last) } } Sleep(1000) } }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) exchange.IO("mode", 0) # 所有行情函数共享配额 exchange.IO("rate", "GetTicker,GetDepth", 10, "1s") symbols = ["rb888", "m888", "i888", "c888"] Log("Monitoring multiple symbols:", ", ".join(symbols)) while True: if not exchange.IO("status"): Sleep(5000) continue for symbol in symbols: ticker = exchange.GetTicker(symbol) if ticker: Log(symbol, "Price:", ticker["Last"]) Sleep(1000)
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } let _ = exchange.IO(("mode", 0)); // 所有行情函数共享配额 let _ = exchange.IO(("rate", "GetTicker,GetDepth", 10, "1s")); let symbols = ["rb888", "m888", "i888", "c888"]; Log!("Monitoring multiple symbols:", symbols.join(", ")); loop { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(5000); continue; } for symbol in &symbols { if let Ok(ticker) = exchange.GetTicker(*symbol) { Log!(*symbol, "Price:", ticker.Last); } } Sleep(1000); } }
    c++
    // C++暂不支持
  • 场景3:高频交易策略

    对交易相关接口实施严格的限流控制:

    javascript
    function main() { while (!exchange.IO("status")) { Sleep(1000) } // 分别为不同函数设置限流 exchange.IO("rate", "GetTicker", 10, "1s", "delay") exchange.IO("rate", "CreateOrder", 2, "1s", "delay") exchange.IO("rate", "CancelOrder", 5, "1s", "delay") exchange.IO("rate", "GetAccount", 1, "1s", "delay") Log("Rate limits configured for high-frequency trading") // 策略逻辑 while (true) { if (!exchange.IO("status")) { Sleep(5000) continue } var ticker = exchange.GetTicker("rb888") var account = exchange.GetAccount() // 交易逻辑(示例) LogStatus(_D(), "Price:", ticker.Last, "Balance:", account.Balance) Sleep(500) } }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) # 分别为不同函数设置限流 exchange.IO("rate", "GetTicker", 10, "1s", "delay") exchange.IO("rate", "CreateOrder", 2, "1s", "delay") exchange.IO("rate", "CancelOrder", 5, "1s", "delay") exchange.IO("rate", "GetAccount", 1, "1s", "delay") Log("Rate limits configured for high-frequency trading") # 策略逻辑 while True: if not exchange.IO("status"): Sleep(5000) continue ticker = exchange.GetTicker("rb888") account = exchange.GetAccount() # 交易逻辑(示例) LogStatus(_D(), "Price:", ticker["Last"], "Balance:", account["Balance"]) Sleep(500)
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 分别为不同函数设置限流 let _ = exchange.IO(("rate", "GetTicker", 10, "1s", "delay")); let _ = exchange.IO(("rate", "CreateOrder", 2, "1s", "delay")); let _ = exchange.IO(("rate", "CancelOrder", 5, "1s", "delay")); let _ = exchange.IO(("rate", "GetAccount", 1, "1s", "delay")); Log!("Rate limits configured for high-frequency trading"); // 策略逻辑 loop { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(5000); continue; } let ticker = exchange.GetTicker("rb888"); let account = exchange.GetAccount(); // 交易逻辑(示例) if let (Ok(ticker), Ok(account)) = (ticker, account) { LogStatus!(_D(None), "Price:", ticker.Last, "Balance:", account.Balance); } Sleep(500); } }
    c++
    // C++ 暂不支持
  • 场景4:日内交易次数控制

    使用 quota 模式控制每日的总交易次数:

    javascript
    function main() { while (!exchange.IO("status")) { Sleep(1000) } // 每天09:00重置,限制每日开仓100次 exchange.IO("quota", "CreateOrder", 100, "@0900") Log("Daily order limit: 100 orders, reset at 09:00") var orderCount = 0 while (true) { if (!exchange.IO("status")) { Sleep(5000) continue } var ticker = exchange.GetTicker("m888") // 交易逻辑(示例) // var orderId = exchange.CreateOrder(...) // if (orderId) { // orderCount++ // Log("Order created, daily count:", orderCount) // } else { // Log("Daily order quota exceeded", "#FF0000") // } Sleep(1000) } }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) # 每天09:00重置,限制每日开仓100次 exchange.IO("quota", "CreateOrder", 100, "@0900") Log("Daily order limit: 100 orders, reset at 09:00") orderCount = 0 while True: if not exchange.IO("status"): Sleep(5000) continue ticker = exchange.GetTicker("m888") # 交易逻辑(示例) # orderId = exchange.CreateOrder(...) # if orderId: # orderCount += 1 # Log("Order created, daily count:", orderCount) # else: # Log("Daily order quota exceeded", "#FF0000") Sleep(1000)
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 每天09:00重置,限制每日开仓100次 let _ = exchange.IO(("quota", "CreateOrder", 100, "@0900")); Log!("Daily order limit: 100 orders, reset at 09:00"); let mut orderCount = 0; loop { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(5000); continue; } let _ticker = exchange.GetTicker("m888"); // 交易逻辑(示例) // match exchange.CreateOrder(None, "buy", -1, 1) { // Ok(_orderId) => { // orderCount += 1; // Log!("Order created, daily count:", orderCount); // } // Err(_) => Log!("Daily order quota exceeded", "#FF0000"), // } Sleep(1000); } }
    c++
    // C++暂不支持
  • 注意事项

    • 必须检查连接状态

      • 使用 API 限流功能前,必须先通过exchange.IO("status")检查与交易服务器的连接状态
      • 在循环中持续检查连接状态,以确保策略稳定运行
    • 配合立即返回模式

      • 建议配合exchange.IO("mode", 0)立即返回模式一起使用
      • 避免行情获取函数的等待影响限流效果
    • 商品期货市场

      • 优宽量化支持的市场为商品期货
      • 合约代码格式示例:rb888(螺纹钢)、m888(豆粕)、i888(铁矿石)、c888(玉米)
    • 限流配置时机

      • 建议在策略初始化阶段配置限流规则
      • 限流配置即时生效,无需重启策略
    • quota 模式时间对齐

      • quota 模式严格对齐时间窗口
      • 例如:设置为 "1s" 时,时间窗口对齐到整秒;设置为 "1m" 时,时间窗口对齐到整分钟
    • delay 模式的时间差异

      • 使用 "delay" 参数时,API 调用时间与日志记录时间可能存在差异
      • 这是由于函数正在等待限流窗口所致,属于正常现象
    • 合理设置限流参数

      • 应根据交易所的实际限制设置参数
      • 预留一定余量,以避免触及交易所的硬性限制

    最佳实践

    • 分级限流策略

      • 针对不同类型的 API 设置不同的限流参数
      • 对重要的交易接口(CreateOrder、CancelOrder)设置更严格的限制
      • 对行情接口可适当放宽
    • 结合实际业务

      • 根据策略的实际调用频率设置限流参数
      • 监控实际调用情况,并动态调整限流参数
    • 异常处理

      • 妥善处理返回 null 的情况
      • 记录超限日志,以便后续分析与优化
    • 测试验证

      • 在模拟环境中充分测试限流配置
      • 验证在各种极端情况下的表现
    • 持续监控

      • 监控 API 调用频率及限流触发情况
      • 定期检查并优化限流配置