这是系列教学的最后一篇文章,不知大家学会了多少,想进一步交流的加学长的微信:u31u31。
下面是课程中的自定义指标源代码:
#property copyright "版权归“图道交易”学长所有"
#property indicator_chart_window
#property indicator_buffers 3 // 定义3个“画图”缓冲区,分别用于:中轨、上轨、下轨
#property indicator_color1 DeepSkyBlue
#property indicator_color2 DeepSkyBlue
#property indicator_color3 DeepSkyBlue
// ===== 可调参数,交易员的“武器库” =====
extern int BandsPeriod = 20; // 均线和标准差的计算周期
extern int BandsShift = 0; // 指标整体水平位移
extern int BandsMethod = MODE_EMA; // 均线类型,EMA对新价格更敏感,SMA则更平滑
extern int BandsPrice = PRICE_CLOSE; // 价格类型,收盘价是大部分策略的基石
extern double Deviations = 2.0; // 标准差倍数,决定通道宽度,是捕捉“机会”与“风险”的关键
/* ===== 指标数据缓冲区 =====
* 这里是我们存放计算结果的“仓库”,MT4会根据这些数组来绘制指标线。
*/
double EMA[];
double UpperBand[];
double LowerBand[];
//+------------------------------------------------------------------+
//| 指标初始化函数,程序加载时只运行一次,好比开工前的准备工作。 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 关联缓冲区并设置显示标签
SetIndexBuffer(0, EMA);
SetIndexLabel(0, "EMA (" + BandsPeriod + ")");
SetIndexBuffer(1, UpperBand);
SetIndexLabel(1, "Upper Band (" + DoubleToStr(Deviations, 1) + ")");
SetIndexBuffer(2, LowerBand);
SetIndexLabel(2, "Lower Band (" + DoubleToStr(Deviations, 1) + ")");
//--- 统一设置线型
SetIndexStyle(0, DRAW_LINE);
SetIndexStyle(1, DRAW_LINE);
SetIndexStyle(2, DRAW_LINE);
//--- 处理指标的水平位移,让指标快人一步或慢人一拍,有时能发现不同周期共振的秘密
if(BandsShift != 0)
{
SetIndexShift(0, BandsShift);
SetIndexShift(1, BandsShift);
SetIndexShift(2, BandsShift);
}
//--- 给指标起个“小名”,显示在图表左上角,一目了然
IndicatorShortName("EMA Bands (" + BandsPeriod + "," + DoubleToStr(Deviations, 1) + ")");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 指标被移除时执行,可以做一些清理工作。 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// 通常我们在这里释放一些资源,不过这个指标比较简单,暂时留空。
}
//+------------------------------------------------------------------+
//| 核心计算函数,每个报价(tick)来临时都会被调用,性能是关键! |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//--- 数据量不够,连一个周期都算不出来,直接“罢工”返回,避免后续计算出错
if(rates_total < BandsPeriod)
return(0);
/* --- MT4的优化核心:只计算新K线,避免重复劳动 ---
* 首次加载(prev_calculated == 0),需要从头算到尾。
* 后续有了新K线,只用计算增量部分(rates_total - prev_calculated)即可。
* 这是编写高效指标和EA的必会技巧,新手最容易忽略这点导致程序卡顿。
*/
int start_pos;
if(prev_calculated == 0)
start_pos = rates_total - 1;
else
start_pos = rates_total - prev_calculated;
//--- 从最新的K线开始,倒着计算,直到完成所有需要计算的K线
for(int i = start_pos; i >= 0; i--)
{
EMA[i] = iMA(NULL, 0, BandsPeriod, 0, BandsMethod, BandsPrice, i);
double StdDev = iStdDev(NULL, 0, BandsPeriod, 0, BandsMethod, BandsPrice, i);
UpperBand[i] = EMA[i] + (StdDev * Deviations);
LowerBand[i] = EMA[i] - (StdDev * Deviations);
}
return(rates_total);
}