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

优宽量化模拟级别回测机制说明

Author: 雨幕(youquant), Created: 2021-11-05 14:59:01, Updated: 2022-07-03 09:37:26

优宽量化模拟级别回测机制说明


  • 1、回测架构

    优宽量化的回测中策略程序是完整的控制流程,程序是在按照一定的频率不停的轮询。各个行情、交易 API 返回的数据也是按照调用时刻,模拟实际运行时的情况。属于onTick级别,并非其它回测系统的onBar级别。更好的支持了基于Ticker数据的策略的回测(操作频率较高的策略)。

  • 2、模拟级别回测和实盘级别回测的区别

    • 模拟级别回测

      模拟级别回测是按照回测系统的底层K线数据,按照一定算法在给定的底层K线Bar的最高价、最低价、开盘价、收盘价的数值构成的框架内,模拟出ticker数据插值到这个Bar的时间序列中。

    • 实盘级别回测

      实盘级别回测是真实的ticker级别数据在Bar的时间序列中。对于基于ticker级别数据的策略来说,使用实盘级别回测更贴近真实。 实盘级别回测,ticker是真实记录的数据,并非模拟生成。

  • 3、模拟级别回测机制–底层K线

    实盘级别回测没有底层K线选项(因为ticker数据都是真实的,不用底层K线来模拟生成)。 模拟级别回测中,基于K线数据模拟生成的ticker。这个K线数据就是底层K线。在实际使用模拟级别回测中,底层K线周期必须小于策略运行时调用API获取K线的周期。否则,由于底层K线周期较大,生成的ticker数量不足,调用API获取指定周期的K线时,数据会有失真的情况。在使用大周期K线回测时,可以适当调大底层K线周期。

  • 4、底层K线如何生成ticker 数据

    底层K线生成模拟ticker的机制和MT4是一样的: 相关链接

    img img img img

  • 5、生成ticker数据的算法代码

    把底层K线数据模拟出tick数据的具体算法:

function recordsToTicks(period, num_digits, records) {
    // http://www.metatrader5.com/en/terminal/help/tick_generation
    if (records.length == 0) {
        return []
    }
    var ticks = []
    var steps = [0, 2, 4, 6, 10, 12, 16, 18, 23, 25, 27, 29]
    var pown = Math.pow(10, num_digits)

    function pushTick(t, price, vol) {
        ticks.push([Math.floor(t), Math.floor(price * pown) / pown, vol])
    }

    for (var i = 0; i < records.length; i++) {
        var T = records[i][0]
        var O = records[i][1]
        var H = records[i][2]
        var L = records[i][3]
        var C = records[i][4]
        var V = records[i][5]
        if (V > 1) {
            V = V - 1
        }
        if ((O == H) && (L == C) && (H == L)) {
            pushTick(T, O, V)
        } else if (((O == H) && (L == C)) || ((O == L) && (H == C))) {
            pushTick(T, O, V)
        } else if ((O == C) && ((O == L) || (O == H))) {
            pushTick(T, O, V / 2)
            pushTick(T + (period / 2), (O == L ? H : L), V / 2)
        } else if ((C == H) || (C == L)) {
            pushTick(T, O, V / 2)
            pushTick(T + (period * 0.382), (C == L ? H : L), V / 2)
        } else if ((O == H) || (O == L)) {
            pushTick(T, O, V / 2)
            pushTick(T + (period * 0.618), (O == L ? H : L), V / 2)
        } else {
            var dots = []
            var amount = V / 11
            pushTick(T, O, amount)
            if (C > O) {
                dots = [
                    O - (O - L) * 0.75,
                    O - (O - L) * 0.5,
                    L,
                    L + (H - L) / 3.0,
                    L + (H - L) * (4 / 15.0),
                    H - (H - L) / 3.0,
                    H - (H - L) * (6 / 15.0),
                    H,
                    H - (H - C) * 0.75,
                    H - (H - C) * 0.5,
                ]
            } else {
                dots = [
                    O + (H - O) * 0.75,
                    O + (H - O) * 0.5,
                    H,
                    H - (H - L) / 3.0,
                    H - (H - L) * (4 / 15.0),
                    H - (H - L) * (2 / 3.0),
                    H - (H - L) * (9 / 15.0),
                    L,
                    L + (C - L) * 0.75,
                    L + (C - L) * 0.5,
                ]
            }
            for (var j = 0; j < dots.length; j++) {
                pushTick(T + period * (steps[j + 1] / 30.0), dots[j], amount)
            }
        }
        pushTick(T + (period * 0.98), C, 1)
    }
    return ticks
}

所以,在使用模拟级别回测时会出现时间序列上的价格跳动。


更多内容