Go语言怎么处理程序化交易中的K线数据

本文小编为大家详细介绍“Go语言怎么处理程序化交易中的K线数据”,内容详细,步骤清晰,细节处理妥当,希望这篇“Go语言怎么处理程序化交易中的K线数据”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

十年的谷城网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。全网营销推广的优势是能够根据用户设备显示端的尺寸不同,自动调整谷城建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。创新互联建站从事“谷城网站设计”,“谷城网站推广”以来,每个客户项目都认真落实执行。

前言

在编写程序化交易策略时,使用K线数据,经常会有需求使用一些非标准周期K线数据的情况,例如需要使用12分钟周期K线数据、4小时K线周期数据,通常这类非标准周期是无法直接获取的。那么我们如何应对此类需求呢?
答案肯定是有办法的。
非标准周期可以通过更小周期的数据,合并合成获取,可以想象一下,多个周期中的最高价,算作合成后的最高价,最低价算作合成后的最低价,开盘价不会变,就用合成这根K线原料数据的第一个开盘价,收盘价对应的是用合成这根K线的原料数据的最后一个的收盘价,时间就是取的开盘价的时间,成交量用原料数据的交易量求和计算得出。

思路

我们以区块链资产市场BTC_USDT为例,用1小时合成为4小时。

Go语言怎么处理程序化交易中的K线数据

Go语言怎么处理程序化交易中的K线数据

Go语言怎么处理程序化交易中的K线数据

Go语言怎么处理程序化交易中的K线数据

Go语言怎么处理程序化交易中的K线数据

可以看到数据是一致的。

编写代码实现

验证了初步的思路,就可以动手写一写代码初步实现一下这个需求了。直接放出代码,代码仅供参考学习:

  function GetNewCycleRecords (sourceRecords, targetCycle) {    // K线合成函数
      var ret = []
      
      // 首先获取源K线数据的周期
      if (!sourceRecords || sourceRecords.length < 2) {
          return null
      }
      var sourceLen = sourceRecords.length
      var sourceCycle = sourceRecords[sourceLen - 1].Time - sourceRecords[sourceLen - 2].Time

      if (targetCycle % sourceCycle != 0) {
          Log("targetCycle:", targetCycle)
          Log("sourceCycle:", sourceCycle)
          throw "targetCycle is not an integral multiple of sourceCycle."
      }

      if ((1000 * 60 * 60) % targetCycle != 0 && (1000 * 60 * 60 * 24) % targetCycle != 0) {
          Log("targetCycle:", targetCycle)
          Log("sourceCycle:", sourceCycle)
          Log((1000 * 60 * 60) % targetCycle, (1000 * 60 * 60 * 24) % targetCycle)
          throw "targetCycle cannot complete the cycle."
      }

      var multiple = targetCycle / sourceCycle


      var isBegin = false 
      var count = 0
      var high = 0 
      var low = 0 
      var open = 0
      var close = 0 
      var time = 0
      var vol = 0
      for (var i = 0 ; i < sourceLen ; i++) {
          // 获取 时区偏移数值
          var d = new Date()
          var n = d.getTimezoneOffset()

          if (((1000 * 60 * 60 * 24) - sourceRecords[i].Time % (1000 * 60 * 60 * 24) + (n * 1000 * 60)) % targetCycle == 0) {
              isBegin = true
          }

          if (isBegin) {
              if (count == 0) {
                  high = sourceRecords[i].High
                  low = sourceRecords[i].Low
                  open = sourceRecords[i].Open
                  close = sourceRecords[i].Close
                  time = sourceRecords[i].Time
                  vol = sourceRecords[i].Volume

                  count++
              } else if (count < multiple) {
                  high = Math.max(high, sourceRecords[i].High)
                  low = Math.min(low, sourceRecords[i].Low)
                  close = sourceRecords[i].Close
                  vol += sourceRecords[i].Volume

                  count++
              }

              if (count == multiple || i == sourceLen - 1) {
                  ret.push({
                      High : high,
                      Low : low,
                      Open : open,
                      Close : close,
                      Time : time,
                      Volume : vol,
                  })
                  count = 0
              }
          }
      }

      return ret 
  }

  // 测试
  function main () {
      while (true) {
          var r = exchange.GetRecords()                           // 原始数据,作为合成K线的基础K线数据,例如要合成4小时K线,可以用1小时K线作为原始数据。
          var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4)      // 通过 GetNewCycleRecords 函数 传入 原始K线数据 r , 和目标周期, 1000 * 60 * 60 * 4 即 目标合成的周期 是4小时K线数据。

          $.PlotRecords(r2, "r2")                                 // 策略类库栏 可以勾选画线类库,调用 $.PlotRecords 画线类库 导出函数 画图。
          Sleep(1000)                                             // 每次循环间隔 1000 毫秒,防止访问K线接口获取数据过于频繁,导致交易所限制。
      }
  }

其实要合成K线,就需要两个东西,第一是需要原料数据,即小周期的K线数据,例子中 var r = exchange.GetRecords()。获取的小周期K线数据。第二是需要明确合成为多大的周期,即K线数据合成的目标周期。然后通过GetNewCycleRecords函数的算法,就可以最后返回一个合成出来的K线数组结构的数据了。实盘运行了一下:
Go语言怎么处理程序化交易中的K线数据

对比交易所图表
Go语言怎么处理程序化交易中的K线数据

