Trade
exchange.Buy
exchange.Buy()函数用于下达买单。Buy()函数是交易所对象exchange的成员函数。
Buy()函数操作交易所对象exchange所绑定的交易所账户。exchange对象的成员函数(方法)的用途仅与exchange相关,后续文档中不再赘述。
exchange.Buy(price, amount)
exchange.Buy(price, amount, ...args)示例
-
exchange.Buy()返回的订单编号,可用于查询订单信息和撤销订单。javascriptfunction main() { // 由于是测试代码,未采用商品期货策略的通用架构,此处仅通过 exchange.IO("status") 函数判断,在成功连接期货公司前置机后立即执行测试代码。股票证券无需使用 exchange.IO("status") 判断连接状态 while (!exchange.IO("status")) { Sleep(1000) } // 设置合约代码 exchange.SetContractType("rb888") // 设置下单方向 exchange.SetDirection("buy") // 注意,此处的下单价格 100 仅为示例,实际测试时可自行设置和修改 var id = exchange.Buy(100, 1) Log("id:", id) }pythondef main(): while not exchange.IO("status"): Sleep(1000) exchange.SetContractType("rb888") exchange.SetDirection("buy") id = exchange.Buy(100, 1) Log("id:", id)rustfn main() { // 由于是测试代码,未采用商品期货策略的通用架构,此处仅通过 exchange.IO("status") 函数判断,在成功连接期货公司前置机后立即执行测试代码。股票证券无需使用 exchange.IO("status") 判断连接状态 while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 设置合约代码 let _ = exchange.SetContractType("rb888"); // 设置下单方向 let _ = exchange.SetDirection("buy"); // 注意,此处的下单价格 100 仅为示例,实际测试时可自行设置和修改 let id = exchange.Buy(100, 1); Log!("id:", id); }c++void main() { while (exchange.IO("status") == 0) { Sleep(1000); } exchange.SetContractType("rb888"); exchange.SetDirection("buy"); auto id = exchange.Buy(100, 1); Log("id:", id); } -
商品期货和股票证券除了可以使用市价单(价格参数传入 -1,实际上系统会使用一个较高的买入价或较低的卖出价来确保成交),还可以使用限价单方式下单。此时可以设置一个较大的滑点,以确保与对手盘成交,具体请参看
exchange.Sell中的范例。javascriptfunction main() { // 由于是测试代码,未采用商品期货策略的通用架构,这里仅通过 exchange.IO("status") 函数判断成功连接期货公司前置机后立即执行测试代码。股票证券无需使用 exchange.IO("status") 判断连接状态 while (!exchange.IO("status")) { Sleep(1000) } // 设置合约代码 exchange.SetContractType("rb888") // 设置下单方向 exchange.SetDirection("buy") // 下单价格参数传入 -1 即为市价单 var id = exchange.Buy(-1, 1) Log("id:", id) }pythondef main(): while not exchange.IO("status"): Sleep(1000) exchange.SetContractType("rb888") exchange.SetDirection("buy") id = exchange.Buy(-1, 1) Log("id:", id)rustfn main() { // 由于是测试代码,未采用商品期货策略的通用架构,这里仅通过 exchange.IO("status") 函数判断成功连接期货公司前置机后立即执行测试代码。股票证券无需使用 exchange.IO("status") 判断连接状态 while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 设置合约代码 let _ = exchange.SetContractType("rb888"); // 设置下单方向 let _ = exchange.SetDirection("buy"); // 下单价格参数传入 -1 即为市价单 let id = exchange.Buy(-1, 1); Log!("id:", id); }c++void main() { while (exchange.IO("status") == 0) { Sleep(1000); } exchange.SetContractType("rb888"); exchange.SetDirection("buy"); auto id = exchange.Buy(-1, 1); Log("id:", id); }
返回值
| 类型 | 描述 |
string / 空值 | 下单成功时返回订单Id,下单失败时返回空值。 |
参数
| 名称 | 类型 | 必填 | 描述 |
price | number | 是 |
|
amount | number | 是 |
|
arg | string / number / bool / object / array / any (系统支持的所有类型) | 否 | 扩展参数,可用于向该条下单日志中输出附带信息。 |
参考
备注
期货合约下单时,必须注意交易方向是否设置正确。如果交易方向与交易函数不匹配,将会报错。参考:exchange.SetDirection
参数price设置为-1时用于下达市价单,回测系统与实盘环境均支持市价单。
股票证券下单:
下单量为股票股数,而非股票手数(在股票证券交易所对象中,如无特殊说明,相关的量均指股票股数)。下单量需符合股票信息中的每手股数要求。例如,02333.HK为港股长城汽车,每手500股,下单量必须是500的整数倍;601633.SH为A股长城汽车,每手100股,下单量必须是100的整数倍。每手股数可以从SetContractType函数返回的数据结构中获取(VolumeMultiple字段),也可以从GetTicker()函数返回的数据结构的Info属性中获取(LotSize字段)。
exchange.Sell
exchange.Sell()函数用于下达卖单。
exchange.Sell(price, amount)
exchange.Sell(price, amount, ...args)示例
-
exchange.Sell()返回的订单编号,可用于查询订单信息及撤销订单。javascriptfunction main(){ // 鉴于测试代码,不使用商品期货策略一般架构,这里仅仅判断exchange.IO("status")函数,判断连接期货公司前置机成功后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态 while (!exchange.IO("status")) { Sleep(1000) } // 设置合约代码 exchange.SetContractType("rb888") // 设置下单方向 exchange.SetDirection("sell") // 注意,这里的下单价格100为举例,具体测试的时候可以自行设置、改动 var id = exchange.Sell(100, 1) Log("id:", id) }pythondef main(): while not exchange.IO("status"): Sleep(1000) exchange.SetContractType("rb888") exchange.SetDirection("sell") id = exchange.Sell(100, 1) Log("id:", id)rustfn main() { // 鉴于测试代码,不使用商品期货策略一般架构,这里仅仅判断exchange.IO("status")函数,判断连接期货公司前置机成功后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态 while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 设置合约代码 let _ = exchange.SetContractType("rb888"); // 设置下单方向 let _ = exchange.SetDirection("sell"); // 注意,这里的下单价格100为举例,具体测试的时候可以自行设置、改动 let id = exchange.Sell(100, 1); Log!("id:", id); }c++void main() { while (exchange.IO("status") == 0) { Sleep(1000); } exchange.SetContractType("rb888"); exchange.SetDirection("sell"); auto id = exchange.Sell(100, 1); Log("id:", id); } -
商品期货除了可以使用市价单下单外,还可以使用限价单下单。此时可设置一个较大的滑价,以确保与对手盘成交。
javascriptfunction main() { while(true) { if (exchange.IO("status")) { // 设置当前合约为 rb2001,测试时请根据回测时间设置合适的合约 exchange.SetContractType("rb2001") exchange.SetDirection("buy") // 获取当前行情 var ticker = exchange.GetTicker() // 获取当前卖一价格 var currSell1Price = ticker.Sell // 加 50 元滑价,即以比卖一挂单价高 50 的价格买入 1 手 var id = exchange.Buy(currSell1Price + 50, 1) Log(exchange.GetOrder(id)) break } else { Log("未连接") } } }pythondef main(): while True: if exchange.IO("status"): exchange.SetContractType("rb2001") exchange.SetDirection("buy") ticker = exchange.GetTicker() currSell1Price = ticker["Sell"] id = exchange.Buy(currSell1Price + 50, 1) Log(exchange.GetOrder(id)) break else : Log("未连接")rustfn main() { loop { if exchange.IO("status").unwrap_or_default() == "true" { // 设置当前合约为 rb2001,测试时请根据回测时间设置合适的合约 let _ = exchange.SetContractType("rb2001"); let _ = exchange.SetDirection("buy"); // 获取当前行情 let ticker = exchange.GetTicker(None).unwrap(); // 获取当前卖一价格 let currSell1Price = ticker.Sell; // 加 50 元滑价,即以比卖一挂单价高 50 的价格买入 1 手 let id = exchange.Buy(currSell1Price + 50.0, 1).unwrap(); Log!(exchange.GetOrder(&id)); break; } else { Log!("未连接"); } } }c++void main() { while(true) { if(exchange.IO("status") == 1) { exchange.SetContractType("rb2001"); exchange.SetDirection("buy"); auto ticker = exchange.GetTicker(); auto currSell1Price = ticker.Sell; auto id = exchange.Buy(currSell1Price + 50, 1); Log(exchange.GetOrder(id)); break; } else { Log("未连接"); } } }
返回值
| 类型 | 描述 |
string / 空值 | 下单成功时返回订单Id,下单失败时返回空值。参考 |
参数
| 名称 | 类型 | 必填 | 描述 |
price | number | 是 |
|
amount | number | 是 |
|
arg | string / number / bool / object / array / any (系统支持的所有类型) | 否 | 扩展参数,可用于将附带信息输出到该条下单日志中, |
参考
备注
期货合约下单时务必注意交易方向是否设置正确,若交易方向与交易函数不匹配将会报错。参考:exchange.SetDirection
参数price设置为-1时用于下达市价单,回测系统与实盘环境均支持市价单。
下单量为股票股数,而非股票手数(在股票证券交易所对象中,若无特殊说明,相关的量均指股票股数)。下单量需符合股票信息中每手股数的要求。参考exchange.Buy。
exchange.CreateOrder
exchange.CreateOrder()函数用于下单。
exchange.CreateOrder(symbol, side, price, amount)
exchange.CreateOrder(symbol, side, price, amount, ...args)示例
商品期货交易所对象调用exchange.CreateOrder()函数下单。
javascript
function main() {
while(!exchange.IO("status")) {
Sleep(1000)
}
// 调用CreateOrder函数下单
var id = exchange.CreateOrder("rb2410", "buy", 3500, 1)
Log(id)
}
python
def main():
while not exchange.IO("status"):
Sleep(1000)
id = exchange.CreateOrder("rb2410", "buy", 3500, 1)
Log(id)
rust
fn main() {
while exchange.IO("status").unwrap_or_default() != "true" {
Sleep(1000);
}
// 调用CreateOrder函数下单
let id = exchange.CreateOrder("rb2410", "buy", 3500, 1);
Log!(id);
}
c++
void main() {
while (exchange.IO("status") == 0) {
Sleep(1000);
}
auto id = exchange.CreateOrder("rb2410", "buy", 3500, 1);
Log(id);
}返回值
| 类型 | 描述 |
string / 空值 | 下单成功时返回订单ID,下单失败时返回空值。 |
参数
| 名称 | 类型 | 必填 | 描述 |
symbol | string | 是 | 参数 |
side | string | 是 |
其中, |
price | number | 是 |
|
amount | number | 是 |
|
arg | string / number / bool / object / array / any (系统支持的所有类型) | 否 | 扩展参数,用于向该条下单日志输出附带信息, |
参考
exchange.Buy exchange.Sell exchange.IO(API限流控制)
exchange.CancelOrder
exchange.CancelOrder()函数用于取消订单。
exchange.CancelOrder(orderId)
exchange.CancelOrder(orderId, ...args)示例
-
撤销订单。
javascriptfunction main(){ // 由于是测试代码,未采用商品期货策略的通用架构,此处仅通过 exchange.IO("status") 函数判断成功连接期货公司前置机后,立即执行测试代码。股票证券无需使用 exchange.IO("status") 判断连接状态 while (!exchange.IO("status")) { Sleep(1000) } // 设置合约代码 exchange.SetContractType("rb888") // 设置下单方向 exchange.SetDirection("sell") // 下单价格仅为示例,价格过高将无法成交,订单会停留在订单簿中等待成交,具体测试时可自行调整价格 var id = exchange.Sell(99999, 1) exchange.CancelOrder(id) }pythondef main(): while not exchange.IO("status"): Sleep(1000) exchange.SetContractType("rb888") exchange.SetDirection("sell") id = exchange.Sell(99999, 1) exchange.CancelOrder(id)rustfn main() { // 由于是测试代码,未采用商品期货策略的通用架构,此处仅通过 exchange.IO("status") 函数判断成功连接期货公司前置机后,立即执行测试代码。股票证券无需使用 exchange.IO("status") 判断连接状态 while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 设置合约代码 let _ = exchange.SetContractType("rb888"); // 设置下单方向 let _ = exchange.SetDirection("sell"); // 下单价格仅为示例,价格过高将无法成交,订单会停留在订单簿中等待成交,具体测试时可自行调整价格 let id = exchange.Sell(99999, 1).unwrap(); let _ = exchange.CancelOrder(&id); }c++void main() { while (exchange.IO("status") == 0) { Sleep(1000); } exchange.SetContractType("rb888"); exchange.SetDirection("sell"); auto id = exchange.Sell(99999, 1); exchange.CancelOrder(id); } -
在优宽量化的API函数中,能够产生日志输出的函数(例如
Log(...)、exchange.Buy(Price, Amount)、exchange.CancelOrder(Id)等)均可在必要参数之后附加一些额外的输出参数。例如:
exchange.CancelOrder(orders[j].Id, orders[j]),即在取消Id为orders[j].Id的订单时,附带输出该订单的信息,也就是orders[j]这个Order结构。javascriptfunction main() { // 由于这是测试代码,未采用商品期货策略的一般架构,这里仅通过exchange.IO("status")函数进行判断,在成功连接期货公司前置机后立即执行测试代码。股票证券则无需使用exchange.IO("status")判断连接状态 while (!exchange.IO("status")) { Sleep(1000) } // 设置合约代码 exchange.SetContractType("rb888") // 设置下单方向 exchange.SetDirection("sell") Log("数据1", "数据2", "数据3", "...") var data2 = 200 // 下单价格仅为示例,价格过高不会成交,订单会处于订单簿中等待成交状态,实际测试时可自行调整价格 var id = exchange.Sell(100000, 0.1, "附带数据1", data2, "...") exchange.CancelOrder(id, "附带数据1", data2, "...") LogProfit(100, "附带数据1", data2, "...") }pythondef main(): while not exchange.IO("status"): Sleep(1000) exchange.SetContractType("rb888") exchange.SetDirection("sell") Log("数据1", "数据2", "数据3", "...") data2 = 200 id = exchange.Sell(100000, 0.1, "附带数据1", data2, "...") exchange.CancelOrder(id, "附带数据1", data2, "...") LogProfit(100, "附带数据1", data2, "...")rustfn main() { // 由于这是测试代码,未采用商品期货策略的一般架构,这里仅通过exchange.IO("status")函数进行判断,在成功连接期货公司前置机后立即执行测试代码。股票证券则无需使用exchange.IO("status")判断连接状态 while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 设置合约代码 let _ = exchange.SetContractType("rb888"); // 设置下单方向 let _ = exchange.SetDirection("sell"); Log!("数据1", "数据2", "数据3", "..."); let data2 = 200; // Rust 不支持在 exchange.Sell()、exchange.CancelOrder()、LogProfit() 等函数中传入附带输出参数,可使用 Log! 宏单独输出附带信息 // 下单价格仅为示例,价格过高不会成交,订单会处于订单簿中等待成交状态,实际测试时可自行调整价格 let id = exchange.Sell(100000, 0.1).unwrap(); Log!("附带数据1", data2, "..."); let _ = exchange.CancelOrder(&id); LogProfit(100); }c++void main() { while (exchange.IO("status") == 0) { Sleep(1000); } exchange.SetContractType("rb888"); exchange.SetDirection("sell"); Log("数据1", "数据2", "数据3", "..."); int data2 = 200; auto id = exchange.Sell(100000, 0.1, "附带数据1", data2, "..."); exchange.CancelOrder(id, "附带数据1", data2, "..."); LogProfit(100, "附带数据1", data2, "..."); }
返回值
| 类型 | 描述 |
bool |
|
参数
| 名称 | 类型 | 必填 | 描述 |
orderId | string | 是 |
|
arg | string / number / bool / object / array / any (系统支持的所有类型) | 否 | 扩展参数,用于向该撤单日志中输出附带信息, |
参考
备注
参数orderId为字符串类型。
exchange.GetOrder
exchange.GetOrder()函数用于获取订单信息。
exchange.GetOrder(orderId)示例
根据指定的订单Id查询订单的详细信息。
javascript
function main(){
// 由于此处为测试代码,未采用商品期货策略的通用架构,仅通过exchange.IO("status")函数判断是否成功连接期货公司前置机,连接成功后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态
while (!exchange.IO("status")) {
Sleep(1000)
}
// 设置合约代码
exchange.SetContractType("rb888")
// 设置下单方向
exchange.SetDirection("sell")
// 此处下单价格仅为示例,价格过高不会成交,订单将处于订单簿中的待成交状态,实际测试时可自行调整价格
var id = exchange.Sell(99999, 1)
// 参数id为订单号,需填入所要查询订单的订单号
var order = exchange.GetOrder(id)
Log("Id:", order.Id, "Price:", order.Price, "Amount:", order.Amount, "DealAmount:",
order.DealAmount, "Status:", order.Status, "Type:", order.Type)
}
python
def main():
while not exchange.IO("status"):
Sleep(1000)
exchange.SetContractType("rb888")
exchange.SetDirection("sell")
id = exchange.Sell(99999, 1)
order = exchange.GetOrder(id)
Log("Id:", order["Id"], "Price:", order["Price"], "Amount:", order["Amount"], "DealAmount:",
order["DealAmount"], "Status:", order["Status"], "Type:", order["Type"])
rust
fn main() {
// 由于此处为测试代码,未采用商品期货策略的通用架构,仅通过exchange.IO("status")函数判断是否成功连接期货公司前置机,连接成功后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态
while exchange.IO("status").unwrap_or_default() != "true" {
Sleep(1000);
}
// 设置合约代码
let _ = exchange.SetContractType("rb888");
// 设置下单方向
let _ = exchange.SetDirection("sell");
// 此处下单价格仅为示例,价格过高不会成交,订单将处于订单簿中的待成交状态,实际测试时可自行调整价格
let id = exchange.Sell(99999, 1).unwrap();
// 参数id为订单号,需填入所要查询订单的订单号
let order = exchange.GetOrder(&id).unwrap();
Log!("Id:", order.Id, "Price:", order.Price, "Amount:", order.Amount, "DealAmount:",
order.DealAmount, "Status:", order.Status, "Type:", order.Type);
}
c++
void main() {
while (exchange.IO("status") == 0) {
Sleep(1000);
}
exchange.SetContractType("rb888");
exchange.SetDirection("sell");
auto id = exchange.Sell(99999, 1);
auto order = exchange.GetOrder(id);
Log("Id:", order.Id, "Price:", order.Price, "Amount:", order.Amount, "DealAmount:",
order.DealAmount, "Status:", order.Status, "Type:", order.Type);
}返回值
| 类型 | 描述 |
| 根据订单号查询订单详情,查询成功时返回 |
参数
| 名称 | 类型 | 必填 | 描述 |
orderId | string | 是 |
|
参考
备注
返回值为Order结构。
exchange.GetOrders
exchange.GetOrders()函数用于获取所有合约当前未完成的订单,并支持查询指定合约的未完成订单。
exchange.GetOrders()
exchange.GetOrders(symbol)示例
-
以较高的价格下单,然后查询未成交订单的信息。
javascriptfunction main(){ // 由于是测试代码,未采用商品期货策略的通用架构,这里仅通过exchange.IO("status")函数进行判断,在成功连接期货公司前置机后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态 while (!exchange.IO("status")) { Sleep(1000) } // 设置合约代码 exchange.SetContractType("rb888") // 设置下单方向 exchange.SetDirection("sell") // 此处的下单价格仅为示例,过高的价格不会成交,订单将处于订单簿中等待成交,实际测试时可自行调整价格 exchange.Sell(99999, 1) exchange.Sell(88888, 1) var orders = exchange.GetOrders() Log("未完成订单一的信息,ID:", orders[0].Id, "Price:", orders[0].Price, "Amount:", orders[0].Amount, "DealAmount:", orders[0].DealAmount, "Type:", orders[0].Type, "Symbol:", orders[0].Symbol) Log("未完成订单二的信息,ID:", orders[1].Id, "Price:", orders[1].Price, "Amount:", orders[1].Amount, "DealAmount:", orders[1].DealAmount, "Type:", orders[1].Type, "Symbol:", orders[1].Symbol) }pythondef main(): while not exchange.IO("status"): Sleep(1000) exchange.SetContractType("rb888") exchange.SetDirection("sell") exchange.Sell(99999, 1) exchange.Sell(88888, 1) orders = exchange.GetOrders() Log("未完成订单一的信息,ID:", orders[0]["Id"], "Price:", orders[0]["Price"], "Amount:", orders[0]["Amount"], "DealAmount:", orders[0]["DealAmount"], "Type:", orders[0]["Type"], "Symbol:", orders[0]["Symbol"]) Log("未完成订单二的信息,ID:", orders[1]["Id"], "Price:", orders[1]["Price"], "Amount:", orders[1]["Amount"], "DealAmount:", orders[1]["DealAmount"], "Type:", orders[1]["Type"], "Symbol:", orders[1]["Symbol"])rustfn main() { // 由于是测试代码,未采用商品期货策略的通用架构,这里仅通过exchange.IO("status")函数进行判断,在成功连接期货公司前置机后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态 while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 设置合约代码 let _ = exchange.SetContractType("rb888"); // 设置下单方向 let _ = exchange.SetDirection("sell"); // 此处的下单价格仅为示例,过高的价格不会成交,订单将处于订单簿中等待成交,实际测试时可自行调整价格 let _ = exchange.Sell(99999, 1); let _ = exchange.Sell(88888, 1); let orders = exchange.GetOrders(None).unwrap(); Log!("未完成订单一的信息,ID:", orders[0].Id, "Price:", orders[0].Price, "Amount:", orders[0].Amount, "DealAmount:", orders[0].DealAmount, "Type:", orders[0].Type, "Symbol:", orders[0].Symbol); Log!("未完成订单二的信息,ID:", orders[1].Id, "Price:", orders[1].Price, "Amount:", orders[1].Amount, "DealAmount:", orders[1].DealAmount, "Type:", orders[1].Type, "Symbol:", orders[1].Symbol); }c++void main() { while (exchange.IO("status") == 0) { Sleep(1000); } exchange.SetContractType("rb888"); exchange.SetDirection("sell"); exchange.Sell(99999, 1); exchange.Sell(88888, 1); auto orders = exchange.GetOrders(); Log("未完成订单一的信息,ID:", orders[0].Id, "Price:", orders[0].Price, "Amount:", orders[0].Amount, "DealAmount:", orders[0].DealAmount, "Type:", orders[0].Type, "Symbol:", orders[0].Symbol); Log("未完成订单二的信息,ID:", orders[1].Id, "Price:", orders[1].Price, "Amount:", orders[1].Amount, "DealAmount:", orders[1].DealAmount, "Type:", orders[1].Type, "Symbol:", orders[1].Symbol); } -
在商品期货和股票证券中,
exchange.GetOrders()函数获取的是所有未完成的订单。在商品期货中,exchange.GetOrders()函数获取的订单与当前设置的合约无关。可以使用以下示例进行回测、模拟盘和实盘测试。javascript/*backtest start: 2020-06-17 10:00:00 end: 2020-06-18 00:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}] */ function main() { var contractTypeList = ["MA009", "rb2010", "i2009"] while (true) { if (exchange.IO("status")) { for (var i = 0; i < contractTypeList.length; i++) { var ret = exchange.SetContractType(contractTypeList[i]) var ticker = exchange.GetTicker() exchange.SetDirection("sell") var id = exchange.Sell(ticker.Sell + 5, 1) Log(contractTypeList[i], "开空仓订单ID:", id) } var orders = exchange.GetOrders() for (var j = 0; j < orders.length; j++) { Log(orders[j]) } break } else { LogStatus(_D(), "未连接") } } }python'''backtest start: 2020-06-17 10:00:00 end: 2020-06-18 00:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}] ''' def main(): contractTypeList = ["MA009", "rb2010", "i2009"] while True: if exchange.IO("status"): for i in range(len(contractTypeList)): ret = exchange.SetContractType(contractTypeList[i]) ticker = exchange.GetTicker() exchange.SetDirection("sell") id = exchange.Sell(ticker["Sell"] + 5, 1) Log(contractTypeList[i], "开空仓订单ID:", id) orders = exchange.GetOrders() for i in range(len(orders)): Log(orders[i]) break else: LogStatus(_D(), "未连接")rust/*backtest start: 2020-06-17 10:00:00 end: 2020-06-18 00:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}] */ fn main() { let contractTypeList = ["MA009", "rb2010", "i2009"]; loop { if exchange.IO("status").unwrap_or_default() == "true" { for i in 0..contractTypeList.len() { let ret = exchange.SetContractType(contractTypeList[i]); let ticker = exchange.GetTicker(None).unwrap(); let _ = exchange.SetDirection("sell"); let id = exchange.Sell(ticker.Sell + 5.0, 1); Log!(contractTypeList[i], "开空仓订单ID:", id); } let orders = exchange.GetOrders(None).unwrap(); for j in 0..orders.len() { Log!(orders[j]); } break; } else { LogStatus!(_D(None), "未连接"); } } }c++/*backtest start: 2020-06-17 10:00:00 end: 2020-06-18 00:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}] */ void main() { vector<string> contractTypeList = {"MA009", "rb2010", "i2009"}; while (true) { if (exchange.IO("status") == 1) { for (int i = 0 ; i < contractTypeList.size(); i++) { auto ret = exchange.SetContractType(contractTypeList[i]); auto ticker = exchange.GetTicker(); exchange.SetDirection("sell"); auto id = exchange.Sell(ticker.Sell + 5.0, 1); Log(contractTypeList[i], "开空仓订单ID:", id); } auto orders = exchange.GetOrders(); for (int j = 0; j < orders.size(); j++) { Log(orders[j]); } break; } else { LogStatus(_D(), "未完成"); } } }
返回值
| 类型 | 描述 |
|
|
参数
| 名称 | 类型 | 必填 | 描述 |
symbol | string | 否 | 参数 |
参考
备注
当交易所对象exchange所代表的账户没有挂单(即处于未成交状态的活动订单)时,调用exchange.GetOrders()函数将返回空数组,即:[]。
exchange.GetOrders()函数不依赖于当前的合约代码设置;当不传入symbol参数时,将获取所有合约的未完成订单。
exchange.GetHistoryOrders
exchange.GetHistoryOrders() 函数用于获取当前交易日内所有合约的历史订单,并支持查询指定合约的历史订单。
exchange.GetHistoryOrders()
exchange.GetHistoryOrders(symbol)示例
javascript
function main(){
// 鉴于测试代码,不使用商品期货策略一般架构,这里仅仅判断exchange.IO("status")函数,判断连接期货公司前置机成功后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态
while (!exchange.IO("status")) {
Sleep(1000)
}
var orders = exchange.GetHistoryOrders()
Log(orders)
}
python
def main():
while not exchange.IO("status"):
Sleep(1000)
orders = exchange.GetHistoryOrders()
Log(orders)
rust
fn main() {
// 鉴于测试代码,不使用商品期货策略一般架构,这里仅仅判断exchange.IO("status")函数,判断连接期货公司前置机成功后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态
while exchange.IO("status").unwrap_or_default() != "true" {
Sleep(1000);
}
let orders = exchange.GetHistoryOrders(None, None, None);
Log!(orders);
}
c++
void main() {
while (exchange.IO("status") == 0) {
Sleep(1000);
}
auto orders = exchange.GetHistoryOrders();
Log(orders);
}返回值
| 类型 | 描述 |
|
|
参数
| 名称 | 类型 | 必填 | 描述 |
symbol | string | 否 |
|
参考
备注
注意:exchange.GetHistoryOrders() 函数不依赖于当前合约代码的设置。未传入 symbol 参数时,获取当前交易日内所有合约的历史订单;传入 symbol 参数时,获取当前交易日内指定合约的历史订单。
exchange.SetPrecision
exchange.SetPrecision()函数用于设置exchange交易所对象的价格精度与下单量精度。设置后,系统会自动截断并忽略超出精度范围的多余部分。
exchange.SetPrecision(pricePrecision, amountPrecision)示例
设置价格精度与下单量精度。
javascript
function main(){
// 设置价格小数位精度为2位,品种下单量小数位精度为3位
exchange.SetPrecision(2, 3)
}
python
def main():
exchange.SetPrecision(2, 3)
rust
fn main() {
// 设置价格小数位精度为2位,品种下单量小数位精度为3位
exchange.SetPrecision(2, 3);
}
c++
void main() {
exchange.SetPrecision(2, 3);
}参数
| 名称 | 类型 | 必填 | 描述 |
pricePrecision | number | 是 |
|
amountPrecision | number | 是 |
|
参考
备注
回测系统不支持该函数,回测系统的数值精度会自动处理。pricePrecision和amountPrecision均必须为整型数值。
exchange.SetRate
设置交易所对象当前的汇率。
exchange.SetRate(rate)示例
设置交易所对象当前的汇率。
javascript
function main(){
// 鉴于测试代码,不使用商品期货策略一般架构,这里仅仅判断exchange.IO("status")函数,判断连接期货公司前置机成功后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态
while (!exchange.IO("status")) {
Sleep(1000)
}
// 设置合约代码
exchange.SetContractType("rb888")
// 设置汇率之前打印行情数据
Log(exchange.GetTicker())
// 设置汇率转换
exchange.SetRate(7)
Log(exchange.GetTicker())
// 设置为1,不转换
exchange.SetRate(1)
Log(exchange.GetTicker())
}
python
def main():
while not exchange.IO("status"):
Sleep(1000)
exchange.SetContractType("rb888")
Log(exchange.GetTicker())
exchange.SetRate(7)
Log(exchange.GetTicker())
exchange.SetRate(1)
Log(exchange.GetTicker())
rust
fn main() {
// 鉴于测试代码,不使用商品期货策略一般架构,这里仅仅判断exchange.IO("status")函数,判断连接期货公司前置机成功后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态
while exchange.IO("status").unwrap_or_default() != "true" {
Sleep(1000);
}
// 设置合约代码
let _ = exchange.SetContractType("rb888");
// 设置汇率之前打印行情数据
Log!(exchange.GetTicker(None));
// 设置汇率转换
exchange.SetRate(7);
Log!(exchange.GetTicker(None));
// 设置为1,不转换
exchange.SetRate(1);
Log!(exchange.GetTicker(None));
}
c++
void main() {
while (exchange.IO("status") == 0) {
Sleep(1000);
}
exchange.SetContractType("rb888");
Log(exchange.GetTicker());
exchange.SetRate(7);
Log(exchange.GetTicker());
exchange.SetRate(1);
Log(exchange.GetTicker());
}参数
| 名称 | 类型 | 必填 | 描述 |
rate | number | 是 |
|
参考
备注
如果使用exchange.SetRate()函数设置了汇率值(例如设置为7),那么当前exchange交易所对象所代表交易所的行情、深度、下单价格等所有价格信息,都会乘以所设置的汇率7进行转换。例如,exchange是以美元为计价货币的交易所,执行exchange.SetRate(7)之后,实盘中所有价格都会乘以7,转换为接近CNY计价的价格。
exchange.IO
exchange.IO()函数用于调用交易所对象相关的协议及其它接口。
exchange.IO(k, ...args)示例
-
使用 status 参数可判断与期货公司前置机的连接状态:
exchange.IO("status"),返回true表示与 CTP 的行情服务器和交易数据服务器均已正常连接。javascriptfunction main() { while (!exchange.IO("status")) { LogStatus("正在等待与交易服务器连接, " + new Date()) } }pythondef main(): while not exchange.IO("status"): LogStatus("正在等待与交易服务器连接, " + _D())rustfn main() { while exchange.IO("status").unwrap_or_default() != "true" { LogStatus!("正在等待与交易服务器连接,", _D(None)); } }c++void main() { while(exchange.IO("status") == 0) { LogStatus("正在等待与交易服务器连接, " + _D()); } } -
使用
wait参数设置阻塞:exchange.IO("wait", Timeout),仅当当前交易所有任意品种的行情信息更新或订单成交时才返回。可通过第二个参数(毫秒数)指定超时时间:超时返回空值,正常返回EventTick/OrderEvent结构。该函数需结合exchange.IO("mode", 0)一起使用,以便程序在有最新行情时及时响应并执行相应逻辑(使用exchange.IO("mode", 0)并不影响exchange.IO("wait"),其作用是使程序中调用exchange.GetTicker()等函数时不发生阻塞)。若Timeout参数设置为-1,该函数将立即返回,在没有新事件时返回空值;若Timeout参数设置为0,则阻塞等待最新事件,效果等同于不设置Timeout参数。需要注意的是,使用exchange.IO("wait")时,必须至少已订阅一个当前处于交易状态的合约(已交割的过期合约不再提供行情数据),否则由于没有任何行情或订单更新,程序将阻塞在该函数处。仅支持商品期货实盘。EventTick:{Event:"tick", Index:交易所索引, Nano:事件纳秒级时间, Symbol:合约名称, Ticker:行情数据}。OrderTick:{Event:"order", Index:交易所索引, Nano:事件纳秒级时间, Order:订单信息}。简单实现回调机制:
javascriptfunction on_tick(symbol, ticker) { Log("symbol:", symbol, "update") Log("ticker:", ticker) } function on_order(order) { Log("order update", order) } function main() { while(!exchange.IO("status")) { Sleep(10) } // 如果在程序中不使用诸如exchange.GetTicker()之类的获取行情的函数,可以不设置exchange.IO("mode", 0) exchange.IO("mode", 0) _C(exchange.SetContractType, "MA005") while(true) { var e = exchange.IO("wait") if(e) { if(e.Event == "tick") { on_tick(e.Symbol, e.Ticker) } else if(e.Event == "order") { on_order(e.Order) } } } }pythondef on_tick(symbol, ticker): Log("symbol:", symbol, "update") # 数据结构:https://www.youquant.com/api#ticker Log("ticker:", ticker) def on_order(order): Log("order update", order) def main(): # wait connect trade server while not exchange.IO("status"): Sleep(10) # switch push mode exchange.IO("mode", 0) # subscribe instrument _C(exchange.SetContractType, "MA001") while True: e = exchange.IO("wait") if e: if e.Event == "tick": on_tick(e['Symbol'], e['Ticker']) elif e.Event == "order": on_order(e['Order'])rustfn on_tick(symbol: &JsonValue, ticker: &JsonValue) { Log!("symbol:", *symbol, "update"); Log!("ticker:", *ticker); } fn on_order(order: &JsonValue) { Log!("order update", *order); } fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(10); } // 如果在程序中不使用诸如exchange.GetTicker()之类的获取行情的函数,可以不设置exchange.IO("mode", 0) let _ = exchange.IO(("mode", 0)); _C!(exchange.SetContractType("MA005")); loop { // exchange.IO("wait")返回的是JSON文本,用JSONParse解析后处理 let e = exchange.IO("wait").unwrap_or_default(); if let Some(e) = JSONParse(&e) { if e["Event"].as_str() == Some("tick") { on_tick(&e["Symbol"], &e["Ticker"]); } else if e["Event"].as_str() == Some("order") { on_order(&e["Order"]); } } } }c++void on_tick(const string &symbol, json &ticker) { Log("symbol:", symbol, "update"); Log("ticker:", ticker); } void on_order(json &order) { Log("order update", order); } void main() { while(exchange.IO("status") == 0) { Sleep(10); } exchange.IO("mode", 0); _C(exchange.SetContractType, "rb2005"); while(true) { auto e = exchange.IO("wait"); if(e != false) { if(e["Event"] == "tick") { on_tick(e["Symbol"], e["Ticker"]); } else if(e["Event"] == "order") { on_order(e["Order"]); } } } } -
多品种回调示例:
javascriptfunction on_tick(symbol, ticker) { Log("symbol:", symbol, "update", "ticker:", ticker) } function main() { while(!exchange.IO("status")) { Sleep(10) } _C(exchange.SetContractType, "MA101") _C(exchange.SetContractType, "rb2101") _C(exchange.SetContractType, "i2101") while(true) { var e = exchange.IO("wait", -1) if(e) { if(e.Event == "tick") { on_tick(e.Symbol, e.Ticker) } } Sleep(10) } }pythondef on_tick(symbol, ticker): Log("symbol:", symbol, "update", "ticker:", ticker) def main(): while not exchange.IO("status"): Sleep(10) _C(exchange.SetContractType, "MA101") _C(exchange.SetContractType, "rb2101") _C(exchange.SetContractType, "i2101") while True: e = exchange.IO("wait", -1) if e: if e.Event == "tick": on_tick(e['Symbol'], e['Ticker']) Sleep(10)rustfn on_tick(symbol: &JsonValue, ticker: &JsonValue) { Log!("symbol:", *symbol, "update", "ticker:", *ticker); } fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(10); } _C!(exchange.SetContractType("MA101")); _C!(exchange.SetContractType("rb2101")); _C!(exchange.SetContractType("i2101")); loop { let e = exchange.IO(("wait", -1)).unwrap_or_default(); if let Some(e) = JSONParse(&e) { if e["Event"].as_str() == Some("tick") { on_tick(&e["Symbol"], &e["Ticker"]); } } Sleep(10); } }c++void on_tick(const string &symbol, json &ticker) { Log("symbol:", symbol, "update", "ticker:", ticker); } void main() { while(exchange.IO("status") == 0) { Sleep(10); } _C(exchange.SetContractType, "MA101"); _C(exchange.SetContractType, "rb2101"); _C(exchange.SetContractType, "i2101"); while(true) { auto e = exchange.IO("wait", -1); if(e != false) { if(e["Event"] == "tick") { on_tick(e["Symbol"], e["Ticker"]); } } } } -
使用
instruments参数获取所有合约的列表数据:exchange.IO("instruments"),返回交易所全部合约的列表,仅支持实盘。javascriptfunction main() { while (!exchange.IO("status")) { LogStatus("正在等待与交易服务器连接, " + new Date()) } Log("开始获取所有合约") var instruments = _C(exchange.IO, "instruments") Log("合约列表获取成功") var len = 0 for (var instrumentId in instruments) { len++ } Log("合约列表长度为:",len) }pythondef main(): while not exchange.IO("status"): LogStatus("正在等待与交易服务器连接, " + _D()) Log("开始获取所有合约") instruments = _C(exchange.IO, "instruments") Log("合约列表获取成功") length = 0 for i in range(len(instruments)): length += 1 Log("合约列表长度为:", length)rustfn main() { while exchange.IO("status").unwrap_or_default() != "true" { LogStatus!("正在等待与交易服务器连接,", _D(None)); } Log!("开始获取所有合约"); let instruments = _C!(exchange.IO("instruments")); Log!("合约列表获取成功"); // 返回的是JSON文本,解析后统计合约个数 let parsed = JSONParse(&instruments).unwrap_or_default(); let mut len = 0; if let Some(obj) = parsed.as_object() { for _instrumentId in obj.keys() { len += 1; } } Log!("合约列表长度为:", len); }c++void main() { while(exchange.IO("status") == 0) { LogStatus("正在等待与交易服务器连接, " + _D()); } Log("开始获取所有合约"); auto instruments = _C(exchange.IO, "instruments"); Log("合约列表获取成功"); int length = 0; for(int i = 0; i < instruments.size(); i++) { length++; } Log("合约列表长度为:", length); } -
使用
products参数获取所有产品的列表数据:
exchange.IO("products"),返回交易所全部产品的列表,仅支持实盘。使用
subscribed参数获取已订阅的合约数据:
exchange.IO("subscribed"),返回已订阅行情的合约,仅支持实盘。使用
settlement参数获取结算单数据:
exchange.IO("settlement")用于查询结算单。若不传入第二个参数,默认返回上一个交易日的数据;若传入如20170317的参数,则返回日期为2017-03-17的结算单,仅支持实盘。使用api参数调用底层接口:
优宽量化的CTP(商品期货)终端提供了完整的全API实现。当发明者平台的API无法满足你所需的功能时,可以使用
exchange.IO函数进行更深层的系统调用,且完全兼容官方的API名称。CTP的IO直接扩展函数调用请求,将在收到第一个isLast标记为true的响应包后返回。CTP协议接口:CTP协议接口相关资料
以下通过几个简单的例子进行说明:
-
查询投资者信息:
javascriptfunction main() { while (!exchange.IO("status")) { LogStatus("正在等待与交易服务器建立连接, " + new Date()) } Log(exchange.IO("api", "ReqQryInvestor")) }pythondef main(): while not exchange.IO("status"): LogStatus("正在等待与交易服务器建立连接, " + _D()) Log(exchange.IO("api", "ReqQryInvestor"))rustfn main() { while exchange.IO("status").unwrap_or_default() != "true" { LogStatus!("正在等待与交易服务器建立连接,", _D(None)); } Log!(exchange.IO(("api", "ReqQryInvestor"))); }c++void main() { while(exchange.IO("status") == 0) { LogStatus("正在等待与交易服务器建立连接, " + _D()); } Log(exchange.IO("api", "ReqQryInvestor")); } -
修改密码:
javascriptfunction main() { // CTP 协议建立连接需要一定时间 Sleep(6000) exchange.IO("api", "ReqUserPasswordUpdate", {BrokerID: "9999", UserID: "11111", OldPassword: "oldpass", NewPassword: "newpass"}) }pythondef main(): Sleep(6000) exchange.IO("api", "ReqUserPasswordUpdate", {"BrokerID": "9999", "UserID": "11111", "OldPassword": "oldpass", "NewPassword": "newpass"})rustfn main() { // CTP 协议建立连接需要一定时间 Sleep(6000); let _ = exchange.IO(("api", "ReqUserPasswordUpdate", r#"{"BrokerID": "9999", "UserID": "11111", "OldPassword": "oldpass", "NewPassword": "newpass"}"#)); }c++void main() { Sleep(6000); exchange.IO("api", "ReqUserPasswordUpdate", R"({"BrokerID": "9999", "UserID": "11111", "OldPassword": "oldpass", "NewPassword": "newpass"})"_json); } -
复杂示例:
javascriptfunction main() { // CTP 协议建立连接需要一定时间 Sleep(6000) // 若增加一个值为 false 的参数,表示不等待返回值,仅发送请求;第三个参数只需填充所需的字段,也可省略此参数;若字段类型为 char,传入长度为 1 的字符串即可 var r = exchange.IO("api", "ReqQryProduct", {ProductID: "MA"}) // CTP 未登录时调用会失败 if (!r) { return } _.each(r, function(item) { // IO 请求可能返回多个数据包,因此以数组形式返回。遍历数据包中的所有数据类型;一个数据包可能包含多条具体数据,具体数据类型的名称请参阅 CTP 官方文档 http://www.sfit.com.cn/5_2_DocumentDown.htm _.each(item, function(f) { // 取出所需的数据,Name 为该数据的类型,Value 为该数据的值 if (f.Name == 'CThostFtdcProductField') { // 打印查询到的甲醇合约信息 Log(f.Value) } }) }); }pythondef main(): Sleep(6000) r = exchange.IO("api", "ReqQryProduct", {"ProductID": "MA"}) if not r: return for r_index in range(len(r)): for f_index in range(len(r[r_index])): if r[r_index][f_index]["Name"] == 'CThostFtdcProductField': Log(r[r_index][f_index]["Value"])rustfn main() { // CTP 协议建立连接需要一定时间 Sleep(6000); // 第三个参数只需填充所需的字段(JSON 文本形式);若字段类型为 char,传入长度为 1 的字符串即可 let r = exchange.IO(("api", "ReqQryProduct", r#"{"ProductID": "MA"}"#)).unwrap_or_default(); // CTP 未登录时调用会失败 let r = match JSONParse(&r) { Some(v) => v, None => return, }; // IO 请求可能返回多个数据包,因此以数组形式返回。遍历数据包中的所有数据类型;一个数据包可能包含多条具体数据,具体数据类型的名称请参阅 CTP 官方文档 http://www.sfit.com.cn/5_2_DocumentDown.htm if let Some(packets) = r.as_array() { for item in packets { if let Some(fields) = item.as_array() { for f in fields { // 取出所需的数据,Name 为该数据的类型,Value 为该数据的值 if f["Name"].as_str() == Some("CThostFtdcProductField") { // 打印查询到的甲醇合约信息 Log!(f["Value"]); } } } } } }c++void main() { Sleep(6000); auto r = exchange.IO("api", "ReqQryProduct", R"({"ProductID": "MA"})"_json); if(r == false) { return; } for(auto& ele1 : r.items()) { for(auto& ele2 : ele1.value().items()) { if(ele2.value()["Name"] == "CThostFtdcProductField") { Log(ele2.value()["Value"]); } } } } -
复杂的示例:
javascriptfunction main() { while (!exchange.IO("status")) { LogStatus("正在等待与交易服务器建立连接, " + new Date()) } // 也可不指定日期 var r = exchange.IO("api", "ReqQrySettlementInfo", {TradingDay: "20190506"}) var s = '' _.each(r, function(item) { _.each(item, function(f) { if (f.Name == 'CThostFtdcSettlementInfoField') { s += f.Value.Content } }) }) Log(s) }pythondef main(): while not exchange.IO("status"): LogStatus("正在等待与交易服务器建立连接, " + _D()) r = exchange.IO("api", "ReqQrySettlementInfo", {"TradingDay": "20190506"}) s = '' for i in range(len(r)): for ii in range(len(r[i])): if r[i][ii]["Name"] == "CThostFtdcSettlementInfoField": s += r[i][ii]["Value"]["Content"] Log(s)rustfn main() { while exchange.IO("status").unwrap_or_default() != "true" { LogStatus!("正在等待与交易服务器建立连接,", _D(None)); } // 也可不指定日期 let r = exchange.IO(("api", "ReqQrySettlementInfo", r#"{"TradingDay": "20190506"}"#)).unwrap_or_default(); let parsed = JSONParse(&r).unwrap_or_default(); let mut s = String::new(); if let Some(packets) = parsed.as_array() { for item in packets { if let Some(fields) = item.as_array() { for f in fields { if f["Name"].as_str() == Some("CThostFtdcSettlementInfoField") { s += f["Value"]["Content"].as_str().unwrap_or(""); } } } } } Log!(s); }c++void main() { while(exchange.IO("status") == 0) { LogStatus("正在等待与交易服务器建立连接, " + _D()); } auto r = exchange.IO("api", "ReqQrySettlementInfo", R"({"TradingDay": "20200311"})"_json); string s = ""; for(auto& ele1 : r.items()) { for(auto& ele2 : ele1.value().items()) { if(ele2.value()["Name"] == "CThostFtdcSettlementInfoField") { s += std::string(ele2.value()["Value"]["Content"]); } } } Log(s); } -
限制 GetTicker 每秒最多调用 3 次,超出限制时报错并返回空值:
javascriptfunction main() { // 等待与交易服务器建立连接 while (!exchange.IO("status")) { LogStatus("正在等待与交易服务器建立连接, " + new Date()) Sleep(1000) } // 场景1:限制 GetTicker 每秒最多调用 3 次,超出限制时返回 null exchange.IO("rate", "GetTicker", 3, "1s") for (var i = 0; i < 10; i++) { if (!exchange.IO("status")) { Log("Exchange not ready, waiting...", "#FF0000") Sleep(5000) continue } var ticker = exchange.GetTicker("rb888") // 螺纹钢主力合约 if (ticker) { Log("Call", i+1, "Success, Price:", ticker.Last) } else { Log("Call", i+1, "Failed: Rate limit exceeded", "#FF0000") } Sleep(100) } }pythondef main(): # 等待与交易服务器建立连接 while not exchange.IO("status"): LogStatus("正在等待与交易服务器建立连接, " + _D()) Sleep(1000) # 场景1:限制 GetTicker 每秒最多调用 3 次,超出限制时返回 null exchange.IO("rate", "GetTicker", 3, "1s") for i in range(10): if not exchange.IO("status"): Log("Exchange not ready, waiting...", "#FF0000") Sleep(5000) continue ticker = exchange.GetTicker("rb888") # 螺纹钢主力合约 if ticker: Log("Call", i+1, "Success, Price:", ticker["Last"]) else: Log("Call", i+1, "Failed: Rate limit exceeded", "#FF0000") Sleep(100)rustfn main() { // 等待与交易服务器建立连接 while exchange.IO("status").unwrap_or_default() != "true" { LogStatus!("正在等待与交易服务器建立连接,", _D(None)); Sleep(1000); } // 场景1:限制 GetTicker 每秒最多调用 3 次,超出限制时返回错误 let _ = exchange.IO(("rate", "GetTicker", 3, "1s")); for i in 0..10 { if exchange.IO("status").unwrap_or_default() != "true" { Log!("Exchange not ready, waiting...", "#FF0000"); Sleep(5000); continue; } // 螺纹钢主力合约 match exchange.GetTicker("rb888") { Ok(ticker) => Log!("Call", i + 1, "Success, Price:", ticker.Last), Err(_) => Log!("Call", i + 1, "Failed: Rate limit exceeded", "#FF0000"), } Sleep(100); } }c++void main() { // 等待与交易服务器建立连接 while (exchange.IO("status") == 0) { LogStatus("正在等待与交易服务器建立连接, " + _D()); Sleep(1000); } // 场景1:限制 GetTicker 每秒最多调用 3 次,超出限制时返回无效数据 exchange.IO("rate", "GetTicker", 3, "1s"); for (int i = 0; i < 10; i++) { if (exchange.IO("status") == 0) { Log("Exchange not ready, waiting...", "#FF0000"); Sleep(5000); continue; } auto ticker = exchange.GetTicker("rb888"); // 螺纹钢主力合约 if (ticker.Valid) { Log("Call", i + 1, "Success, Price:", ticker.Last); } else { Log("Call", i + 1, "Failed: Rate limit exceeded", "#FF0000"); } Sleep(100); } } -
限制 GetTicker 每秒最多调用 3 次,超出频率限制时自动等待:
javascriptfunction main() { while (!exchange.IO("status")) { Sleep(1000) } // 场景 2:使用 delay 参数,超出频率限制时自动等待 exchange.IO("rate", "GetTicker", 3, "1s", "delay") Log("Start testing delay mode with m888 (soybean meal)", "#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() if (ticker) { Log("Call", i+1, "Price:", ticker.Last, "Time cost:", endTime - startTime, "ms") } } }pythonimport time def main(): while not exchange.IO("status"): Sleep(1000) # 场景 2:使用 delay 参数,超出频率限制时自动等待 exchange.IO("rate", "GetTicker", 3, "1s", "delay") Log("Start testing delay mode with m888 (soybean meal)", "#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 if ticker: Log("Call", i+1, "Price:", ticker["Last"], "Time cost:", endTime - startTime, "ms")rustfn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 场景 2:使用 delay 参数,超出频率限制时自动等待 let _ = exchange.IO(("rate", "GetTicker", 3, "1s", "delay")); Log!("Start testing delay mode with m888 (soybean meal)", "#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; if let Ok(ticker) = ticker { Log!("Call", i + 1, "Price:", ticker.Last, "Time cost:", endTime - startTime, "ms"); } } }c++void main() { while (exchange.IO("status") == 0) { Sleep(1000); } // 场景 2:使用 delay 参数,超出频率限制时自动等待 exchange.IO("rate", "GetTicker", 3, "1s", "delay"); Log("Start testing delay mode with m888 (soybean meal)", "#00FF00"); for (int i = 0; i < 10; i++) { if (exchange.IO("status") == 0) { Sleep(5000); continue; } auto startTime = UnixNano() / 1000000; auto ticker = exchange.GetTicker("m888"); // 豆粕主力合约 auto endTime = UnixNano() / 1000000; if (ticker.Valid) { Log("Call", i + 1, "Price:", ticker.Last, "Time cost:", endTime - startTime, "ms"); } } } -
限制多个函数的联合调用频率:
javascriptfunction main() { while (!exchange.IO("status")) { Sleep(1000) } // 场景3: GetTicker 与 GetDepth 共享调用频率限制,合计每秒最多 5 次 exchange.IO("mode", 0) // 切换为接口立即返回模式 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("i888") // 铁矿石主力合约 Log("Call", i+1, "GetTicker:", ticker ? "Success" : "Failed") } else { var depth = exchange.GetDepth("i888") Log("Call", i+1, "GetDepth:", depth ? "Success" : "Failed") } Sleep(100) } }pythondef main(): while not exchange.IO("status"): Sleep(1000) # 场景3: GetTicker 与 GetDepth 共享调用频率限制,合计每秒最多 5 次 exchange.IO("mode", 0) # 切换为接口立即返回模式 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("i888") # 铁矿石主力合约 Log("Call", i+1, "GetTicker:", "Success" if ticker else "Failed") else: depth = exchange.GetDepth("i888") Log("Call", i+1, "GetDepth:", "Success" if depth else "Failed") Sleep(100)rustfn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 场景3: GetTicker 与 GetDepth 共享调用频率限制,合计每秒最多 5 次 let _ = exchange.IO(("mode", 0)); // 切换为接口立即返回模式 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("i888"); Log!("Call", i + 1, "GetTicker:", if ticker.is_ok() { "Success" } else { "Failed" }); } else { let depth = exchange.GetDepth("i888"); Log!("Call", i + 1, "GetDepth:", if depth.is_ok() { "Success" } else { "Failed" }); } Sleep(100); } }c++void main() { while (exchange.IO("status") == 0) { Sleep(1000); } // 场景3: GetTicker 与 GetDepth 共享调用频率限制,合计每秒最多 5 次 exchange.IO("mode", 0); // 切换为接口立即返回模式 exchange.IO("rate", "GetTicker,GetDepth", 5, "1s"); for (int i = 0; i < 10; i++) { if (exchange.IO("status") == 0) { Sleep(5000); continue; } if (i % 2 == 0) { auto ticker = exchange.GetTicker("i888"); // 铁矿石主力合约 Log("Call", i + 1, "GetTicker:", ticker.Valid ? "Success" : "Failed"); } else { auto depth = exchange.GetDepth("i888"); Log("Call", i + 1, "GetDepth:", depth.Valid ? "Success" : "Failed"); } Sleep(100); } } -
使用通配符限制所有 API 调用的频率:
javascriptfunction main() { while (!exchange.IO("status")) { Sleep(1000) } // 场景 4:将所有 API 调用限制为每秒最多 5 次 exchange.IO("mode", 0) // 设置为立即返回模式 exchange.IO("rate", "*", 5, "1s") var symbols = ["rb888", "m888", "i888"] // 螺纹钢、豆粕、铁矿石 for (var i = 0; i < 10; i++) { if (!exchange.IO("status")) { Sleep(5000) continue } var symbol = symbols[i % symbols.length] var ticker = exchange.GetTicker(symbol) var depth = exchange.GetDepth(symbol) var account = exchange.GetAccount() Log("Round", i+1, symbol, "Ticker:", ticker ? "✓" : "✗", "Depth:", depth ? "✓" : "✗", "Account:", account ? "✓" : "✗") Sleep(100) } }pythondef main(): while not exchange.IO("status"): Sleep(1000) # 场景 4:将所有 API 调用限制为每秒最多 5 次 exchange.IO("mode", 0) # 设置为立即返回模式 exchange.IO("rate", "*", 5, "1s") symbols = ["rb888", "m888", "i888"] # 螺纹钢、豆粕、铁矿石 for i in range(10): if not exchange.IO("status"): Sleep(5000) continue symbol = symbols[i % len(symbols)] ticker = exchange.GetTicker(symbol) depth = exchange.GetDepth(symbol) account = exchange.GetAccount() Log("Round", i+1, symbol, "Ticker:", "✓" if ticker else "✗", "Depth:", "✓" if depth else "✗", "Account:", "✓" if account else "✗") Sleep(100)rustfn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 场景 4:将所有 API 调用限制为每秒最多 5 次 let _ = exchange.IO(("mode", 0)); // 设置为立即返回模式 let _ = exchange.IO(("rate", "*", 5, "1s")); let symbols = ["rb888", "m888", "i888"]; // 螺纹钢、豆粕、铁矿石 for i in 0..10 { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(5000); continue; } let symbol = symbols[i % symbols.len()]; let ticker = exchange.GetTicker(symbol); let depth = exchange.GetDepth(symbol); let account = exchange.GetAccount(); Log!("Round", i + 1, symbol, "Ticker:", if ticker.is_ok() { "✓" } else { "✗" }, "Depth:", if depth.is_ok() { "✓" } else { "✗" }, "Account:", if account.is_ok() { "✓" } else { "✗" }); Sleep(100); } }c++void main() { while (exchange.IO("status") == 0) { Sleep(1000); } // 场景 4:将所有 API 调用限制为每秒最多 5 次 exchange.IO("mode", 0); // 设置为立即返回模式 exchange.IO("rate", "*", 5, "1s"); std::vector<string> symbols = {"rb888", "m888", "i888"}; // 螺纹钢、豆粕、铁矿石 for (int i = 0; i < 10; i++) { if (exchange.IO("status") == 0) { Sleep(5000); continue; } auto symbol = symbols[i % symbols.size()]; auto ticker = exchange.GetTicker(symbol); auto depth = exchange.GetDepth(symbol); auto account = exchange.GetAccount(); Log("Round", i + 1, symbol, "Ticker:", ticker.Valid ? "✓" : "✗", "Depth:", depth.Valid ? "✓" : "✗", "Account:", account.Valid ? "✓" : "✗"); Sleep(100); } } -
使用 quota 模式实现严格的时间窗口对齐限流:
javascriptfunction main() { while (!exchange.IO("status")) { Sleep(1000) } // 场景5:quota 模式,严格的时间窗口对齐 exchange.IO("mode", 0) // 切换到立即返回模式 exchange.IO("quota", "GetTicker", 3, "1s") Log("Testing quota mode with c888 (corn)", "#00FF00") 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 调用一次,每秒约 6-7 次 } }pythondef main(): while not exchange.IO("status"): Sleep(1000) # 场景5:quota 模式,严格的时间窗口对齐 exchange.IO("mode", 0) # 切换到立即返回模式 exchange.IO("quota", "GetTicker", 3, "1s") Log("Testing quota mode with c888 (corn)", "#00FF00") 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 调用一次,每秒约 6-7 次rustfn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 场景5:quota 模式,严格的时间窗口对齐 let _ = exchange.IO(("mode", 0)); // 切换到立即返回模式 let _ = exchange.IO(("quota", "GetTicker", 3, "1s")); Log!("Testing quota mode with c888 (corn)", "#00FF00"); 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 调用一次,每秒约 6-7 次 } }c++void main() { while (exchange.IO("status") == 0) { Sleep(1000); } // 场景5:quota 模式,严格的时间窗口对齐 exchange.IO("mode", 0); // 切换到立即返回模式 exchange.IO("quota", "GetTicker", 3, "1s"); Log("Testing quota mode with c888 (corn)", "#00FF00"); for (int i = 0; i < 8; i++) { if (exchange.IO("status") == 0) { Sleep(5000); continue; } auto ticker = exchange.GetTicker("c888"); // 玉米主力合约 Log(_D(), "Call", i + 1, ticker.Valid ? "Success" : "Quota exceeded"); Sleep(150); // 每 150ms 调用一次,每秒约 6-7 次 } }
返回值
| 类型 | 描述 |
string / number / bool / object / array / any (系统支持的所有类型) |
|
参数
| 名称 | 类型 | 必填 | 描述 |
k | string | 是 |
|
arg | string / number / bool / object / array / any (系统支持的所有类型) | 是 | 扩展参数,根据具体的调用场景传入, |
参考
备注
使用mode参数切换行情模式:
-
exchange.IO("mode", 0)
立即返回模式。如果当前尚未接收到交易所最新的行情数据推送,则立即返回旧的行情数据;如果已有新数据,则返回新数据。
商品期货中的应用可参考:exchange.IO 函数 wait 参数的使用示例。 -
exchange.IO("mode", 1)
缓存模式(默认模式)。如果当前尚未收到交易所最新的行情数据(与上一次接口获取的数据相比),则等待接收后再返回;如果在调用该函数之前已收到最新的行情数据,则立即返回最新数据。 -
exchange.IO("mode", 2)
强制更新模式,进入等待状态,直到接收到交易所下一次最新推送的数据后返回。
API限流控制功能:
优宽量化平台支持对交易所 API 调用进行频率限制,以避免触发交易所自身的频率限制。平台支持两种限流模式:
-
rate模式(平滑限流):不严格对齐时间窗口,适用于一般的限流需求。
-
quota模式(额度限流):严格对齐时间窗口,例如 1m 对齐到整分钟,1s 对齐到整秒。
函数签名:
javascript
exchange.IO("rate", functionNames, maxCalls, period, [behavior])
exchange.IO("quota", functionNames, maxCalls, period, [behavior])
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| mode | string | 限流模式:"rate"(平滑限流)或 "quota"(额度限流) |
| functionNames | string | 需要限流的函数名,支持单个函数、多个函数(以逗号分隔)或通配符(* 表示所有函数) |
| maxCalls | number | 时间周期内允许的最大调用次数 |
| period | string | 时间周期或重置时间点。支持的时间单位:ns, us, µs, ms, s, m, h, d(例如:"1s", "1m", "1h");支持的重置时间点格式:@HHMM 或 @HHMMSS(例如:"@0815" 表示每天 08:15 重置) |
| behavior | string | 可选参数,用于设置超限行为。默认为空(超限时返回 null 并报错);设置为 "delay" 时,超限会等待 |
支持的函数列表:
交易类:CreateOrder, CancelOrder
账户类:GetAccount, GetPositions
订单类:GetOrder, GetOrders, GetHistoryOrders
行情类:GetTicker, GetDepth, GetRecords
其它:IO/api
注意事项:
-
优宽量化支持的市场:商品期货(如螺纹钢 rb888、豆粕 m888 等)
-
使用 API 限流功能前,必须先通过
exchange.IO("status")进行检查,确保与交易服务器的连接正常 -
建议配合
exchange.IO("mode", 0)立即返回模式使用,以避免不必要的等待 -
IO/api的限流仅对exchange.IO("api", ...)调用生效 -
quota模式严格对齐时间窗口,例如设置
"1s"时,时间窗口按整秒对齐 -
使用
"delay"参数时,调用时间与日志记录时间之间可能存在差异,这属于正常现象
exchange.Log
exchange.Log()函数用于在日志栏区域输出下单、撤单日志。该函数被调用时不会实际下单,仅用于输出和记录交易日志。
exchange.Log(orderType, price, amount)
exchange.Log(orderType, price, amount, ...args)示例
使用exchange.Log(orderType, price, amount)可以进行实盘跟单测试和模拟下单,也可以辅助记录下单信息。
javascript
var id = 123
function main() {
// 下单类型买入,价格999,数量 0.1
exchange.Log(LOG_TYPE_BUY, 999, 0.1)
// 取消订单
exchange.Log(LOG_TYPE_CANCEL, id)
}
python
id = 123
def main():
exchange.Log(LOG_TYPE_BUY, 999, 0.1)
exchange.Log(LOG_TYPE_CANCEL, id)
rust
fn main() {
let id = 123;
// 下单类型买入,价格999,数量 0.1
exchange.Log(LOG_TYPE_BUY, 999, 0.1);
// 取消订单,orderType为LOG_TYPE_CANCEL时price参数为撤单的订单Id(Rust中amount参数必传,可传0)
exchange.Log(LOG_TYPE_CANCEL, id, 0);
}
c++
void main() {
auto id = 123;
exchange.Log(LOG_TYPE_BUY, 999, 0.1);
exchange.Log(LOG_TYPE_CANCEL, id);
}参数
| 名称 | 类型 | 必填 | 描述 |
orderType | number | 是 |
|
price | number | 是 |
|
amount | number | 是 |
|
arg | string / number / bool / object / array / any (系统支持的所有类型) | 否 | 扩展参数,用于向该条日志输出附带信息, |
参考
备注
当orderType参数为LOG_TYPE_CANCEL时,price参数表示撤单的订单Id,用于在直接调用exchange.IO()函数撤单时打印撤单日志。exchange.Log()函数是exchange交易所对象的成员函数,需与全局函数Log区分。