资源加载中... loading...

详解优宽量化交易平台API升级:提升策略设计体验

Author: 雨幕(youquant), Created: 2024-08-02 16:24:41, Updated: 2024-11-15 09:45:54

[TOC]

img

前言

优宽量化交易平台经过多年的技术迭代,进行了多次重构,虽然作为用户的我们可能未曾察觉。在过去的几个月中,平台在用户体验方面进行了大量优化和升级,包括全面升级UI界面,丰富常用量化交易工具,以及增加更多回测数据支持。

为了让策略设计更加便捷、交易逻辑更加清晰,且初学者更容易上手,平台升级了策略使用的API接口。使用最新版本的托管者即可启用这些新功能。平台依然最大程度地兼容旧接口的调用。有关API接口新增功能等信息已同步更新至优宽量化交易平台的API文档:

语法手册:https://www.youquant.com/syntax-guide 用户指南:https://www.youquant.com/user-guide

那么通过本篇让我们一起来速览都有哪些接口升级更新以及对于老旧策略使用时需要哪些改动以兼容当前API。

1、API接口新增

新增exchange.GetHistoryOrders函数

新增的exchange.GetHistoryOrders()函数用来获取全部合约(也可以指定某个合约)的历史成交订单(只能查询当前交易日范围),

详细的函数说明,可以查询API文档语法手册:

https://www.youquant.com/syntax-guide#fun_exchange.gethistoryorders

function main() {
    var tbl = {type: "table", title: "test", cols: ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], rows: []}
    for (var i = 0; i < 10; i++) {
        if (exchange.IO("status")) {
            var orders = exchange.GetHistoryOrders()              // 不传参数
            // var orders = exchange.GetHistoryOrders("rb2410")   // 传参数
            
            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(_D(), "\n", "`" + JSON.stringify(tbl) + "`")   
            return orders.length
        }

        Sleep(1000)
    }
}

新增exchange.GetPositions函数

旧版本的获取持仓数据函数为exchange.GetPosition()。此次升级为了更加贴合函数命名语义增加了新的获取持仓函数:exchange.GetPositions()。同时依然兼容/升级GetPosition函数。

exchange.GetPositions()函数有三种调用形式:

  • exchange.GetPositions() 当不传任何参数时,获取所有合约的持仓数据。
  • exchange.GetPositions(“rb2410”) 当指定具体合约代码时,获取具体合约的持仓数据。

https://www.youquant.com/syntax-guide#fun_exchange.getpositions

function main() {
    var tbl1 = {"type": "table", "title": "test GetPosition/GetPositions", "cols": ["Symbol", "Amount", "Price", "FrozenAmount", "Type", "Profit", "Margin", "ContractType", "MarginLevel"], "rows": []}
    var tbl2 = {"type": "table", "title": "test GetPosition/GetPositions", "cols": ["Symbol", "Amount", "Price", "FrozenAmount", "Type", "Profit", "Margin", "ContractType", "MarginLevel"], "rows": []}
    var dictType = {
        "PD_LONG": PD_LONG,
        "PD_SHORT": PD_SHORT,
        "PD_LONG_YD": PD_LONG_YD,
        "PD_SHORT_YD": PD_SHORT_YD,
    }


    for (var i = 0; i < 10; i++) {
        if (exchange.IO("status")) {
            var pos1 = exchange.GetPositions()
            var pos2 = exchange.GetPosition()

            Log("pos1.length:", pos1.length, "pos1:", pos1)
            Log("pos2.length:", pos2.length, "pos2:", pos2)

            if (pos1 && pos2) {
                for (var p of pos1) {
                    tbl1.rows.push([p.Symbol, p.Amount, p.Price, p.FrozenAmount, p.Type, p.Profit, p.Margin, p.ContractType, p.MarginLevel])
                }
                for (var p of pos2) {
                    tbl2.rows.push([p.Symbol, p.Amount, p.Price, p.FrozenAmount, p.Type, p.Profit, p.Margin, p.ContractType, p.MarginLevel])
                }
            }

            LogStatus(_D(), dictType, "\n", "`" + JSON.stringify([tbl1, tbl2]) +  "`")
            return 
        }

        Sleep(1000)
    }
}

新增exchange.CreateOrder函数

新增的exchange.CreateOrder()函数可谓是此次升级中的重点,exchange.CreateOrder()函数最大的功能是直接在该函数的参数中指定下单的品种、方向。这样就不再依赖系统当前设置的交易对、合约代码、交易方向等设置了。

在多品种交易下单场景中、并发场景中极大程度的降低了设计复杂度。exchange.CreateOrder()函数的四个参数分别是symbolsidepriceamount。用来指定订单的合约代码、方向、价格、数量。