需要注意的是:目标周期不能小于你传入GetNewCycleRecords 函数作为数据原料的K线的周期,因为无法用小周期去合成更小的周期的数据。设置的目标周期必须是周期闭合的。例如 12分钟周期的K线,从每个小时的0分0秒开始(以0时举例),第一个周期是00:00:00 ~ 00:12:00,第二个周期是00:12:00 ~ 00:24:00,第三个周期是00:24:00 ~ 00:36:00,第四个周期是00:36:00 ~ 00:48:00,第五个周期是00:48:00 ~ 01:00:00 ,正好组成一个完整的1小时。如果是 13分钟周期,就是不闭合的周期,这样的周期算出的数据不唯一,因为根据合成的数据起始点不同,合成出来的数据有差异。

使用K线数据构造需要的数据结构

经常有群友提问,我想计算每根K线的最高价的均线,怎么办?通常,我们计算均线都是计算的收盘价的均值,组成均线,但是也有时候有需求计算最高价、最低价、开盘价等等。这个时候就不能直接把exchange.GetRecords() 函数返回的K线数据直接传入 指标计算函数了。例如:talib.MA 均线指标计算函数有两个参数,第一个参数是需要传入的数据,第二个参数是指标周期参数。例如我们要算如下图的指标:
Go语言怎么处理程序化交易中的K线数据

K线周期是4小时,在交易所图表上,已经设置好了一条均线,均线周期参数为9。并且设置计算的数据源是每根Bar的最高价。
Go语言怎么处理程序化交易中的K线数据
即这条均线是9个4小时周期K线Bar的最高价平均计算出的均值,组成的指标均线。我们自己动手构造一个数据算下,看是不是和交易所的图表计算得出的一样。

var highs = []
for (var i = 0 ; i < r2.length ; i++) {
    highs.push(r2[i].High)
}

既然要计算每根Bar的最高价的均值得出均线指标。那么就需要先构造一个数组,其中每个数据元素都是对应每根Bar的最高价。可以看到 highs 变量初始为一个空数组,然后我们遍历 r2 这个K线数据变量(不记得r2了?看下上面合成4小时K线的main函数中的代码)。读取r2每根Bar的最高价(即 r2[i].High , i取值范围 从 0 到 r2.length - 1 ),然后 push 进highs 。这样就构造了一个和K线数据Bar一一对应的数据结构。此时 highs 就可以传入 talib.MA函数计算出均线了。

完整的例子:

function main () {
    while (true) {
        var r = exchange.GetRecords()
        var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4)
        if (!r2) {
            continue
        }
        
        $.PlotRecords(r2, "r2")                                               // 画出K线
        
        var highs = []
        for (var i = 0 ; i < r2.length ; i++) {
            highs.push(r2[i].High)
        }
        
        var ma = talib.MA(highs, 9)                                           // 用均线指标函数 talib.MA 计算 均线指标
        $.PlotLine("high_MA9", ma[ma.length - 2], r2[r2.length - 2].Time)     // 使用画线类库把均线指标画在图表上
        
        Sleep(1000)
    }
}

回测运行:

Go语言怎么处理程序化交易中的K线数据

可以看到 图中鼠标停留位置的均线指标值均为 11466.9289。以上代码可以复制到策略中运行测试,记得勾选「画线类库」后保存!

数字货币市场的K线数据获取方式

发明者量化交易平台已经有封装好的接口,即 exchange.GetRecords 函数,即可获取K线数据。下面着重讲解的是直接访问交易所K线数据接口获取数据,因为有时候需要指定参数获取更多的K线,封装的GetRecords 接口一般是返回 100根。如果遇到策略初始需要超过100根的K线时,就需要收集等待。
为了让策略尽快进行运作,可以自己封装一个函数,直接访问交易所K线接口,指定参数获取更多的K线数据。以火币币币交易 BTC_USDT 交易对为例,我们实现这个需求:找到交易所的API文档,查看K线接口描述:
Go语言怎么处理程序化交易中的K线数据

https://api.huobi.pro/market/history/kline?period=1day&size=200&symbol=btcusdt

参数:

测试代码:

function GetRecords_Huobi (period, size, symbol) {
    var url = "https://api.huobi.pro/market/history/kline?" + "period=" + period + "&size=" + size + "&symbol=" + symbol
    var ret = HttpQuery(url)
    
    try {
        var jsonData = JSON.parse(ret)
        var records = []
        for (var i = jsonData.data.length - 1; i >= 0 ; i--) {
            records.push({
                Time : jsonData.data[i].id * 1000,
                High : jsonData.data[i].high,
                Open : jsonData.data[i].open,
                Low : jsonData.data[i].low,
                Close : jsonData.data[i].close,
                Volume : jsonData.data[i].vol,
            })
        }
        return records
    } catch (e) {
        Log(e)
    }
}  


function main() {
    var records = GetRecords_Huobi("1day", "300", "btcusdt")
    Log(records.length)
    $.PlotRecords(records, "K")
}

Go语言怎么处理程序化交易中的K线数据

Go语言怎么处理程序化交易中的K线数据

可以看到日志上,打印 records.length 为 300, 即 records K线数据 bar 数量有300根。
Go语言怎么处理程序化交易中的K线数据

读到这里,这篇“Go语言怎么处理程序化交易中的K线数据”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注创新互联行业资讯频道。


网站标题:Go语言怎么处理程序化交易中的K线数据
URL链接:http://cdiso.cn/article/pghdih.html

其他资讯