BotVS 商品期货 量化 测试入门 策略

为什么要写这个策略代码呢?

原因很简单,在平时测试托管者功能的时候,每次要对 BotVS 各个 API 进行测试。每次的测试代码很大程度上类似,干脆就写个 测试策略吧。写好以后,感觉不仅可以测试托管者。同样对于 初识 BotVS量化平台的 新同学 在学习使用商品期货 simnow 仿真账户 或者 实盘的时候也是个很好的工具。
  • 用途: 如上所述,该策略仅仅是为了方便BotVS新用户快速熟悉 BotVS 商品期货程序化交易,测试模拟账户、实盘账户下单 等功能 。透过对该策略的源代码的剖析和学习也可以学习到 策略编写方面的一些技巧、经验。那么简单介绍下吧!

  • 显示UI

上期技术 提供的 Simnow 仿真账户申请 详见:

botvs.com/bbs-topic/325


  • 策略参数

参数很简单,只有2个,第一个是 程序轮询间隔 (BotVS 策略是轮询架构的),该参数可以控制每次轮询后暂停多少毫秒,防止策略访问 交易所过于频繁。第二个参数就是 合约代码了,默认的是 rb1801 即 :螺纹钢1801合约

  • 交互

交互就是 策略使用时主要用到的 功能了。

  • 修改合约

可以在该交互控件 中填写 合约代码,如填写 MA801 ,后点击 changeSymbol 就可以将 策略中当前的合约代码 比如 rb1801 切换成 MA801。

  • 开当前合约 多单:编辑框写上开仓手数,点击 OPEN_LONG 按钮就会 进行开多仓操作。
  • 开空 同理不赘述
  • 按数量平仓:点击 COVER 就会按编辑框写入的 数量平仓,如果 此时 同时持有多头和空头仓位,会随机先平 一边,如果平仓数量大于一边的数量,会平完后,按剩余的计划数量继续平仓另一边。(鉴于测试的时候同时持有多空的情况不多,所以平仓没有单独写)
  • 获取当前合约合约未完成的订单:点击后在日志 显示区域会 显示出 未完成的订单(挂单状态)
  • 获取当前合约指定ID的订单:可以 传入 一个 ID 获取 该ID 的订单
  • 获取当前合约持仓信息:获取当前的合约的持仓。
  • 获取所有合约持仓信息:获取所有持仓信息 列表 (数组形式)
  • 取消订单:编辑框 写入 要取消的订单的 ID 号 ,点击 CANCEL_ORDER 就可以取消挂单。
  • 调用JS 代码 ,可以在编辑框内写 要执行的 JS 代码, 点击 按钮 JS_CODE 就可以执行。

源码:

// 商品期货 测试 程序
/*
1、 行情部分测试
2、 交易 测试
3、 交互界面

*/
// var _Interval = 500
// var _StrContractType = "rb1801"


//
var CONNECTED = 1
var NOTCONNECTED = 2
var _TableObj = {
    type : "table",
    title : "test",
    cols : ["value"],
    rows : [],
}
var _templeteObj = null
// var _isFirst = true
var _chart = null       // 配置对象 ,并非控制对象
var _chartObj = null
var _LogStatusMessage = ""

function E(obj) {
    if(!obj){
        return obj
    }

    var cloneObj = function(obj) { // 深拷贝 对象函数
        var str, newobj = obj.constructor === Array ? [] : {};
        if (typeof obj !== 'object') {
            return;
        } else if (JSON) {
            str = JSON.stringify(obj); //系列化对象
            newobj = JSON.parse(str); //还原
        } else {
            for (var i in obj) {
                newobj[i] = typeof obj[i] === 'object' ?
                    cloneObj(obj[i]) : obj[i];
            }
        }
        return newobj;
    }
    
    if(obj && typeof(obj) == "object" && typeof(obj.Info) !== "undefined"){
        var newObj = cloneObj(obj)
        delete newObj.Info
        return newObj
    }else if(typeof(obj.length) == "number"){
        ///*
        var newArray = []
        for(var n = 0; n < obj.length; n++){
            newArray.push(E(obj[n]))
        }
        return newArray
        //*/
        /*
        var newObj = cloneObj(obj)
        delete newObj.Info
        return newObj
        */
    }else{
        // Log(obj, "is not object or not have attribute 'Info'")
        return obj
    }
}

