#property description "The indicator displays larger time frame's candlesticks on the current one."
//--- 指标设置
#property indicator_chart_window
#property indicator_buffers 16
#property indicator_plots 8
//---- 图 1
#property indicator_label1 "BearBody"
#property indicator_color1 clrSeaGreen,clrSeaGreen
//---- 图 2
#property indicator_label2 "BearBodyEnd"
#property indicator_color2 clrSeaGreen,clrSeaGreen
//---- 图 3
#property indicator_label3 "BearShadow"
#property indicator_color3 clrSalmon,clrSalmon
//---- 图 4
#property indicator_label4 "BearShadowEnd"
#property indicator_color4 clrSalmon,clrSalmon
//---- 图 5
#property indicator_label5 "BullBody"
#property indicator_color5 clrOlive,clrOlive
//---- 图 6
#property indicator_label6 "BullBodyEnd"
#property indicator_color6 clrOlive,clrOlive
//---- 图 7
#property indicator_label7 "BullShadow"
#property indicator_color7 clrSkyBlue,clrSkyBlue
//---- 图 8
#property indicator_label8 "BullShadowEnd"
#property indicator_color8 clrSkyBlue,clrSkyBlue
//--- 预定义常量
#define INDICATOR_EMPTY_VALUE 0.0
//--- 输入参数
input ENUM_TIMEFRAMES InpPeriod=PERIOD_H4; // 指标计算的时间范围
input datetime InpDateStart=D'2013.01.01 00:00'; // 分析起始日期
//--- 熊市蜡烛图的指标缓冲区
double ExtBearBodyFirst[];
double ExtBearBodySecond[];
double ExtBearBodyEndFirst[];
double ExtBearBodyEndSecond[];
double ExtBearShadowFirst[];
double ExtBearShadowSecond[];
double ExtBearShadowEndFirst[];
double ExtBearShadowEndSecond[];
//--- 牛市蜡烛图的指标缓冲区
double ExtBullBodyFirst[];
double ExtBullBodySecond[];
double ExtBullBodyEndFirst[];
double ExtBullBodyEndSecond[];
double ExtBullShadowFirst[];
double ExtBullShadowSecond[];
double ExtBullShadowEndFirst[];
double ExtBullShadowEndSecond[];
//--- 全局变量
datetime ExtTimeBuff[]; // 较大时间帧的时间缓冲区
int ExtSize=0; // 时间缓冲区大小
int ExtCount=0; // 时间缓冲区的标引
int ExtStartPos=0; // 指标计算的初始位置
bool ExtStartFlag=true; // 接收初始位置的辅助标识
datetime ExtCurrentTime[1]; // 生成较大时间帧柱形的最近时间
datetime ExtLastTime; // 较大时间帧的最近时间,执行计算
bool ExtBearFlag=true; // 标记定义编写数据订单熊市指标缓冲区
bool ExtBullFlag=true; // 标记定义编写数据订单牛市指标缓冲区
int ExtIndexMax=0; // 数组中最大元素标引
int ExtIndexMin=0; // 数组中最小元素标引
int ExtDirectionFlag=0; // 当前蜡烛图的价格移动方向
//--- 正确绘制蜡烛图开盘价和收盘价之间的转换
const double ExtEmptyBodySize=0.2*SymbolInfoDouble(Symbol(),SYMBOL_POINT);
//+------------------------------------------------------------------+
//| 填写蜡烛图的基本部分 |
//+------------------------------------------------------------------+
void FillCandleMain(const double &open[],const double &close[],
const double &high[],const double &low[],
const int start,const int last,const int fill_index,
int &index_max,int &index_min)
{
//--- 在数组中找出最大和最小元素的标引
index_max=ArrayMaximum(high,ExtStartPos,last-start+1); // 最高极值
index_min=ArrayMinimum(low,ExtStartPos,last-start+1); // 最低极值
//--- 定义当前时间帧填充多少柱
int count=fill_index-start+1;
//--- 如果首柱的收盘价超过最后的柱,那么蜡烛图为熊市
if(open[start]>close[last])
{
//--- 如果蜡烛图之前牛市,清空牛市指标缓冲区的值
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- 熊市蜡烛图
ExtDirectionFlag=-1;
//--- 生成蜡烛图
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
close[last],high[index_max],low[index_min],start,count,ExtBearFlag);
//--- 退出函数
return;
}
//--- 如果首柱的收盘价少于最后的柱,那么蜡烛图为牛市
if(open[start]<close[last])
{
//--- 如果蜡烛图之前为熊市,清空熊市指标缓冲区的值
if(ExtDirectionFlag!=1)
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,start,count);
//--- 牛市蜡烛图
ExtDirectionFlag=1;
//--- 生成蜡烛图
FormCandleMain(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,close[last],
open[start],high[index_max],low[index_min],start,count,ExtBullFlag);
//--- 退出函数
return;
}
//--- 如果您在这部分函数,首柱开盘价等于
//--- 最后柱的收盘价;这种蜡烛图被认为熊市图
//--- 如果在那之前蜡烛图为牛市,清空牛市指标缓冲区的值
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- 熊市蜡烛图
ExtDirectionFlag=-1;
//--- 如果收盘和开盘价相同,使用切换来正确显示
if(high[index_max]!=low[index_min])
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],low[index_min],start,count,ExtBearFlag);
else
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,
open[start],open[start]-ExtEmptyBodySize,high[index_max],
high[index_max]-ExtEmptyBodySize,start,count,ExtBearFlag);
}
//+------------------------------------------------------------------+
//| 填充蜡烛图末端 |
//+------------------------------------------------------------------+
void FillCandleEnd(const double &open[],const double &close[],
const double &high[],const double &low[],
const int start,const int last,const int fill_index,
const int index_max,const int index_min)
{
//--- 单柱时不要绘制
if(last-start==0)
return;
//--- 如果首柱的收盘价超过最后的柱,蜡烛图为熊市
if(open[start]>close[last])
{
//--- 生成蜡烛图末端
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,
open[start],close[last],high[index_max],low[index_min],fill_index,ExtBearFlag);
//--- 退出函数
return;
}
//--- 如果首柱的收盘价小于最后的柱,蜡烛图为牛市
if(open[start]<close[last])
{
//--- 生成蜡烛图末端
FormCandleEnd(ExtBullBodyEndFirst,ExtBullBodyEndSecond,ExtBullShadowEndFirst,ExtBullShadowEndSecond,
close[last],open[start],high[index_max],low[index_min],fill_index,ExtBullFlag);
//--- 退出函数
return;
}
//--- 如果您在这部分函数,首柱开盘价等于
//--- 最后柱的收盘价;这种蜡烛图被认为熊市图
//--- 生成蜡烛图末端
if(high[index_max]!=low[index_min])
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],low[index_min],fill_index,ExtBearFlag);
else
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],high[index_max]-ExtEmptyBodySize,fill_index,ExtBearFlag);
}
//+------------------------------------------------------------------+
//| 自定义指标初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 检查指标周期
if(!CheckPeriod((int)Period(),(int)InpPeriod))
return(INIT_PARAMETERS_INCORRECT);
//--- 在前景显示价格数据
ChartSetInteger(0,CHART_FOREGROUND,0,1);
//--- 绑定指标缓冲区
SetIndexBuffer(0,ExtBearBodyFirst);
SetIndexBuffer(1,ExtBearBodySecond);
SetIndexBuffer(2,ExtBearBodyEndFirst);
SetIndexBuffer(3,ExtBearBodyEndSecond);
SetIndexBuffer(4,ExtBearShadowFirst);
SetIndexBuffer(5,ExtBearShadowSecond);
SetIndexBuffer(6,ExtBearShadowEndFirst);
SetIndexBuffer(7,ExtBearShadowEndSecond);
SetIndexBuffer(8,ExtBullBodyFirst);
SetIndexBuffer(9,ExtBullBodySecond);
SetIndexBuffer(10,ExtBullBodyEndFirst);
SetIndexBuffer(11,ExtBullBodyEndSecond);
SetIndexBuffer(12,ExtBullShadowFirst);
SetIndexBuffer(13,ExtBullShadowSecond);
SetIndexBuffer(14,ExtBullShadowEndFirst);
SetIndexBuffer(15,ExtBullShadowEndSecond);
//--- 设置一些属性值来创建指标
for(int i=0;i<8;i++)
{
PlotIndexSetInteger(i,PLOT_DRAW_TYPE,DRAW_FILLING); // 图形结构类型
PlotIndexSetInteger(i,PLOT_LINE_STYLE,STYLE_SOLID); // 绘制线型风格
PlotIndexSetInteger(i,PLOT_LINE_WIDTH,1); // 绘制线型宽度
}
//---
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(prev_calculated==0)
{
//--- 接收较大时间帧柱形的到达时间
if(!GetTimeData())
return(0);
}
//--- 设置直接索引
ArraySetAsSeries(time,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(open,false);
ArraySetAsSeries(close,false);
//--- 启动计算柱形的变量
int start=prev_calculated;
//--- 如果生成柱形,重新计算上面的指标值
if(start!=0 && start==rates_total)
start--;
//--- 循环计算指标值
for(int i=start;i<rates_total;i++)
{
//--- 用空值填充指标缓冲区的i元素
FillIndicatorBuffers(i);
//--- 从InpDateStart日期开始计算柱形
if(time[i]>=InpDateStart)
{
//--- 定义值第一时间显示的持仓
if(ExtStartFlag)
{
//--- 存储最初柱形的数量
ExtStartPos=i;
//--- 定义超过time[i]的较大时间帧的初始日期
while(time[i]>=ExtTimeBuff[ExtCount])
if(ExtCount<ExtSize-1)
ExtCount++;
//--- 改变标识值以便不在这模块再次运行
ExtStartFlag=false;
}
//--- 检查数组中是否有任何元素
if(ExtCount<ExtSize)
{
//--- 等候当前时间帧的值到达较大时间帧的值
if(time[i]>=ExtTimeBuff[ExtCount])
{
//--- 绘制蜡烛图的主要部分(不填写最后和倒数第二柱之间的区域)
FillCandleMain(open,close,high,low,ExtStartPos,i-1,i-2,ExtIndexMax,ExtIndexMin);
//--- 填充蜡烛图末端(最后和倒数第二柱之间的区域)
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- 切换初始持仓以绘制下一个蜡烛图
ExtStartPos=i;
//--- 增加数组计数器
ExtCount++;
}
else
continue;
}
else
{
//--- 重置数组的值
ResetLastError();
//--- 接收来自较大时间帧的最后日期
if(CopyTime(Symbol(),InpPeriod,0,1,ExtCurrentTime)==-1)
{
Print("Data copy error, code = ",GetLastError());
return(0);
}
//--- 如果新日期靠后,停止生成蜡烛图
if(ExtCurrentTime[0]>ExtLastTime)
{
//--- 在主要指标缓冲区清空最后和倒数第二柱之间的区域
ClearEndOfBodyMain(i-1);
//--- 使用辅助指标缓冲区填充该区域
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- 切换初始持仓以绘制下一个蜡烛图
ExtStartPos=i;
//--- 重置价格方向标识
ExtDirectionFlag=0;
//--- 存储新的最近日期
ExtLastTime=ExtCurrentTime[0];
}
else
{
//--- 生成蜡烛图
FillCandleMain(open,close,high,low,ExtStartPos,i,i,ExtIndexMax,ExtIndexMin);
}
}
}
}
//--- 返回prev_calculated值以便下次调用
return(rates_total);
}
//+------------------------------------------------------------------+
//| 检查指定指标周期的正确性 |
//+------------------------------------------------------------------+
bool CheckPeriod(int current_period,int high_period)
{
//--- 指标周期应该超过显示它的时间帧
if(current_period>=high_period)
{
Print("Error! The value of the indicator period should exceed the value of the current time frame!");
return(false);
}
//--- 如果指标周期是周或月份,周期则是正确的
if(high_period>32768)
return(true);
//--- 转变周期值到分钟
if(high_period>30)
high_period=(high_period-16384)*60;
if(current_period>30)
current_period=(current_period-16384)*60;
//--- 指标周期应该是它显示的时间帧的几倍
if(high_period%current_period!=0)
{
Print("Error! The value of the indicator period should be multiple of the value of the current time frame!");
return(false);
}
//--- 指标周期应该超过它显示的时间帧的3或更多倍
if(high_period/current_period<3)
{
Print("Error! The indicator period should exceed the current time frame 3 or more times!");
return(false);
}
//--- 指标周期在当前时间帧是正确的
return(true);
}
//+------------------------------------------------------------------+
//| 接收来自较大时间帧的时间数据 |
//+------------------------------------------------------------------+
bool GetTimeData(void)
{
//--- 重置错误的值
ResetLastError();
//--- 复制当前时间的所有数据
if(CopyTime(Symbol(),InpPeriod,InpDateStart,TimeCurrent(),ExtTimeBuff)==-1)
{
//--- 接收错误代码
int code=GetLastError();
//--- 打印错误信息
PrintFormat("Data copy error! %s",code==4401
? "History is still being uploaded!"
: "Code = "+IntegerToString(code));
//--- 返回false,反复尝试下载数据
return(false);
}
//--- 接收数组大小
ExtSize=ArraySize(ExtTimeBuff);
//--- 为数组设置循环指数为零
ExtCount=0;
//--- 在时间帧设置当前蜡烛图持仓为零
ExtStartPos=0;
ExtStartFlag=true;
//--- 存储来自较大时间帧的最近时间值
ExtLastTime=ExtTimeBuff[ExtSize-1];
//--- 成功执行
return(true);
}
//+--------------------------------------------------------------------------+
//| 函数形成了蜡烛图的主要部分。根据标识的 |
//| 值,函数定义了要使用哪个数据和数组 |
//| 以便正确显示 |
//+--------------------------------------------------------------------------+
void FormCandleMain(double &body_fst[],double &body_snd[],
double &shadow_fst[],double &shadow_snd[],
const double fst_value,const double snd_value,
const double fst_extremum,const double snd_extremum,
const int start,const int count,const bool flag)
{
//--- 检查标识的值
if(flag)
{
//--- 生成蜡烛图主体
FormMain(body_fst,body_snd,fst_value,snd_value,start,count);
//--- 生成蜡烛图影子
FormMain(shadow_fst,shadow_snd,fst_extremum,snd_extremum,start,count);
}
else
{
//--- 生成蜡烛图主体
FormMain(body_fst,body_snd,snd_value,fst_value,start,count);
//--- 生成蜡烛图影子
FormMain(shadow_fst,shadow_snd,snd_extremum,fst_extremum,start,count);
}
}
//+-------------------------------------------------------------------------------+
//| 函数形成了蜡烛图的末端。根据标识的值, |
//| 函数定义了要使用哪个数据和数组 |
//| 以便正确显示。 |
//+-------------------------------------------------------------------------------+
void FormCandleEnd(double &body_fst[],double &body_snd[],
double &shadow_fst[],double &shadow_snd[],
const double fst_value,const double snd_value,
const double fst_extremum,const double snd_extremum,
const int end,bool &flag)
{
//--- 检查标识的值
if(flag)
{
//--- 生成蜡烛图主体的末端
FormEnd(body_fst,body_snd,fst_value,snd_value,end);
//--- 生成蜡烛图影子的末端
FormEnd(shadow_fst,shadow_snd,fst_extremum,snd_extremum,end);
//--- 改变标识值到相反方向
flag=false;
}
else
{
//--- 生成蜡烛图主体的末端
FormEnd(body_fst,body_snd,snd_value,fst_value,end);
//--- 生成蜡烛图影子的末端
FormEnd(shadow_fst,shadow_snd,snd_extremum,fst_extremum,end);
//--- 改变标识值到相反方向
flag=true;
}
}
//+---------------------------------------------------------------------------------+
//| 清空蜡烛图末端(最后和倒数第二柱之间的区域) |
//| |
//+---------------------------------------------------------------------------------+
void ClearEndOfBodyMain(const int ind)
{
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,ind,1);
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,ind,1);
}
//+--------------------------------------------------------------------------+
//| 清空蜡烛图 |
//+--------------------------------------------------------------------------+
void ClearCandle(double &body_fst[],double &body_snd[],double &shadow_fst[],
double &shadow_snd[],const int start,const int count)
{
//--- 检查
if(count!=0)
{
//--- 以空值填充指标缓冲区
ArrayFill(body_fst,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(body_snd,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(shadow_fst,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(shadow_snd,start,count,INDICATOR_EMPTY_VALUE);
}
}
//+--------------------------------------------------------------------------+
//| 生成蜡烛图的主要部分 |
//+--------------------------------------------------------------------------+
void FormMain(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int start,const int count)
{
//--- 检查
if(count!=0)
{
//--- 用值填充指标缓冲区
ArrayFill(fst,start,count,fst_value);
ArrayFill(snd,start,count,snd_value);
}
}
//+-----------------------------------------------------------------------------+
//| 生成蜡烛图末端 |
//+-----------------------------------------------------------------------------+
void FormEnd(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int last)
{
//--- 用值填充指标缓冲区
ArrayFill(fst,last-1,2,fst_value);
ArrayFill(snd,last-1,2,snd_value);
}
//+------------------------------------------------------------------+
//| 通过空值填充指标缓冲区的i元素 |
//+------------------------------------------------------------------+
void FillIndicatorBuffers(const int i)
{
//--- 在指标缓冲区单元设置空值
ExtBearBodyFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodySecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodyEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodyEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodySecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowEndSecond[i]=INDICATOR_EMPTY_VALUE;
}
|