DIF,DEA及MACD——C++函数式元编程实现

目录

意义解释

MACD的延后性

程序实现

结果分析


意义解释

ema,dif,dea和macd是金融中的对于股票的4个指数,其计算数据集xn是收盘价格。ema为收盘价格当日加上N日内的惯性量。其递推计算公式如下:

dif是ema在近期(N_near)和远期(N_far)只差,表示的是近期与远期的残差,为近期价格发展趋势对比于长时间区域的增加或减少,正向越大表示上升幅度越大,是时间区间内收盘价格的变化趋势(可以理解为价格变化速度)。

dea是DEA_N日内dif的惯性加权值,表示的是时间区间内收盘价格变化的值(可以理解为价格变化速度的平滑值)。

macd是dif减dea的差值,本质意义是当日收盘变化趋势(dif)对比时间区间内的收盘变化趋势(dea)的趋势。由于dea是dif的平滑值,其中有之前时间的平滑,所以dif和dea的残差即今日dif对比近期内平滑速度的差值,即macd表征的是变化趋势的上升或者下降,进一步可解释为macd表示收盘价格正负向变化是要扩大还是减小(简单的说macd表示的是价格的变化加速度)。

以下为这几个参数的数学表示(截图自百度):

DIF,DEA及MACD——C++函数式元编程实现_第1张图片

MACD的延后性

前面说了MACD是收盘价格变化的“加速度”,但是这个加速度是有延后性的。我们从源头开始梳理一下,MACD由DIF和DEA的差值决定,DEF是DIF的惯性平滑值,DIF是EMA不同时间区间的差值,而EMA是收盘价格的惯性平滑值。重点在于这个“惯性平滑”,惯性平滑是使用之前的值加权到当天收盘价格上来表现的,因此这个值不会是今天的值,而必然是受之前时间区间内的值影响。试验过卡尔曼滤波的人应该知道,卡尔曼滤波在匀速运动时候是比较准确的,但是当其遇到大机动情况就会出现惯性偏移。从感性上可以这么理解,EMA是延后的,从而依赖于EMA的MACD在收盘价格运动模型出现变化的时候就会出现一点点的偏移,但是这个偏移会在较短时间内再次被消弭。经过观测现实数据,发现确实会存在这种情况,如下图:

DIF,DEA及MACD——C++函数式元编程实现_第2张图片

 观察蓝框中的价格变化以及下方的MACD。可以发现价格由涨变跌,加速度直观上来讲是负值,但是下方的MACD显示当天的加速度是正的,直到2天后才变成负值。由此可见在这个区间内MACD的延时应该为2-4天。

 

程序实现

为了便于理解,于此给出C++模板函数编程式编程的实现,以加深理解。

#include 
#include 
#include 
 
 /**
  * @brief  ema_t用于计算传入数组的惯性加权和
  * @note   N为总体数目,N_Left是剩余要加权的数目
  * @param  vec_input: 用于计算的数组
  * @param  N_Start: 当前加权开始位置
  * @retval 当前加权值加上其后值的加权值
  */
template
inline val_t ema_t(const typename std::vector& vec_input, const int& N_Start)
{
	if constexpr (N_Left == 1)
	{
		return vec_input[N_Start];
	}
	if constexpr (N_Left > 0)
	{
		return (2. * vec_input[N_Start] + ema_t(vec_input, N_Start + 1) * (N - 1) ) / (N + 1.);
	}
}
 
template
std::function(const typename std::vector&)> ema_gen() 
{
	return [](const std::vector& vec_input) 
	{
		size_t szt_output_num = vec_input.size() - N + 1;
		std::vector vec_ret(szt_output_num, 0.0);
		for (size_t i = 0; i < szt_output_num; ++i) 
		{
			vec_ret[i] = ema_t(vec_input, i);
		}
		return vec_ret;
	};
}
 
/**
 * @brief  dif值是N_near时间区间的ema值减去N_far时间区间内的值,dif值表示的是增长值,可以看做是收盘价的增长速度
 * @note   
 * @retval 
 */
