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

网格改进版 (实战原版)

Author: ianzeng123, Date: 2023-10-08 10:12:49
Tags:


/*backtest
start: 2023-01-03 09:00:00
end: 2023-09-30 15:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_CTP","currency":"FUTURES","depthDeep":20}]
args: [["symbol","c888"],["maxPos",3],["stdPeriod",30]]
*/

var obj = $.NewPositionManager(); // 使用发明者量化交易类库
var band = []; // 定义全局变量 band
var pos_dir = '--'
var pos_amount = '--'
var pos_price = '--'
var pos_profit = '--'
var pos_margin = 0
var stopprofit = 0
var stoploss = 0

function bandCal(records){
    var ma = TA.MA(records, maPeriod)[records.length - 1]
    var std = talib.STDDEV(records, stdPeriod)[records.length - 1]
    var array = [-1.96, -0.85, -0.53, 0.53, 0.85, 1.96];

    // 获取网格区间分界线
    var band = array.map(num => _N(ma + num * std, 2))
    return band
}

function timeSel() {
    var t = new Date();                  // 获取当前时间对象
    var hour = t.getHours();             // 获取当前小时:0~23
    var minute = t.getMinutes();         // 获取当前分钟:0~59
    var day = t.getDay();

    var isYes = false;

    var minuteStr = minute.toString();
    if (minuteStr.length === 1) {
        minuteStr = "0" + minuteStr;
    }
    curtime =  parseInt(hour.toString() + minuteStr, 10);

    if ((day >= 1 && day <= 5) && // Monday to Friday
        (curtime >= 900 && curtime <= 1130) || // 9:00 to 11:30 AM
        (curtime >= 1330 && curtime <= 1500) || // 1:30 to 3:00 PM
        (curtime >= 2100 && curtime <= 2300)) { // 21:00 to 23:00 PM
        isYes = true;
    }

    return isYes
}

function onTick(records, mainId) {

    // 此处用来获取持仓信息
    var positions = _C(exchange.GetPosition) // 获取持仓数组
    var position_amount = 0
    
    
    for (var i = 0; i < positions.length; i++) { // 遍历持仓数组
        if (positions[i]['Type'] === PD_LONG || positions[i]['Type'] === PD_LONG_YD) {
            position_amount = 1 * positions[i].Amount // 将position_long标记为正数
        } else if (positions[i]['Type'] === PD_SHORT || positions[i]['Type'] === PD_SHORT_YD) {
            position_amount = -1 * positions[i].Amount // 将position_short标记为负数
        }
    }

    // 根据价格落在(-inf,-1.96],(-1.96,-0.85],(-0.85,-0.53],(-0.53,0.53],(0.53,0.85], (0.85,1.96], (1.96, Inf) 的区间范围来获取最新收盘价所在的价格区间
    var grid = null
    var close_01 = records[records.length - 1].Close;

    if (close_01 > band[5]) {
        grid = 6
    } else if (close_01 > band[4]) {
        grid = 5
    } else if (close_01 > band[3]) {
        grid = 4
    } else if (close_01 > band[2]) {
        grid = 3
    } else if (close_01 > band[1]) {
        grid = 2
    } else if (close_01 > band[0]) {
        grid = 1
    } else {
        grid = 0
    }

    Log('当前网格区间:', grid)

    // 若无仓位且价格突破则按照设置好的区间开仓
    if (!position_amount) {
        if (grid == 6 || grid == 0) {
            band = bandCal(records) // 重新计算band
            _G('band', band)
            return('更新band')
        }

        if (grid > 3) {
            obj.OpenShort(mainId, 1); // 以市价单开空仓到仓位
            Log('空仓grid', grid)
        }
        if (grid < 3) {
            obj.OpenLong(mainId, 1); // 以市价单开多仓到仓位
            Log('多仓grid', grid)
        }
    }

    // 持有空仓的处理
    if (position_amount < 0) {
        // 突破区间,进行止损,重新计算band
        if (grid == 6) {
            Log('止损平仓grid', grid)
            obj.CoverAll(mainId) // 以市价单全平空仓
            band = bandCal(records) // 重新计算band
            stoploss += 1
        }
        // 等于3为在中间网格,平仓
        else if (grid <= 3) {
            Log('止盈平仓grid', grid)
            obj.CoverAll(mainId) // 以市价单全平空仓
            band = bandCal(records) // 重新计算band
            stopprofit += 1
        }
        // 大于3为在中间网格的下方,加仓
        else if (grid > 3 && -position_amount < maxPos) {
            obj.OpenShort(mainId, 1) // 以市价单调空仓到仓位
        }
    }

    // 持有多仓的处理
    if (position_amount > 0) {
        // 突破区间,进行止损,重新计算band
        if (grid == 0) {
            Log('止损平仓grid', grid)
            obj.CoverAll(mainId) // 以市价单全平多仓
            band = bandCal(records) // 重新计算band
            stoploss += 1
        }
        // 等于3为在中间网格,平仓
        else if (grid >= 3) {
            Log('止盈平仓grid', grid)
            obj.CoverAll(mainId) // 以市价单全平空仓
            band = bandCal(records) // 重新计算band
            stopprofit += 1
        }
        // 小于3为在中间网格的下方,加仓
        else if (grid < 3 && position_amount < maxPos) {
            obj.OpenLong(mainId, 1) // 以市价单调多仓到仓位
        }
    }
    

    _G('band', band)
}

