一根k线的故事

Author: ianzeng123, Created: 2023-07-13 21:50:54, Updated: 2023-11-15 19:59:51

img

一根k线的故事

k线我们天天都在用,不管是分钟k线,日k线,月k线还是年k线,可以你知道一根k线是怎样形成的吗?

一根k线的数据结构是这样的,它包含一个时间戳,代表k线起始的时间,开盘价,最高价,最低价,收盘价和成交量,我们都很熟悉:


{ 
    Time : 1567736576000, // 一个时间戳,精确到毫秒,与Javascript的new Date().getTime()得到的结果格式一样 
    Open : 1000, // 开盘价 
    High : 1500, // 最高价 
    Low : 900, // 最低价 
    Close : 1200, // 收盘价 
    Volume : 1000000 // 交易量 }

但是,原始的k线是不存在的,每一根k线都是由tick数据合成的。

{
    Info    : {...},             
    High    : 1000,              // 最高价
    Low     : 500,               // 最低价
    Sell    : 900,               // 卖一价
    Buy     : 899,               // 买一价
    Last    : 900,               // 最后成交价
    Volume  : 10000000,          // 最近成交量
    Time    : 1567736576000      // 毫秒级别时间戳
}

K线是通过将tick数据按照一定的时间间隔进行合并而生成的。一种常见的方法来合成K线是这样的:

  1. 确定K线的时间间隔:首先,你需要确定每个K线的时间间隔,例如1分钟、5分钟、15分钟等。这个时间间隔决定了每个K线的时间范围。

  2. 收集tick数据:从交易所获取到的tick数据包含了每一笔交易的价格、成交量和时间戳等信息。你需要收集足够多的tick数据来生成K线。

  3. 分组tick数据:将收集到的tick数据按照时间间隔进行分组。对于每个时间间隔,你需要将对应时间范围内的tick数据进行分组。

  4. 计算K线数据:对于每个时间间隔的tick数据分组,你可以根据需要计算K线的开盘价、最高价、最低价、收盘价和成交量等数据。常见的计算方法包括:

    • 开盘价:取该时间间隔内的第一笔交易的价格作为开盘价。
    • 最高价:取该时间间隔内的所有交易的最高价格。
    • 最低价:取该时间间隔内的所有交易的最低价格。
    • 收盘价:取该时间间隔内的最后一笔交易的价格作为收盘价。
    • 成交量:累加该时间间隔内的所有交易的成交量。
  5. 生成K线:根据计算得到的K线数据,你可以生成相应的K线。每个K线包含了开盘价、最高价、最低价、收盘价和成交量等信息。

需要注意的是,K线的合成方法可能因交易所和数据源而异。有些交易所可能提供直接的K线数据,而无需手动合成。此外,还有其他的K线合成方法,例如基于成交量、价格范围等的合成方法。具体的合成方法取决于你的需求和数据源的特点。

那么你现在知道k线是怎么合成出来了,可是你知道怎么画一根k线吗?

var cfgA = [{
    __isStock: true,
    title: {
        text: 'A'
    },
    series: [{
        type: 'candlestick',
        name: 'A',
        id: 'A',
        data: []
    }]
}];

function main() {
    var symbols = "rb888";
    var chart = Chart(cfgA);
    chart.reset();

    var arrLastTime = 0;

    while (true) {
        if (exchange.IO("status")) {
            LogStatus("时间:", _D(), ",已经连接");
            
            exchange.SetContractType(symbols);
            var r = exchange.GetRecords();
            
            for (var j = 0; j < r.length; j++) {
                if (r[j].Time > arrLastTime) {
                    // 增加
                    chart.add(0, [r[j].Time, r[j].Open, r[j].High, r[j].Low, r[j].Close]);
                    arrLastTime = r[j].Time;
                } 
                else if (r[j].Time == arrLastTime) {  
                    // 更新                                          
                    chart.add(0, [r[j].Time, r[j].Open, r[j].High, r[j].Low, r[j].Close], -1);
                }
            }
    
            chart.update(cfgA);
        }
        
        Sleep(5000);
    }
}

前面的图表设置我们不必于太过于关心,这里我们需要关注的是k线的数据是怎样添加的,让我们回到交易所接口返回的k线数据:

2023-07-12 09:02:00		信息	Records数据 [{"Time":1689123600000,"Open":3692,"High":3696,"Low":3692,"Close":3694,"Volume":9784,"OpenInterest":1799446},{"Time":1689123660000,"Open":3694,"High":3696,"Low":3693,"Close":3695,"Volume":5541,"OpenInterest":1798668},{"Time":1689123720000,"Open":3695,"High":3695,"Low":3695,"Close":3695,"Volume":0,"OpenInterest":1799071}]
2023-07-12 09:01:58		信息	Records数据 [{"Time":1689123600000,"Open":3692,"High":3696,"Low":3692,"Close":3694,"Volume":9784,"OpenInterest":1799446},{"Time":1689123660000,"Open":3694,"High":3696,"Low":3693,"Close":3695,"Volume":5541,"OpenInterest":1798668}]
2023-07-12 09:01:37		信息	Records数据 [{"Time":1689123600000,"Open":3692,"High":3696,"Low":3692,"Close":3694,"Volume":9784,"OpenInterest":1799446},{"Time":1689123660000,"Open":3694,"High":3696,"Low":3693,"Close":3696,"Volume":2770,"OpenInterest":1798668}]
2023-07-12 09:01:22		信息	Records数据 [{"Time":1689123600000,"Open":3692,"High":3696,"Low":3692,"Close":3694,"Volume":9784,"OpenInterest":1799446},{"Time":1689123660000,"Open":3694,"High":3694,"Low":3693,"Close":3693,"Volume":1847,"OpenInterest":1798668}]
2023-07-12 09:01:00		信息	Records数据 [{"Time":1689123600000,"Open":3692,"High":3696,"Low":3692,"Close":3694,"Volume":9784,"OpenInterest":1799446},{"Time":1689123660000,"Open":3694,"High":3694,"Low":3694,"Close":3694,"Volume":0,"OpenInterest":1798668}]
2023-07-12 09:00:58		信息	Records数据 [{"Time":1689123600000,"Open":3692,"High":3696,"Low":3692,"Close":3694,"Volume":9784,"OpenInterest":1799446}]
2023-07-12 09:00:37		信息	Records数据 [{"Time":1689123600000,"Open":3692,"High":3696,"Low":3692,"Close":3696,"Volume":4892,"OpenInterest":1799446}]

我们设置的周期为1分钟,有没有感到一点奇怪,为什么最后一根k线的数据不是固定的呢,可以看到时间是一样的,除了开盘价,其他值一直在变动:

img

只有到了新的时间段(Time),倒数第二个数据才算固定下来。OHLC和成交量都固定下来。

img

这是因为k线是被合成出来的,当最新的k线周期没有完成的时候,最后一根k线不是固定的,如果这里你理解了,你就可以明白了k线的数据是怎样添加的了。

循环语句 for (var j = 0; j < r.length; j++) 遍历了 r 数组中的所有元素,该数组包含了当前品种最新的 K 线数据。通过遍历 r 数组并将每个元素添加到当前品种对应的系列中,实现了将最新的 K 线数据添加到图表中并刷新的效果。在每次添加完数据之后,通过更新 arrLastTime 数组来记录最新的时间戳,并用于判断下一次是否需要添加/更新数据。

这里的数据添加和更新很有意思,如果上一根k线已经走完,就是新的时间戳大于上一个周期的时间戳,表示新的k线已经产生,这时候就要增加最新的数据。

 if (r[j].Time > arrLastTime) {
    // 增加
    chart.add(0, [r[j].Time, r[j].Open, r[j].High, r[j].Low, r[j].Close]);
    arrLastTime = r[j].Time;
} 
                

而如果此时的k线周期还没有完成,最新的k线数据还没有固定,这时候就要不断的更新最新的k线数据,add函数里最后使用-1进行k线数据的更新。

else if (r[j].Time == arrLastTime) {  
    // 更新                                          
    chart.add(0, [r[j].Time, r[j].Open, r[j].High, r[j].Low, r[j].Close], -1);
}

综上,这个 for 循环共同实现了将最新的 K 线数据添加到对应的系列中,用于刷新图表并展示最新的数据。

这就是一根k线的故事,希望大家有所收获。


更多内容