var symbols = ["MA409", "i2501", "rb2410", "TA409"]

function CancellAll() {
    var orders = exchange.GetOrders()
    for (var order of orders) {
        exchange.CancelOrder(order["Id"], order)
        Sleep(1000)
    }
    Log("GetOrders:", exchange.GetOrders())
}

function main() {    
    for (var i = 0; i < 10; i++) {
        if (exchange.IO("status")) {
            for (var symbol of symbols) {
                var info = exchange.SetContractType(symbol)
                var t = exchange.GetTicker()
                if (info && t) {
                    Log("测试 Buy/Sell", "#FF0000")                    
                    exchange.SetDirection("buy")
                    var id1 = exchange.Buy(t.Last - 10, 1)  // 低于最新成交价,为了挂单
                    exchange.SetDirection("sell")
                    var id2 = exchange.Sell(t.Last + 10, 1) // 同理

                    Log("测试 CreateOrder", "#FF0000")
                    var id3 = exchange.CreateOrder(symbol, "buy", t.Last - 20, 1, "测试CreateOrder", "#FF0000")
                    var id4 = exchange.CreateOrder(symbol, "sell", t.Last + 20, 1, "测试CreateOrder", "#FF0000")
                }
            }
            Sleep(5000)

            CancellAll()  // 撤销所有挂单
            return 
        }

        Sleep(1000)
    }
}

https://www.youquant.com/syntax-guide#fun_exchange.createorder

2、API接口升级

升级exchange.GetTicker函数

行情函数exchange.GetTicker()本次升级主要是增加了symbol参数。使得该函数可以脱离当前合约代码直接按照参数指定的合约代码,请求行情数据。简化了代码编写过程。同时依然兼容不传参的调用方式,最大程度兼容平台旧策略。

function main() {
    var symbols = ["rb2410", "MA888"]

    for (var i = 0; i < 10; i++) {
        if (exchange.IO("status")) {
            var tbl = {
                type: "table", title: "test:", cols: ["Symbol", "High", "Open", "Low", "Last", "Buy", "Sell", "Time", "Volume", "OpenInterest"], rows: []
            }

            var index = 0 
            for (var symbol of symbols) {
                var info = exchange.SetContractType(symbol)
                Log(info)

                var ticker = null
                if (index == 0) {
                    ticker = exchange.GetTicker()          // 测试不带参数
                    Log(ticker)
                } else {
                    ticker = exchange.GetTicker(symbol)    // 测试带参数
                    Log(ticker)
                }
                index++

                // 检查返回的结构
                if (info && ticker) {                
                    tbl["rows"].push([
                        ticker["Symbol"], 
                        ticker["High"], 
                        ticker["Open"], 
                        ticker["Low"], 
                        ticker["Last"], 
                        ticker["Buy"], 
                        ticker["Sell"], 
                        ticker["Time"], 
                        ticker["Volume"],
                        ticker["OpenInterest"],                        
                    ])
                }
            }

            LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
            return 
        }

        Sleep(1000)
    }    
}

请求一批指定合约的行情数据设计变得更加简单。

升级exchange.GetDepth函数

GetTicker函数相同exchange.GetDepth()函数此次也增加了symbol参数。可以实现在请求深度数据时直接指定品种。

function main() {
    var symbols = ["rb2410", "MA888"]

    for (var i = 0; i < 10; i++) {
        if (exchange.IO("status")) {
            var tbl = {type: "table", title: "test:", cols: ["symbol", "Bids.length", "Asks.length", "Bids[0]", "Asks[0]", "Time"], rows: []}

            var index = 0 
            for (var symbol of symbols) {
                var info = exchange.SetContractType(symbol)
                Log(info)

                var depth = null
                if (index == 0) {
                    depth = exchange.GetDepth()          // 测试不带参数
                    Log("测试GetDepth不传参", depth)
                } else {
                    depth = exchange.GetDepth(symbol)    // 测试带参数
                    Log("测试GetDepth传参", depth)
                }
                index++
            }
            return 
        }

        Sleep(1000)
    }    
}

升级exchange.GetTrades函数

GetTicker函数相同exchange.GetTrades()函数此次也增加了symbol参数。可以实现在请求市场成交数据时直接指定品种。

升级exchange.GetRecords函数

GetRecords函数本次做出了较大调整,除了支持symbol参数直接指定请求的K线数据的品种信息。保留了原有的period参数用来指定K线周期,还增加了一个limit参数用来指定请求时期望的K线长度。同时也兼容旧版本的GetRecords函数只传入period周期参数的调用方式。