function main() {
    SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused|(CTP_T@10010)")
    var preBartime = 0
    var initAccount = _C(exchange.GetAccount)

    // 获取主力合约
    if(exchange.IO("status")){
        var mainInfo = exchange.SetContractType(symbolID);
        var mainId = mainInfo.InstrumentID;
    }
    
    // 读取保存网格数据;
    band = _G('band')

    // 保存网格数据为空;
    if (band == null) {
        Log('无存储网格数据')
        _C(exchange.SetContractType, mainId)
        records = _C(exchange.GetRecords)
        
        if(records.length < 20) return
        band = bandCal(records)
        Log(band)
        _G('band', band)
        Log('已储存新的网格数据')
    }else{
        Log('载入已保存的网格数据')
    }

    while (true) { // 进入循环模式
        if(exchange.IO("status") && timeSel()){
            LogStatus("行情和交易服务器连接成功, " + _D())

            // 订阅合约
            var mainInfo = exchange.SetContractType(symbolID);
            var mainId = mainInfo.InstrumentID;

            exchange.SetContractType(mainId)
            var records = _C(exchange.GetRecords)
            
            if(preBartime != records[records.length - 1].Time){
                preBartime = records[records.length - 1].Time
                onTick(records, mainId)
            }

            var tblStatus = {
                type: "table",
                title: "持仓信息",
                cols: ["合约名称", "持仓方向", "持仓均价", "持仓数量", "持仓盈亏", "止盈次数", "止损次数"],
                rows: []
            }

            var statusPos = _C(exchange.GetPosition) // 获取持仓数组

            if(statusPos.length != 0){
                pos_dir = statusPos[0]['Type'] % 2 == 0 ? '多头' : '空头'
                pos_amount = statusPos[0]['Amount']
                pos_price = statusPos[0]['Price']
                pos_profit = statusPos[0]['Profit']
                pos_margin = statusPos[0].Margin
            }else{
                pos_dir = '--'
                pos_amount = '--'
                pos_price = '--'
                pos_profit = '--'
                pos_margin = 0
            }

            tblStatus.rows.push([mainId, pos_dir, pos_price, pos_amount, pos_profit, stopprofit, stoploss])

            lastStatus = '`' + JSON.stringify([tblStatus]) + '`'
            LogStatus(lastStatus)

            var accountInfo = _C(exchange.GetAccount)

            var curprofit = accountInfo.Info.Balance - initAccount.Info.Balance 
            LogProfit(curprofit, "权益", '&')
    
        }else{
            LogStatus("正在等待与交易服务器连接, " + _D())
        }
        Sleep(3000)
    }
}


更多内容