# 引言

使用指定数据方式得到的线条总是不能达到想要的效果,一是阶梯线在价格发生变化的点存在倾斜,二是高低价的线很难完美显示,所以只能自己动手画了。代码仅供参考,如有错误的地方请指正!
ee3c75b472c5869794e205747703d888.png

# 模版代码

this.chart.addTechnicalIndicatorTemplate({
	name: 'BandHighLowInd',
    shortName: '波段高低价',
    calcParams: [{ value: 10 }],
    precision: 2,
    plots: [
      { key: 'high', title: '高: ', color: (data, options) => { return options.line.colors[0] } },
      { key: 'low', title: '低: ', color: (data, options) => { return options.line.colors[1] } },
      { key: 'highLow', title: '高低: ', color: (data, options) => { return options.line.colors[2] } }
    ],
    calcTechnicalIndicator: (dataList, { params }) => {
      let compareKlineSize = params[0] // 取前后 k 的范围
      let highs = []
      let lows = []
      let highLows = []
      let findHigh // 高低价当前查找标识
      dataList.forEach(function (kLineData, i) {
        let frontIndex = i - compareKlineSize
        if (frontIndex <= 0) {
          frontIndex = 0
        }
        let frontDatas = []
        if (frontIndex < i) {
          frontDatas = dataList.slice(frontIndex, i)
        }
        let afterIndex = i + compareKlineSize + 1
        let afterDatas = []
        if (i < dataList.length - 1) {
          afterDatas = dataList.slice(i + 1, afterIndex)
        }
        if (frontDatas.length === compareKlineSize && afterDatas.length === compareKlineSize) { // 前后 K 线数据必须都找到要比较的条数
          let high = null
          let low = null
          frontDatas.concat(afterDatas).forEach(function (kLineData, i) { // 找出前后 k 线中的最高和最低价
            if (high === null || kLineData.high > high) {
              high = kLineData.high
            }
            if (low === null || kLineData.low < low) {
              low = kLineData.low
            }
          })
          if (kLineData.high > high) { // 当前 k 的高大于前后 k 中找出的高,则放入高价集合中
            highs.push({
              time: kLineData.timestamp,
              value: kLineData.high,
              index: i
            })
            if (isNotEmpty(findHigh)) {
              if (findHigh && highLows[highLows.length - 1].value !== kLineData.high) {
                highLows.push({
                  time: kLineData.timestamp,
                  value: kLineData.high,
                  index: i
                })
                findHigh = false
              }
            } else {
              highLows.push({
                time: kLineData.timestamp,
                value: kLineData.high,
                index: i
              })
              findHigh = false
            }
          }
          if (kLineData.low < low) { // 当前 k 的低小于前后 k 中找出的低,则放入低价集合中
            lows.push({
              time: kLineData.timestamp,
              value: kLineData.low,
              index: i
            })
            if (isNotEmpty(findHigh)) {
              if (!findHigh && highLows[highLows.length - 1].value !== kLineData.low) {
                highLows.push({
                  time: kLineData.timestamp,
                  value: kLineData.low,
                  index: i
                })
                findHigh = true
              }
            } else {
              highLows.push({
                time: kLineData.timestamp,
                value: kLineData.low,
                index: i
              })
              findHigh = true
            }
          }
        }
      })
      let high, low, highLow
      return dataList.map((kLineData, i) => {
        let item = {
        }
        highs.forEach((data) => {
          if (kLineData.timestamp === data.time) {
            high = data.value
            item.highOrigin = true
          }
        })
        if (isNotEmpty(high)) { // 持续先前的高,画出阶梯线
          item.timestamp = kLineData.timestamp
          item.high = high
        }
        lows.forEach((data) => {
          if (kLineData.timestamp === data.time) {
            low = data.value
            item.lowOrigin = true
          }
        })
        if (isNotEmpty(low)) { // 持续先前的低,画出阶梯线
          item.timestamp = kLineData.timestamp
          item.low = low
        }
        highLows.forEach((data) => {
          if (kLineData.timestamp === data.time) {
            highLow = data.value
            item.highLowOrigin = true
          }
        })
        if (isNotEmpty(highLow)) { // 持续先前的高低,方便 title 显示
          item.timestamp = kLineData.timestamp
          item.highLow = highLow
        }
        return item
      })
    },
    render: ({ ctx, dataSource, viewport, styles, xAxis, yAxis }) => {
      if (dataSource.technicalIndicatorDataList.length <= 0) {
        return
      }
      let x = xAxis.convertToPixel(0)
      let high, low, highLow, highLowX
      dataSource.technicalIndicatorDataList.forEach(function (data, i) {
        // 画高线
        ctx.textBaseline = 'middle'
        ctx.textAlign = 'center'
        ctx.fillStyle = '#fff'
        ctx.strokeStyle = '#fff'
        if (styles.line && styles.line.colors && styles.line.colors[0]) {
          ctx.fillStyle = styles.line.colors[0]
          ctx.strokeStyle = styles.line.colors[0]
        }
        if (isNotEmpty(high) && data.high !== high) {
          ctx.beginPath()
          ctx.moveTo(x, yAxis.convertToPixel(high))
          ctx.lineTo(x, yAxis.convertToPixel(data.high))
          ctx.stroke()
          ctx.closePath()
        }
        high = data.high
        let y = yAxis.convertToPixel(high)
        ctx.beginPath()
        ctx.moveTo(x, y)
        ctx.lineTo(x + viewport.dataSpace, y)
        ctx.stroke()
        ctx.closePath()
        // 画低线
        ctx.fillStyle = '#fff'
        ctx.strokeStyle = '#fff'
        if (styles.line && styles.line.colors && styles.line.colors[1]) {
          ctx.fillStyle = styles.line.colors[1]
          ctx.strokeStyle = styles.line.colors[1]
        }
        if (isNotEmpty(low) && data.low !== low) {
          ctx.beginPath()
          ctx.moveTo(x, yAxis.convertToPixel(low))
          ctx.lineTo(x, yAxis.convertToPixel(data.low))
          ctx.stroke()
          ctx.closePath()
        }
        low = data.low
        y = yAxis.convertToPixel(low)
        ctx.beginPath()
        ctx.moveTo(x, y)
        ctx.lineTo(x + viewport.dataSpace, y)
        ctx.stroke()
        ctx.closePath()
        // 画高低线
        if (isNotEmpty(data.highLow) && data.highLowOrigin === true) {
          if (isNotEmpty(highLow) && isNotEmpty(highLowX)) {
            ctx.fillStyle = '#fff'
            ctx.strokeStyle = '#fff'
            if (styles.line && styles.line.colors && styles.line.colors[2]) {
              ctx.fillStyle = styles.line.colors[2]
              ctx.strokeStyle = styles.line.colors[2]
            }
            ctx.beginPath()
            ctx.moveTo(highLowX, yAxis.convertToPixel(highLow))
            ctx.lineTo(x, yAxis.convertToPixel(data.highLow))
            ctx.stroke()
            ctx.closePath()
          }
          highLow = data.highLow
          highLowX = x
        }
        // 画价格
        if (data.high !== undefined && data.highOrigin === true) { // 画高价
          let text = Number.parseFloat(data.high).toFixed(2)
          ctx.fillStyle = '#fff'
          if (styles.line && styles.line.colors && styles.line.colors[0]) {
            ctx.fillStyle = styles.line.colors[0]
          }
          let offset = 10
          let y = yAxis.convertToPixel(data.high)
          for (let i = 2; i < offset - 1; i += 2) {
            ctx.fillText('.', x, y - i)
          }
          ctx.fillText(text, x, y - offset)
        }
        if (data.low !== undefined && data.lowOrigin === true) { // 画低价
          let text = Number.parseFloat(data.low).toFixed(2)
          ctx.fillStyle = '#fff'
          if (styles.line && styles.line.colors && styles.line.colors[1]) {
            ctx.fillStyle = styles.line.colors[1]
          }
          let offset = 15
          let y = yAxis.convertToPixel(data.low)
          for (let i = 2; i < offset - 5; i += 2) {
            ctx.fillText('.', x, y + i)
          }
          ctx.fillText(text, x, y + offset)
        }
        x += viewport.dataSpace
      })
    }
})
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Hito Li 微信支付

微信支付

Hito Li 支付宝

支付宝