目录
意义解释
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表示的是价格的变化加速度)。
以下为这几个参数的数学表示(截图自百度):
MACD的延后性
前面说了MACD是收盘价格变化的“加速度”,但是这个加速度是有延后性的。我们从源头开始梳理一下,MACD由DIF和DEA的差值决定,DEF是DIF的惯性平滑值,DIF是EMA不同时间区间的差值,而EMA是收盘价格的惯性平滑值。重点在于这个“惯性平滑”,惯性平滑是使用之前的值加权到当天收盘价格上来表现的,因此这个值不会是今天的值,而必然是受之前时间区间内的值影响。试验过卡尔曼滤波的人应该知道,卡尔曼滤波在匀速运动时候是比较准确的,但是当其遇到大机动情况就会出现惯性偏移。从感性上可以这么理解,EMA是延后的,从而依赖于EMA的MACD在收盘价格运动模型出现变化的时候就会出现一点点的偏移,但是这个偏移会在较短时间内再次被消弭。经过观测现实数据,发现确实会存在这种情况,如下图:
观察蓝框中的价格变化以及下方的MACD。可以发现价格由涨变跌,加速度直观上来讲是负值,但是下方的MACD显示当天的加速度是正的,直到2天后才变成负值。由此可见在这个区间内MACD的延时应该为2-4天。
程序实现
为了便于理解,于此给出C++模板函数编程式编程的实现,以加深理解。
#include <vector>
#include <functional>
#include <exception>
/**
* @brief ema_t用于计算传入数组的惯性加权和
* @note N为总体数目,N_Left是剩余要加权的数目
* @param vec_input: 用于计算的数组
* @param N_Start: 当前加权开始位置
* @retval 当前加权值加上其后值的加权值
*/
template<int N, int N_Left, typename val_t>
inline val_t ema_t(const typename std::vector<val_t>& 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<N, N_Left - 1, val_t>(vec_input, N_Start + 1) * (N - 1) ) / (N + 1.);
}
}
template<int N, typename val_t>
std::function<typename std::vector<val_t>(const typename std::vector<val_t>&)> ema_gen()
{
return [](const std::vector<val_t>& vec_input)
{
size_t szt_output_num = vec_input.size() - N + 1;
std::vector<val_t> vec_ret(szt_output_num, 0.0);
for (size_t i = 0; i < szt_output_num; ++i)
{
vec_ret[i] = ema_t<N, N, val_t>(vec_input, i);
}
return vec_ret;
};
}
/**
* @brief dif值是N_near时间区间的ema值减去N_far时间区间内的值,dif值表示的是增长值,可以看做是收盘价的增长速度
* @note
* @retval
*/
template<int N_near, int N_far, typename val_t>
std::function<typename std::vector<val_t>(const typename std::vector<val_t>&)> dif_gen()
{
return [](const std::vector<val_t>& vec_input)
{
auto ema_near = ema_gen<N_near, val_t>();
auto ema_far = ema_gen<N_far, val_t>();
std::vector<val_t> vec_near = ema_near(vec_input);
std::vector<val_t> vec_far = ema_far(vec_input);
size_t szt_short = vec_near.size() < vec_far.size() ? vec_near.size() : vec_far.size();
std::vector<val_t> 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<int DIF_near, int DIF_far, int DEA_N, typename val_t>
std::function<typename std::vector<val_t>(const typename std::vector<val_t>&)> dea_gen()
{
return [](const std::vector<val_t>& vec_input)
{
auto dif = dif_gen<DIF_near, DIF_far, val_t>();
auto vec_dif = dif(vec_input);
auto ema = ema_gen<DEA_N, double>();
auto vec_ema = ema(vec_dif);
return vec_ema;
};
}
/**
* @brief macd是dif观测值和dea(dif平滑值)之间的差距,可以看做是dif的变化速度,而dif是收盘价的变化速度平滑值,所以macd是收盘价格变化速度的变化速度,即可以理解成macd是收盘价格的加速度
* @note
* @param std::vector<val_t>&:
* @retval
*/
template<int DIF_near, int DIF_far, int DEA_N, typename val_t>
std::function<typename std::vector<val_t>(const typename std::vector<val_t>&)> macd_gen()
{
return [](const std::vector<val_t>& vec_input)
{
auto dif = dif_gen<DIF_near, DIF_far, val_t>(); // 此处可以加速,但是为了说明算法,此处不予加速
auto vec_dif = dif(vec_input);
auto dea = dea_gen<DIF_near, DIF_far, DEA_N, val_t>();
auto vec_dea = dea(vec_input);
size_t szt_short = vec_dea.size() < vec_dif.size() ? vec_dea.size() : vec_dif.size();
std::vector<val_t> 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 <algorithm>
int main()
{
/* 测试数据产生,模拟一个以恒定速度增长的价格 */
std::vector<double> 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都是固定的值(恒定速度增长,即速度固定)。