function onTick(symbol){
    if(!$.IsTrading(symbol)){
        _LogStatusMessage = symbol + " 不在交易时间段内!" + "#FF0000"
        return
    }else{
        _LogStatusMessage = symbol + " 在交易时间段!"
    }

    var contractTypeInfo = exchange.SetContractType(symbol)
    if(!contractTypeInfo){
        return
    }

    var account = exchange.GetAccount()
    var ticker = exchange.GetTicker()
    var records = exchange.GetRecords()
    var depth = exchange.GetDepth()
    
    if(!account || !ticker || !depth || !records || records.length < 2){
        return
    }
    
    _TableObj.rows = []   // 每次清空
    _TableObj.rows.push([JSON.stringify(E(contractTypeInfo))])
    _TableObj.rows.push([JSON.stringify(E(account))])
    _TableObj.rows.push([JSON.stringify(E(ticker))])
    _TableObj.rows.push([JSON.stringify(E(records[records.length - 1])) + JSON.stringify(E(records[records.length - 2])) + " records.length : " + records.length])
    _TableObj.rows.push([JSON.stringify(E(depth.Asks[0])) + JSON.stringify(E(depth.Bids[0])) + "Asks`s length is:" + depth.Asks.length + "Bids`s length is:" + depth.Bids.length])

    _chartObj = $.PlotRecords(records, "K线")

    /*
    if(_isFirst){
        _chart.reset()
        _isFirst = false
    }
    */
}

function Custom_GetPositons(symbol){
    var positions = exchange.GetPosition()
    if(!positions){
        Log("Custom_GetPositons failed", positions)
    }
    if(typeof(symbol) != "undefined"){
        Log("PD_LONG:", E(_templeteObj.GetPosition(symbol, PD_LONG, positions)))
        Log("PD_SHORT:", E(_templeteObj.GetPosition(symbol, PD_SHORT, positions)))
        Log("positions:", E(positions))
    }else{
        Log("positions:", E(positions))
    }
}

function Custom_Buy(symbol, amount){
    // exchange.SetDirection("buy")
    if(!$.IsTrading(symbol)){
        Log(symbol, " 不在交易时间段内,禁止下单!")
        return
    }
    var tradeInfo = _templeteObj.OpenLong(symbol, amount)
    Log(tradeInfo)
}

function Custom_Pending_Buy(diffPrice, amount, direction){
    if(!$.IsTrading(_StrContractType)){
        Log(_StrContractType, " 不在交易时间段内,禁止下单!")
        return
    }
    exchange.SetContractType(_StrContractType)
    var ticker = _C(exchange.GetTicker)
    exchange.SetDirection(direction)
    var id = exchange.Buy(ticker.Last - diffPrice, amount)
    Log("id:", id)
}

function Custom_Pending_Sell(diffPrice, amount, direction){
    if(!$.IsTrading(_StrContractType)){
        Log(_StrContractType, " 不在交易时间段内,禁止下单!")
        return
    }
    exchange.SetContractType(_StrContractType)
    var ticker = _C(exchange.GetTicker)
    exchange.SetDirection(direction)
    var id = exchange.Sell(ticker.Last + diffPrice, amount) 
    Log("id:", id)
}

function Custom_Sell(symbol, amount){
    // exchange.SetDirection("sell")
    if(!$.IsTrading(symbol)){
        Log(symbol, " 不在交易时间段内,禁止下单!")
        return
    }
    var tradeInfo = _templeteObj.OpenShort(symbol, amount)
    Log(tradeInfo)
}

function Custom_Cover(symbol, amount){
    if(!$.IsTrading(symbol)){
        Log(symbol, " 不在交易时间段内,禁止下单!")
        return
    }
    _templeteObj.Cover(symbol, amount)
}

function ChangeContractType(symbol){
    _StrContractType = symbol
    Log("测试 合约更改为:", _StrContractType)
    Log("清空图表!", "#FF0000")
    if(_chartObj){
        _chartObj.reset()
        $.SetPreBarTime(0)
    }
}

function Custom_GetPendingOrders(symbol){
    var orders = _C(exchange.GetOrders)
    if(orders.length == 0){
        Log(E(orders))
    }
    for(var i = 0 ; i < orders.length ; i++){
        if(typeof(symbol) == "undefined"){
            Log(E(orders[i]))
        }else{
            if(symbol == orders[i].ContractType){
                Log(E(orders[i]))
            }else if(i == orders.length - 1){
                Log(E(orders))
            }
        }
    }
}

