自定义指标-挤压指标
指标原理
挤压指标由布林带(Bollinger Bands)和肯特纳通道(Keltner Channel,又称ATR通道)结合而成,用于寻找价格突破点。
- 布林带(白色粗线):由中线(移动平均线)、上轨和下轨组成,反映价格波动范围。
- 肯特纳通道(虚线):基于真实波动幅度(ATR)计算,反映价格波动的通道范围。
挤压状态:当布林带的上轨和下轨完全进入肯特纳通道内时,市场处于水平震荡,无明确方向;当价格突破时,布林带扩张并脱离肯特纳通道,此时是潜在的突破交易时机。
代码实现
cpp
#property indicator_chart_window
#property indicator_buffers 11
#property indicator_plots 6
#property indicator_label1 "挤压指标"
#property indicator_type1 DRAW_FILLING
#property indicator_color1 Gold
#property indicator_label2 "布林上轨"
#property indicator_type2 DRAW_COLOR_LINE
#property indicator_color2 clrGainsboro, clrLightGreen
#property indicator_width2 3
#property indicator_label3 "肯特纳通道上轨"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrSilver
#property indicator_style3 STYLE_DOT
#property indicator_label4 "布林和肯特纳通道中轨"
#property indicator_type4 DRAW_COLOR_LINE
#property indicator_color4 clrGreen, clrRed
#property indicator_width4 2
#property indicator_label5 "肯特纳通道下轨"
#property indicator_type5 DRAW_LINE
#property indicator_color5 clrSilver
#property indicator_style5 STYLE_DOT
#property indicator_label6 "布林下轨"
#property indicator_type6 DRAW_COLOR_LINE
#property indicator_color6 clrGainsboro, clrRed
#property indicator_width6 3
input int inpPeriod = 20; // 布林和肯特纳周期
input ENUM_APPLIED_PRICE inpPrice = PRICE_CLOSE; // 应用到
input double inpBbMultiplier = 2.0; // 布林标准差倍数
input double inpKcMultiplier = 1.5; // 肯特纳 系数 设置<=0 和布林相同
// 中线,中线颜色,布林上轨,布林上轨颜色,布林下轨, 布林下轨颜色, 肯特纳上轨,肯特纳下轨, 挤压区域上沿,挤压区域下沿, atr
double mid[], midc[], bbup[], bbupc[], bbdn[], bbdnc[], kelu[], keld[], sqzu[], sqzd[], atr[];
double kcMultiplier;
int bbHandle, atrHandle;
int OnInit(void)
{
SetIndexBuffer(0, sqzu, INDICATOR_DATA);
SetIndexBuffer(1, sqzd, INDICATOR_DATA);
SetIndexBuffer(2, bbup, INDICATOR_DATA);
SetIndexBuffer(3, bbupc, INDICATOR_COLOR_INDEX);
SetIndexBuffer(4, kelu, INDICATOR_DATA);
SetIndexBuffer(5, mid, INDICATOR_DATA);
SetIndexBuffer(6, midc, INDICATOR_COLOR_INDEX);
SetIndexBuffer(7, keld, INDICATOR_DATA);
SetIndexBuffer(8, bbdn, INDICATOR_DATA);
SetIndexBuffer(9, bbdnc, INDICATOR_COLOR_INDEX);
SetIndexBuffer(10, atr, INDICATOR_CALCULATIONS);
kcMultiplier = (inpKcMultiplier <= 0) ? inpBbMultiplier : inpKcMultiplier;
bbHandle = iBands(_Symbol, 0, inpPeriod, 0, inpBbMultiplier, inpPrice);
atrHandle = iATR(_Symbol, 0, inpPeriod);
// 主窗口只有鼠标悬停在指标上才能显示
IndicatorSetString(INDICATOR_SHORTNAME, "布林带挤压(" + (string)inpPeriod + "," + (string)inpBbMultiplier + "," + (string)inpKcMultiplier + ")");
return (INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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 < inpPeriod)
return 0;
// 检查需要的相关指标是否已经准备好,没准备好就返回上一次计算的结果
if(BarsCalculated(bbHandle) < rates_total || BarsCalculated(atrHandle) < rates_total){
Print("bbHandle 或 atrHandle 数据没有全部计算");
return (prev_calculated);
}
// 计算需要复制的柱数 +1 是确保至少要复制一个数据 MathMin防止数组越界
int copyCount =MathMin(rates_total- prev_calculated + 1, rates_total);
// 复制指标数据
if(CopyBuffer(bbHandle,BASE_LINE,0,copyCount,mid)!=copyCount) return (prev_calculated);
if(CopyBuffer(bbHandle,LOWER_BAND,0,copyCount,bbdn)!=copyCount) return (prev_calculated);
if(CopyBuffer(bbHandle,UPPER_BAND,0,copyCount,bbup)!=copyCount) return (prev_calculated);
if(CopyBuffer(atrHandle,BASE_LINE,0,copyCount,atr)!=copyCount) return (prev_calculated);
// 初始化循环变量i 确保从上一次计算结束的位置开始计算 i写在外面是因为最终要返回出去
int i = (int) MathMax(prev_calculated-1,0);
// 循环计算肯特纳通道的上轨和下轨, 判断是否发生挤压
for(; i < rates_total&& !_StopFlag; i++){
keld[i] = mid[i] -atr[i] * kcMultiplier;
kelu[i] = mid[i] +atr[i] * kcMultiplier;
bool squeeze = (kelu[i] > bbup[i]);
sqzu[i] = (squeeze)?bbup[i] :mid[i];
sqzd[i] = (squeeze)?bbdn[i] :mid[i];
bbupc[i] = (squeeze)?1 :0;
bbdnc[i] = (squeeze)?1 :0;
midc[i] = (squeeze)?1 :0;
}
// 为什么是返回i而不是prev_calculated 或者 rates_total
return (i);
}
//+------------------------------------------------------------------+