template
std::function(const typename std::vector&)> dif_gen() 
{
	return [](const std::vector& vec_input) 
	{
		auto ema_near = ema_gen();
		auto ema_far = ema_gen();
		std::vector vec_near = ema_near(vec_input);
		std::vector vec_far = ema_far(vec_input);
		size_t szt_short = vec_near.size() < vec_far.size() ? vec_near.size() : vec_far.size();
		std::vector vec_out(szt_short, 0.0);
		for (size_t i = 0; i < szt_short; i++) 
		{
			vec_out[i] = vec_near[i] - vec_far[i];
		}
		return vec_out;
	};
}
 
 /**
  * @brief  dea是dif的惯性加权值,惯性加权范围是DEA_N,可以看做是dif的平滑值,即收盘价增长速度的平滑值
  * @note   
  * @retval 
 */
template
std::function(const typename std::vector&)> dea_gen() 
{
	return [](const std::vector& vec_input)
	{
		auto dif = dif_gen();
		auto vec_dif = dif(vec_input);
		auto ema = ema_gen();
		auto vec_ema = ema(vec_dif);
		return vec_ema;
	};
}
 
 /**
  * @brief  macd是dif观测值和dea(dif平滑值)之间的差距,可以看做是dif的变化速度,而dif是收盘价的变化速度平滑值,所以macd是收盘价格变化速度的变化速度,即可以理解成macd是收盘价格的加速度
  * @note   
  * @param  std::vector&: 
  * @retval 
 */
template
std::function(const typename std::vector&)> macd_gen() 
{
	return [](const std::vector& vec_input) 
	{
		auto dif = dif_gen();			// 此处可以加速,但是为了说明算法,此处不予加速
		auto vec_dif = dif(vec_input);
		auto dea = dea_gen();
		auto vec_dea = dea(vec_input);
		size_t szt_short = vec_dea.size() < vec_dif.size() ? vec_dea.size() : vec_dif.size();
		std::vector vec_out(szt_short, 0.0);
		for (size_t i = 0; i < szt_short; i++)
		{
			vec_out[i] = 2. * (vec_dif[i] - vec_dea[i]);
		}
		return vec_out;
	};
}
 
 
 
#include 
int main() 
{
	/* 测试数据产生,模拟一个以恒定速度增长的价格 */
	std::vector vec;
	vec.resize(50, 0.0);
	std::generate(vec.begin(), vec.end(), []() 
	{
		static double d = 10.1234;
		return d += 1.0;
	});
	std::reverse(vec.begin(), vec.end());			// * 数据是反向的,第一个是最近的数据
 
    printf("origin:\n");
    for(auto v: vec)
    {
        printf("%.4lf ", v);
    }
    printf("\n");
 
	auto ema16 = ema_gen<16, double>();					// 16日的ema
	auto vec_out = ema16(vec);
    printf("ema16:\n");
    for(auto v: vec_out)
    {
        printf("%.4lf ", v);
    }
    printf("\n");
 
	auto dif = dif_gen<12, 26, double>();				// 近12日对比近26日的dif
	auto vec_dif_out = dif(vec);
    printf("dif:\n");
    for(auto v: vec_dif_out)
    {
        printf("%.4lf ", v);
    }
    printf("\n");
 
	auto dea = dea_gen<12, 26, 9, double>();			// 9个dif的dea
	auto vec_dea_out = dea(vec);
    printf("dea:\n");
    for(auto v: vec_dea_out)
    {
        printf("%.4lf ", v);
    }
    printf("\n");
 
	auto macd = macd_gen<12, 26, 9, double>();			// 当日的macd值,表征变化趋势的正负向变化
	auto vec_macd = macd(vec);
    printf("macd:\n");
    for(auto v: vec_macd)
    {
        printf("%.4lf ", v);
    }
    printf("\n");
	return 0;
}

结果分析

运行结果如下:

与我们分析的一样,由于是恒定速度增长的,所以macd的值是0(价格增长的加速度为0);dif和dea都是固定的值(恒定速度增长,即速度固定)。 

你可能感兴趣的:(金融知识,c++,金融)