seerline/clchart

View on GitHub
src/formula/cl.formula.js

Summary

Maintainability
A
50 mins
Test Coverage
/**
 * Copyright (c) 2018-present clchart Contributors.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

// 预先定义好的公式,比如MA等,可在这里扩展公式定义
// 用户可以自定义公式注册到ClData层,便于系统调用

import getValue from '../data/cl.data.tools'

/**
 * Class representing ClFormula
 * @export
 * @class ClFormula
 */
export class ClFormula {
  /**
   * Creates an instance of ClFormula.
   * @constructor
   */
  constructor () {
    this.source = {
      data: {},
      minIndex: 0,
      maxIndex: 0,
      nowIndex: 0
    }
  }
  /**
   * get value from data layer
   * @param {String} label
   * @param {Number} offIndex
   * @return {Array}
   * @memberof ClFormula
   */
  getValue (label, offIndex) { // offIndex 向前偏移offIndex条记录
    if (label === undefined) return 0
    if (this.source.data === undefined || this.source.data.value === undefined) return 0

    if (this.source.nowIndex === undefined) this.source.nowIndex = this.source.minIndex
    const index = this.source.nowIndex - offIndex

    return getValue(this.source.data, label, index)
  }
  /**
   * calculate single stock data by formula
   * @param {Object} source
   * @param {String} formula
   * @return {Array}
   * @memberof ClFormula
   */
  runSingleStock (source, formula) {
    // fix for Wechat mina do not support eval
    if (!eval) {
      const singleValue = []
      const matchData = formula.match(/\.(\w+)(\(.+)/)
      const funcName = matchData[1]
      if (typeof this[funcName] !== 'function') {
        return singleValue
      }
      let argStr = matchData[2] || ''
      argStr = argStr.replace(/\(|\)/g, '').split(',')
      this.source = source
      for (this.source.nowIndex = this.source.minIndex; this.source.nowIndex <= this.source.maxIndex; this.source.nowIndex++) {
        const out = this[funcName](...argStr)
        singleValue.push([this.getValue('idx', 0), out])
      }
      return singleValue
    }
    const singleValue = []
    this.source = source
    const command = `
    for (this.source.nowIndex = this.source.minIndex;this.source.nowIndex <= this.source.maxIndex;this.source.nowIndex++) {
          const ${formula}
          singleValue.push([this.getValue('idx', 0), out]);
    }`
    eval(command)
    return singleValue
  }

  //  自定义公式

  /**
   * calculate move averge data
   * @param {String} label
   * @param {Number} period
   * @return {Array}
   * @memberof ClFormula
   */
  MA (label, period) {
    let off = 0
    let value = 0
    for (let m = 0; m < period; m++) {
      const v = this.getValue(label, m)
      if (v !== 0) {
        off++
        value += v
      }
    }
    return off === 0 ? 0 : value / off
  }
  SUM (label, period) {
    let value = 0
    for (let m = 0; m < period; m++) {
      const v = this.getValue(label, m)
      if (v !== 0) {
        value += v
      }
    }
    return value
  }
  VEMA (label, period) {
    let zoom = 1/period
    let off = 1
    let value = 0
    for (let m = 0; m < period; m++) {
      const v = this.getValue(label, m)
      if (v === 0) continue;
      if ( m === 0)
      {
        value += v
        continue;
      }
      off += Math.pow(1 - zoom, m)
      value += v*Math.pow(1 - zoom, m)
      
    }
    return off === 0 ? 0 : value / off
  }
  AVGPRC () {
    let value = 0
    value = this.getValue('allmoney', 0) / this.getValue('allvol', 0)
    return value
  }
}