golang实现ema及解决pandas计算ema与talib差异
文章目录
解决ema计算差异问题
- pandas用法:
df['close'].ewm(span=12 * 12 * 1, adjust=False).mean()
- talib用法:
talib.set_compatibility(1)
talib.EMA(df['close'], timeperiod=12 * 12 * 1)
- golang使用(代码在后面)
EmaCompatibility(prices, 12 * 12 * 1)
python中计算ema两种方式:
- pandas使用ewm这个窗口函数
- 使用talib.EMA函数
- 参考: https://www.joinquant.com/view/community/detail/3d88c84f05e5a3bd72f728a40e54edf4
- c源码: https://github.com/TA-Lib/ta-lib/blob/master/src/ta_func/ta_EMA.c#L291
但是计算完结果有差异,原因是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
}