[TOC]
发明者量化交易平台经过9年的技术迭代,进行了多次重构,虽然作为用户的我们可能未曾察觉。在过去的两年中,平台在用户体验方面进行了大量优化和升级,包括全面升级UI界面,丰富常用量化交易工具,以及增加更多回测数据支持。
为了让策略设计更加便捷、交易逻辑更加清晰,且初学者更容易上手,平台升级了策略使用的API接口。使用最新版本的托管者即可启用这些新功能。平台依然最大程度地兼容旧接口的调用。有关API接口新增功能等信息已同步更新至发明者量化交易平台的API文档:
那么通过本篇让我们一起来速览都有哪些接口升级更新以及对于老旧策略使用时需要哪些改动以兼容当前API。
对于设计多品种策略、全市场行情监控策略。这种聚合行情接口是必不可少的,为了让策略更加易于开发,避免重复造轮子。发明者量化交易平台封装了交易所这类API。
如果交易所没有这种接口(个别交易所),调用exchange.GetTickers()
时会报错:不支持。
该函数没有任何参数,会返回交易所聚合行情接口中所有品种的实时行情数据。可以简单理解为:
exchange.GetTickers()
函数是exchange.GetTicker()
函数的全品种请求版本(仔细看,这两个函数名区分就是单复数而已)。
我们使用OKX现货模拟盘环境测试:
function main() {
exchange.IO("simulate", true)
var tickers = exchange.GetTickers()
if (!tickers) {
throw "tickers error"
}
var tbl = {type: "table", title: "test tickers", cols: ["Symbol", "High", "Open", "Low", "Last", "Buy", "Sell", "Time", "Volume"], rows: []}
for (var i in tickers) {
var ticker = tickers[i]
tbl.rows.push([ticker.Symbol, ticker.High, ticker.Open, ticker.Low, ticker.Last, ticker.Buy, ticker.Sell, ticker.Time, ticker.Volume])
}
LogStatus("`" + JSON.stringify(tbl) + "`")
return tickers.length
}
新增的exchange.CreateOrder()
函数可谓是此次升级中的重点,exchange.CreateOrder()
函数最大的功能是直接在该函数的参数中指定下单的品种、方向。这样就不再依赖系统当前设置的交易对、合约代码、交易方向等设置了。
在多品种交易下单场景中、并发场景中极大程度的降低了设计复杂度。exchange.CreateOrder()
函数的四个参数分别是symbol
、side
、price
、amount
。
使用OKX期货模拟盘环境测试:
function main() {
exchange.IO("simulate", true)
var id1 = exchange.CreateOrder("ETH_USDT.swap", "buy", 3300, 1)
var id2 = exchange.CreateOrder("BTC_USDC.swap", "closebuy", 70000, 1)
var id3 = exchange.CreateOrder("LTC_USDT.swap", "sell", 110, 1)
Log("id1:", id1, ", id2:", id2, ", id3:", id3)
}
这样只用了3次exchange.CreateOrder()
函数调用就下了三个不同品种、不同方向的期货订单。
新增的exchange.GetHistoryOrders()
函数用来获取某个品种的历史成交订单,这个函数也需要交易所接口支持。
对于查询历史订单来说,各个交易所实现的接口差别非常大:
对于这类接口以最大的兼容程度去封装,实际使用中需要注意是否符合策略的需求、期望。
详细的函数说明这里不再赘述,可以查阅API文档中语法手册:
https://www.fmz.com/syntax-guide#fun_exchange.gethistoryorders
使用币安现货实盘环境测试:
function main() {
var orders = exchange.GetHistoryOrders("ETH_USDT")
// 写入图表
var tbl = {type: "table", title: "test GetHistoryOrders", cols: ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], rows: []}
for (var order of orders) {
tbl.rows.push([order.Symbol, order.Id, order.Price, order.Amount, order.DealAmount, order.AvgPrice, order.Status, order.Type, order.Offset, order.ContractType])
}
LogStatus("orders.length:", orders.length, "\n", "`" + JSON.stringify(tbl) + "`")
}
旧版本的获取持仓数据函数为exchange.GetPosition()
。此次升级为了更加贴合函数命名语义,增加了新的获取持仓函数:exchange.GetPositions()
。同时依然兼容/升级GetPosition函数。
注意,两个函数名称只是差别一个结尾的s,因为GetPositions更加符合语义,所以建议后续都使用GetPositions。
exchange.GetPositions()
函数有三种调用形式:
exchange.GetPositions() 当不传任何参数时,根据当前交易对 / 合约代码的设置,请求当前维度的全部品种的持仓数据。
exchange.GetPositions(“ETH_USDT.swap”)
当指定具体品种信息时(ETH_USDT.swap这种格式由FMZ平台定义),请求具体品种的持仓数据。
举例:BTC_USD.swap
、ETH_USDT.swap
、ETH_USDT.quarter
等。
BTC_USD.swap:BTC的币本位永续合约。
ETH_USDT.swap:ETH的U本位永续合约。
ETH_USDC.swap:ETH的USDC本位永续合约。 (除了USDT,还可以指定不同的quoteCurrency,不再赘述)
ETH_USDT.quarter:ETH的U本位季度交割合约。
BTC_USD.BTC-USD-201226-24250-C:BTC的币本位期权合约。
exchange.GetPositions(“USDT.swap”) 根据指定的维度范围,请求全部品种的持仓数据。 USDT.swap:U本位永续合约范围。 USDT.futures:U本位交割合约范围。 USDC.swap:USDC本位永续合约范围。 (除了USDT,还可以指定不同的quoteCurrency,不再赘述) USDC.futures:USDC本位交割合约范围。 USD.swap:币本位永续合约范围。 USD.futures:币本位交割合约范围。 USDT.option:U本位期权合约范围。 USD.option:币本位期权合约范围。
一些特殊的交易所合约维度划分: USDT.futures_combo:Futures_Deribit交易所的差价组合合约。 USD.futures_ff:Futures_Kraken交易所的混合保证金交割合约。 USD.swap_pf:Futures_Kraken交易所的混合保证金永续合约。
对于交易所API接口不支持的维度,调用时会报错返回空值。
使用OKX期货模拟盘环境测试:
function main() {
exchange.IO("simulate", true)
exchange.SetCurrency("BTC_USDT")
exchange.SetContractType("swap")
var p1 = exchange.GetPositions()
var p2 = exchange.GetPositions("BTC_USDT.swap")
var tbls = []
for (var positions of [p1, p2]) {
var tbl = {type: "table", title: "test GetPosition/GetPositions", cols: ["Symbol", "Amount", "Price", "FrozenAmount", "Type", "Profit", "Margin", "ContractType", "MarginLevel"], rows: []}
for (var p of positions) {
tbl.rows.push([p.Symbol, p.Amount, p.Price, p.FrozenAmount, p.Type, p.Profit, p.Margin, p.ContractType, p.MarginLevel])
}
tbls.push(tbl)
}
LogStatus("`" + JSON.stringify(tbls) + "`")
}
当传入exchange.GetPositions()
函数的参数是ETH_USDT.swap
时,就可以获取ETH的U本位永续合约的持仓数据。
当不传入exchange.GetPositions()
函数的参数时,就可以获取交易所上线的所有U本位永续合约的持仓数据(因为当前交易对为BTC_USDT,合约为swap,按照当前交易对、合约维度范围请求),此时等价于调用exchange.GetPositions("USDT.swap")
,指定一个请求范围。
新增的GetFundings函数可以获取期货交易所永续合约的资金费率。函数有一个参数symbol。函数返回一个Funding结构数组。
BTC_USDT.swap
。不传参数或者传入范围函数会报错symbol参数不支持。行情函数exchange.GetTicker()
本次升级主要是增加了symbol参数。使得该函数可以脱离当前交易对、合约代码直接按照参数指定的品种信息,请求行情数据。简化了代码编写过程。同时依然兼容不传参的调用方式,最大程度兼容平台旧策略。
参数symbol
对于交易所对象exchange
是现货/期货有不同的格式:
AAA_BBB
,AAA表示为baseCurrency即交易币种,BBB表示为quoteCurrency即计价币种。币种名称均为大写字母。
例如:BTC_USDT 现货交易对。AAA_BBB.XXX
,AAA表示为baseCurrency即交易币种,BBB表示为quoteCurrency即计价币种,XXX表示为合约代码,例如永续合约swap。币种名称均为大写字母,合约代码为小写。
例如:BTC_USDT.swap ,BTC的U本位永续合约。使用币安期货实盘环境测试:
var symbols = ["BTC_USDT.swap", "BTC_USDT.quarter", "BTC_USD.swap", "BTC_USD.next_quarter", "ETH_USDT.swap"]
function main() {
exchange.SetCurrency("ETH_USD")
exchange.SetContractType("swap")
var arr = []
var t = exchange.GetTicker()
arr.push(t)
for (var symbol of symbols) {
var ticker = exchange.GetTicker(symbol)
arr.push(ticker)
}
var tbl = {type: "table", title: "test GetTicker", cols: ["Symbol", "High", "Open", "Low", "Last", "Buy", "Sell", "Time", "Volume"], rows: []}
for (var ticker of arr) {
tbl.rows.push([ticker.Symbol, ticker.High, ticker.Open, ticker.Low, ticker.Last, ticker.Buy, ticker.Sell, ticker.Time, ticker.Volume])
}
LogStatus("`" + JSON.stringify(tbl) + "`")
return arr
}
请求一批指定品种的行情数据设计变得更加简单。
与GetTicker函数相同exchange.GetDepth()
函数此次也增加了symbol参数。可以实现在请求深度数据时直接指定品种。
使用币安期货实盘环境测试:
function main() {
exchange.SetCurrency("LTC_USD")
exchange.SetContractType("swap")
Log(exchange.GetDepth())
Log(exchange.GetDepth("ETH_USDT.quarter"))
Log(exchange.GetDepth("BTC_USD.swap"))
}
与GetTicker函数相同exchange.GetTrades()
函数此次也增加了symbol参数。可以实现在请求市场成交数据时直接指定品种。
使用币安期货实盘环境测试:
function main() {
var arr = []
var arrR = []
var symbols = ["LTC_USDT.swap", "ETH_USDT.quarter", "BTC_USD.swap"]
for (var symbol of symbols) {
var r = exchange.Go("GetTrades", symbol)
arrR.push(r)
}
for (var r of arrR) {
arr.push(r.wait())
}
var tbls = []
for (var i = 0; i < arr.length; i++) {
var trades = arr[i]
var symbol = symbols[i]
var tbl = {type: "table", title: symbol, cols: ["Time", "Amount", "Price", "Type", "Id"], rows: []}
for (var trade of trades) {
tbl.rows.push([trade.Time, trade.Amount, trade.Price, trade.Type, trade.Id])
}
tbls.push(tbl)
}
LogStatus("`" + JSON.stringify(tbls) + "`")
}
此次升级同样兼容了通过exchange.Go()
函数并发调用平台API接口时传入symbol参数指定品种信息。
GetRecords函数本次做出了较大调整,除了支持symbol参数直接指定请求的K线数据的品种信息。保留了原有的period参数用来指定K线周期,还增加了一个limit参数用来指定请求时期望的K线长度。同时也兼容旧版本的GetRecords函数只传入period周期参数的调用方式。
exchange.GetRecords()
函数的调用方式:
使用币安期货实盘环境测试:
function main() {
exchange.SetCurrency("ETH_USDT")
exchange.SetContractType("swap")
var r1 = exchange.GetRecords()
var r2 = exchange.GetRecords(60 * 60)
var r3 = exchange.GetRecords("BTC_USDT.swap")
var r4 = exchange.GetRecords("BTC_USDT.swap", 60)
var r5 = exchange.GetRecords("LTC_USDT.swap", 60, 3000)
Log("r1相邻Bar时间差值:", r1[1].Time - r1[0].Time, "毫秒, Bar长度:", r1.length)
Log("r2相邻Bar时间差值:", r2[1].Time - r2[0].Time, "毫秒, Bar长度:", r2.length)
Log("r3相邻Bar时间差值:", r3[1].Time - r3[0].Time, "毫秒, Bar长度:", r3.length)
Log("r4相邻Bar时间差值:", r4[1].Time - r4[0].Time, "毫秒, Bar长度:", r4.length)
Log("r5相邻Bar时间差值:", r5[1].Time - r5[0].Time, "毫秒, Bar长度:", r5.length)
}
GetOrders函数也增加了symbol
参数,可以指定具体品种,查询该品种的未完成订单(挂单);也支持查询指定维度范围的全部品种的未完成订单(挂单)。
exchange.GetOrders()
函数的调用方式有:
使用OKX期货模拟盘环境测试:
function main() {
exchange.IO("simulate", true)
exchange.SetCurrency("BTC_USDT")
exchange.SetContractType("swap")
// 写入图表
var tbls = []
for (var symbol of ["null", "ETH_USDT.swap", "USDT.swap"]) {
var tbl = {type: "table", title: symbol, cols: ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], rows: []}
var orders = null
if (symbol == "null") {
orders = exchange.GetOrders()
} else {
orders = exchange.GetOrders(symbol)
}
for (var order of orders) {
tbl.rows.push([order.Symbol, order.Id, order.Price, order.Amount, order.DealAmount, order.AvgPrice, order.Status, order.Type, order.Offset, order.ContractType])
}
tbls.push(tbl)
}
LogStatus("`" + JSON.stringify(tbls) + "`")
}
ETH_USDT.swap
参数时,请求ETH的USDT本位永续合约的未完成订单(挂单)。"USDT.swap"
时,请求所有USDT本位永续合约的未完成订单(挂单)。依然兼容旧的持仓获取函数命名,同样增加了symbol参数,可以指定具体请求的持仓数据的品种信息。函数使用方面和exchange.GetPositions()
完全一致。
对于exchange.IO("api", ...)
函数调用方式,对所有交易所对象都升级支持了直接传入完整的请求地址功能。
例如希望调用OKX的接口:
GET https://www.okx.com /api/v5/account/max-withdrawal ccy: BTC
支持直接写入基地址https://www.okx.com
,不必先切换基地址再调用IO函数。
使用OKX期货模拟盘环境测试:
function main() {
exchange.IO("simulate", true)
return exchange.IO("api", "GET", "https://www.okx.com/api/v5/account/max-withdrawal", "ccy=BTC")
}
此次升级主要影响了exchange.GetOrder(id)
函数的参数id
,id参数由原来的交易所订单id改为了一种包含交易品种的字符串格式。FMZ平台上所有封装的订单Id都为此格式。
例如:
123456
此次升级之前,若要调用GetOrder函数,传入的订单Id就是123456
。BTC-USDT
。
注意这里说的是交易所命名的交易品种代码,并不是FMZ平台定义的交易对。那么此次升级后,exchange.GetOrder(id)
函数需要传入的参数id的格式就调整为:BTC-USDT,123456
。
先说明一下为什么要这样设计: 因为此次升级了CreateOrder函数直接指定品种下单(下单的品种和当前设置的交易对、合约代码有可能不同),如果返回的订单Id中不包含品种信息。那么这个订单Id将无法使用。因为到具体查单的时候不知道这个订单是什么品种(合约)的。大部分交易所查单、撤单都需要指定描述品种代码的参数。
如何兼容这种影响: 如果下单使用的是exchange.IO函数直接调用交易所下单接口去下单的,返回值中一般都有交易所原始symbol(品种代码)和原始订单id。那么把这两者用英文逗号拼接起来就是符合FMZ平台定义的订单Id了。 同样,如果使用的是FMZ平台封装的下单接口下单的,由于订单Id开头部分是交易品种代码,如果需要使用订单原始Id,只需要删除品种代码和逗号即可。
此次升级对于exchange.CancelOrder()
函数的影响与exchange.GetOrder()
函数相同。
此次升级对于exchange.Buy()
函数的影响与exchange.GetOrder()
函数相同。exchange.Buy()
函数返回的订单Id为新结构,例如在OKX交易所期货下单时返回的Id:LTC-USDT-SWAP,1578360858053058560
。
此次升级对于exchange.Sell()
函数的影响与exchange.GetOrder()
函数相同。exchange.Sell()
函数返回的订单Id为新结构,例如在OKX交易所期货下单时返回的Id:ETH-USDT-SWAP,1578360832820125696
。
仅期货交易所对象支持该函数,对于获取持仓数据函数exchange.GetPosition(),新增exchange.GetPositions()命名,两者行为完全一致。
旧定义:exchange.GetPosition()函数,不指定任何参数调用时,获取的是当前交易对、合约代码设置的具体合约的持仓数据。
调整、改动后,新定义:exchange.GetPosition()函数,不指定任何参数调用时,获取当前设置交易对、合约代码确定的维度范围的所有品种的持仓。
例如,当前交易对为BTC_USDT,合约代码为swap。此时调用:
exchange.GetPosition() // 等价于调用 exchange.GetPosition("USDT.swap")
该函数会请求所有币种的U本位永续合约的持仓数据。
1、对于现货交易所:
旧定义:exchange.GetOrders()函数,不指定任何参数调用时,获取的是当前交易对的所有未完成订单。
调整、改动后,新定义:exchange.GetOrders()函数,不指定任何参数调用时,获取的是所有现货交易对品种的未完成订单。
2、对于期货交易所:
旧定义:exchange.GetOrders()函数,不指定任何参数调用时,获取的是当前交易对、合约代码设置的具体合约的所有未完成订单。
调整、改动后,新定义:exchange.GetOrders()函数,不指定任何参数调用时,获取当前设置交易对、合约代码确定的维度范围的所有未完成订单。
例如,当前交易对为BTC_USD,合约代码为quarter。此时调用:
exchange.GetOrders() // 等价于调用 exchange.GetOrders("USD.futures")
该函数会请求所有币种的币本位交割合约的未完成订单数据。
此次更新给Ticker结构体增加了Symbol字段,该字段记录当前Ticker结构为哪个品种的行情信息。该字段格式与exchange.GetTicker()
函数的symbol参数格式完全一致。
此次更新给Order结构体增加了Symbol字段,该字段格式与exchange.GetTicker()
函数的symbol参数格式完全一致。此次更新也修改了Order结构体的Id字段,以新的订单Id格式记录品种信息、原始订单信息。参考exchange.GetOrder()
函数中订单Id的说明,这里不再赘述。
此次更新给Position结构体增加了Symbol字段,该字段格式与exchange.GetTicker()
函数的symbol参数格式完全一致。
GetFundings函数返回一个Funding结构体数组。
{
"Info": {...}, // 交易所资金费率接口原始应答数据
"Symbol": "BTC_USDT.swap", // FMZ平台定义的品种名称
"Interval": 28800000, // 8小时间隔,单位毫秒
"Time": 1729728000000, // 本期资金费率收取时间
"Rate": 0.0001, // 资金费率,即 0.01 %
}
此次升级为了满足用户需求,先对实盘进行兼容,回测系统将在一周内完成适配. 如个别策略代码受到影响,请按此文章说明进行更改适配
根据此次平台策略API接口升级,平台的回测系统中各API接口已经同步更新完成;另外回测系统新增支持:
对于期货交易所对象的成员函数GetAccount
返回的Account
结构进行了字段扩充。
对于期货交易所对象的成员函数SetMarginLevel进行了升级,增加参数symbol。
测试例子:
function main() {
exchange.SetCurrency("ETH_USDT")
exchange.SetContractType("swap")
// 当前交易对为ETH_USDT,合约代码为swap,设置杠杆值为10
exchange.SetMarginLevel(10)
// 直接指定交易对BTC_USDT,合约代码swap,设置杠杆值20
exchange.SetMarginLevel("BTC_USDT.swap", 20)
}
CtValCcy
记录一张合约的价值单位,一张合约的价值单位可能是:BTC、USD、ETH等。CtVal
记录该交易品种在交易所的一张合约对应的价值,单位为CtValCcy
字段记录的币种。例如:CtVal
为0.01,CtValCcy
为"BTC"表示一张合约价值0.01个BTC。Wa-emmnn_ 我说我新开的机器人怎么回事,返回ID还带交易对名称,研究了好久,还有下单后缀的log信息现在不显示了,也是因为托管者更新的缘故吗?
张小宝lre /upload/asset/2ffc0f961149326b78aed.png 请问这个问题是这次接口更新导致的吗?
ecnemuse 希望exchange.Buy函数能增加开止损单的功能。。
NanSeg 前排围观
Wa-emmnn_ 好UwU
发明者量化-小小梦 好的,这边测试下看下。感谢您提出问题。这边会尽快处理。
Wa-emmnn_ 对的,extMsg1, extMsg2不显示了。
发明者量化-小小梦 您好,订单ID这个是迫不得已的改动,因为升级了直接指定品种下单,订单ID中就必须包含品种信息,否则无法确定这个订单是哪个品种的,在撤单的时候无法调用(因为大多数交易所撤单的时候需要指定品种,并且指定ID)。 您说的下单后缀信息不显示,是指:exchange.Buy(price, amount, extMsg1, extMsg2)调用时,extMsg1, extMsg2 不在日志上显示吗?
发明者量化-小小梦 您好,您发下当前的交易所设置、交易对、合约代码设置。
发明者量化 请详细发送测试代码与配置到工单,工程师会在第一时间回复您
发明者量化-小小梦 交易所的条件单机制等差别有些大,支持程度各不相同,这个这边调研下看是否可行。
发明者量化-小小梦 感谢支持,如果有使用问题,发工单或留言都可以。