function Custom_GetOrder(symbol, id){
    _C(exchange.SetContractType, symbol)
    var order = exchange.GetOrder(id)
    if(!order){
        Log("GetOrder failed, the order is", order)
        return false
    }else{
        Log(E(order))
    }
}

function Custom_CancelOrder(symbol, id){
    Log("取消的订单 id 是:", symbol, id)
    if(typeof(id) == "undefined"){
        id = symbol
        symbol = _StrContractType
    }

    if(!$.IsTrading(symbol)){
        Log(symbol, " 不在交易时间段内,禁止下单!")
        return
    }

    exchange.CancelOrder(id)  // CancelOrder(orderId)
}

function main(){
    LogReset()
    Log("启动!")

    _chart = $.GetCfg()
    Chart(_chart).reset()

    SetErrorFilter("login");
    var connectState = null
    _templeteObj = $.NewPositionManager()

    while(true){
        if(exchange.IO("status")){
            onTick(_StrContractType)       
            connectState = CONNECTED     
        }else{
            
            connectState = NOTCONNECTED
        }
        
        var cmd = GetCommand()
        if(cmd){
            Log("接收到命令:", cmd, "#0000FF")
            var array_cmd = cmd.split(':')
            if(array_cmd.length > 2){
                for(var idx = 2; idx < array_cmd.length; idx++){
                    array_cmd[1] += (':' + array_cmd[idx])
                }
                array_cmd = [array_cmd[0], array_cmd[1]]       // 重新赋值
            }
        
            if(array_cmd.length == 1){                     // button
                switch(array_cmd[0]){
                    case "GET_PNEDING" :
                        Custom_GetPendingOrders(_StrContractType)
                        break
                    case "GET_ALL_POSITION" :
                        Custom_GetPositons()
                        break
                    default :
                        Log("unknow command:" + array_cmd, "#FF0000")
                }
            }else if(array_cmd.length == 2){ // other
                switch(array_cmd[0]){
                    case "OPEN_LONG" :
                        var amount = parseInt(array_cmd[1])
                        Custom_Buy(_StrContractType, amount)
                        break
                    case "OPEN_SHORT":
                        var amount = parseInt(array_cmd[1])
                        Custom_Sell(_StrContractType, amount)
                        break
                    case "COVER" :
                        var amount = parseInt(array_cmd[1])
                        Custom_Cover(_StrContractType, amount)
                        break
                    case "GET_ORDER" :
                        Custom_GetOrder(_StrContractType, array_cmd[1])
                        break
                    case "GET_POSITION" :
                        if(array_cmd[1] == "空"){
                            Custom_GetPositons(_StrContractType)
                        }else{
                            Custom_GetPositons(array_cmd[1])
                        }
                        break
                    case "changeSymbol" :
                        ChangeContractType(array_cmd[1]) 
                        break
                    case "CANCEL_ORDER" :   
                        // Log("CANCEL_ORDER:", array_cmd)            
                        Custom_CancelOrder(array_cmd[1])
                        break
                    case "JS_CODE" :
                        var js = cmd.split(':', 2)[1];  // 分割 返回的消息 字符串, 限制返回2个, 把索引为1的 元素 赋值给 名为js 的变量 
                        Log("执行调试代码:", js);         // 输出 执行的代码
                        try {                           // 异常检测
                            eval(js);                   // 执行 eval函数, 该函数执行传入的参数(代码)。
                        } catch(e) {                    // 抛出异常
                            Log("Exception", e);        // 输出错误信息
                        }
                        break
                    default :
                        Log("unknow command:" + array_cmd, "#FF0000")
                }
            }
        }
        var strConnectState = connectState == CONNECTED ? "已经连接!" : "未连接!"
        LogStatus(_D(), strConnectState, _LogStatusMessage, '\n`' + JSON.stringify(_TableObj) + '`' + '\n' + 
            'Custom_CancelOrder("", "")    // symbol, id' + '\n' + 
            'Custom_Pending_Buy( , , "")    // diffPrice, amount, direction' + '\n' +
            'Custom_Pending_Sell( , , "")    // diffPrice, amount, direction' + '\n' )
        Sleep(_Interval)
    }
}


测试 截图:

要注意 测试 自己的 账号要在 商品期货 开市时间。


策略源码地址: botvs.com/strategy/5912


发明者量化(FMZ.COM) (原BotVS量化平台)

授权首发刊载

编辑于 2018-07-05

文章被以下专栏收录