exchange.GetRecords()函数的调用方式:

  • exchange.GetRecords() 不指定任何参数时请求当前合约代码对应的品种的K线数据,K线周期是策略回测界面或者实盘时设置的默认K线周期。
  • exchange.GetRecords(60 * 15) 仅指定K线周期参数时,请求当前合约代码对应的品种的K线数据。
  • exchange.GetRecords(“rb2410”) 仅指定品种信息时,请求指定品种的K线数据,K线周期是策略回测界面或者实盘时设置的默认K线周期。
  • exchange.GetRecords(“MA888”, 60 * 60) 指定品种信息,指定具体K线周期请求K线数据。
  • exchange.GetRecords(“i888”, 60, 1000) 指定品种信息,指定具体K线周期,指定期望获取的K线长度请求K线数据。
function main() {
    var symbols = ["MA888", "rb2410", "i2409", "hc2410"]
    Log("当前默认K线周期", exchange.GetPeriod())
    for (var i = 0; i < 10; i++) {
        if (exchange.IO("status")) {
            var index = 0
            for (var symbol of symbols) {
                var info = exchange.SetContractType(symbol)
                Log(info)

                var r = null
                if (index == 0) {
                    exchange.SetMaxBarLen(2000) // 测试

                    r = exchange.GetRecords()   // 测试不带参数
                    Log("索引:", index, ",合约:", symbols[index], ",BAR间隔:", r[1]["Time"] - r[0]["Time"], r[2]["Time"] - r[1]["Time"], "最新价格:", r[r.length - 1]["Close"])                    
                } else if (index == 1) {
                    r = exchange.GetRecords(symbol, 60 * 5)   // 测试指定symbol period
                    Log("索引:", index, ",合约:", symbols[index], ",BAR间隔:", r[1]["Time"] - r[0]["Time"], r[2]["Time"] - r[1]["Time"], "最新价格:", r[r.length - 1]["Close"])
                } else if (index == 2) {
                    // r = exchange.GetRecords(symbol, 60 * 60 * 24, 999)
                    r = exchange.GetRecords(symbol, 60, 999)   // 测试指定symbol period limit 
                    Log("索引:", index, ",合约:", symbols[index], ",BAR间隔:", r[1]["Time"] - r[0]["Time"], r[2]["Time"] - r[1]["Time"], "最新价格:", r[r.length - 1]["Close"])
                } else if (index == 3) {
                    r = exchange.GetRecords(symbol)   // 测试指定symbol
                    Log("索引:", index, ",合约:", symbols[index], ",BAR间隔:", r[1]["Time"] - r[0]["Time"], r[2]["Time"] - r[1]["Time"], "最新价格:", r[r.length - 1]["Close"])                    
                }
                index++

                if (info && r) {
                    Log(symbol, "r.length:", r.length, "#FF0000")
                }
            }
            return 
        }

        Sleep(1000)
    }    
}

升级exchange.GetOrders函数

GetOrders函数也增加了symbol参数,可以直接指定查询当前未完成订单(挂单)的合约代码;不传symbol参数则是获取所有合约的当前未完成订单。

  • exchange.GetOrders() 查询所有合约的当前未完成订单。
  • exchange.GetOrders(“rb2410”) 查询rb2410合约的所有未完成订单。
var tbl = {type: "table", title: "test", cols: ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], rows: []}
function main() {
    for (var i = 0; i < 10; i++) {
        if (exchange.IO("status")) {
            var info = exchange.SetContractType("hc2410")
            var orders = exchange.GetOrders()               // 测试1
            // var orders = exchange.GetOrders("rb2410")    // 测试2 
            // var orders = exchange.GetOrders("hc2410")    // 测试3

            Log("orders.length:", orders.length, ", orders:", orders)

            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(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
            return 
        }

        Sleep(1000)
    }
}

3、结构体调整

Ticker结构体

此次更新给Ticker结构体增加了Symbol字段,该字段记录当前Ticker结构为哪个品种的行情信息。例如在商品期货中如果当前这个Ticker数据为螺纹钢合约rb2410的行情数据,此时Ticker结构中Symbol字段为:rb2410

Order结构体

此次更新给Order结构体增加了Symbol字段,该字段格式、定义与exchange.GetTicker()函数的symbol参数格式、定义完全一致。

Position结构体

此次更新给Position结构体增加了Symbol字段,该字段格式、定义与exchange.GetTicker()函数的symbol参数格式、定义完全一致。

Account结构体

新增字段EquityUPnL

  • Equity 当前账户权益,包含可用资金、仓位保证金、盈亏等。

  • UPnL 当前所有持仓的盈亏总和。

4、回测系统

根据本次升级,回测系统正在适配中。


更多内容