golang实现ema及解决pandas计算ema与talib差异

日期 2023年09月06日 09:31

分类 Golang

标签 ema pandas

浏览 5264

字数统计: 2977(字)

文章目录

解决ema计算差异问题

  1. pandas用法:
 df['close'].ewm(span=12 * 12 * 1, adjust=False).mean()
  1. talib用法:
talib.set_compatibility(1)
talib.EMA(df['close'], timeperiod=12 * 12 * 1)
  1. golang使用(代码在后面)
EmaCompatibility(prices, 12 * 12 * 1)

python中计算ema两种方式:

  1. pandas使用ewm这个窗口函数
  2. 使用talib.EMA函数

但是计算完结果有差异,原因是talib的c源码中有3种实现

/* The first EMA is calculated differently. It
 * then become the seed for subsequent EMA.
 *
 * The algorithm for this seed vary widely.
 * Only 3 are implemented here:
 *
 * TA_MA_CLASSIC:
 *    Use a simple MA of the first 'period'.
 *    This is the approach most widely documented.
 *
 * TA_MA_METASTOCK:
 *    Use first price bar value as a seed
 *    from the begining of all the available data.
 *
 * TA_MA_TRADESTATION: !!! not supported yet.
 *    Use 4th price bar as a seed, except when
 *    period is 1 who use 2th price bar or something
 *    like that... (not an obvious one...).
 */

python中默认是TA_MA_CLASSIC,需要使用talib.set_compatibility进行设置

import talib as ta

print(ta.get_compatibility()) # DEFAULT == 0

ta.set_compatibility(1) # METASTOCK == 1

print(ta.get_compatibility())

golang版本

查看了很多talib的golang的ema实现,都没有支持METASTOCK这种模式,经过仔细对比talib的c源码,实现了golang版本


type TaCompatibility string

const TA_MA_CLASSIC TaCompatibility = "TA_MA_CLASSIC"
const TA_MA_METASTOCK TaCompatibility = "TA_MA_METASTOCK"

// Ema - Exponential Moving Average (兼容模式)
func emaCompatibility(inReal []float64, inTimePeriod int, k1 float64, compatibility TaCompatibility) []float64 {
	// 初始返回
	var outReal = make([]float64, len(inReal))
	var prevMA float64
	// pandas - 兼容模式
	if compatibility == TA_MA_METASTOCK {
		// 计算起点数据是第一条价格
		prevMA = inReal[0]
		today := 1
		// 计算 - 起点数据(根k1相关)
		for today < inTimePeriod {
			prevMA = (inReal[today]-prevMA)*k1 + prevMA
			today++
		}
	} else {
		// 默认 - TA_MA_CLASSIC
		// 计算 - 起点数据是ma
		today := 0
		tempReal := 0.0
		i := inTimePeriod
		for i > 0 {
			tempReal += inReal[today]
			today++
			i--
		}
		prevMA = tempReal / float64(inTimePeriod)
	}
	// 填充前面数据
	for i := 0; i < inTimePeriod; i++ {
		outReal[i] = 0
	}
	// 这里很重要,作为后续计算起点
	outReal[inTimePeriod-1] = prevMA
	// 计算后续EMA
	for i := inTimePeriod; i < len(inReal); i++ {
		outReal[i] = inReal[i]*k1 + outReal[i-1]*(1-k1)
	}
	return outReal
}

// EmaCompatibility 兼容模式,首条数据为price而非均值,兼容python中pandas和talib库
func EmaCompatibility(inReal []float64, inTimePeriod int) []float64 {
	k := 2.0 / float64(inTimePeriod+1)
	outReal := emaCompatibility(inReal, inTimePeriod, k, TA_MA_METASTOCK)
	return outReal
}

// Ema 标准模式
func Ema(inReal []float64, inTimePeriod int) []float64 {
	k := 2.0 / float64(inTimePeriod+1)
	outReal := emaCompatibility(inReal, inTimePeriod, k, TA_MA_CLASSIC)
	return outReal
}