如何使用 CopyRates() 在多个时间范围内搜索和过滤看涨吞没形态
How to use CopyRates() to search and filter through several timeframes for Bullish Engulfing pattern
我正在尝试使用 CopyRates()
在多个时间框架(所有时间框架 H2
到 M10
上搜索看涨吞没烛台模式(看跌蜡烛后跟更大的看涨蜡烛)在收盘后的 H4
看涨蜡烛内)。我阅读了 CopyRates()
的定义,但发现实施起来有点困难。这里的想法来自我想要过滤具有最大看跌与看涨蜡烛对比率的模式的模式。在下面查看我到目前为止所做的工作:
在OnTick()
中:
for (int i=ArraySize(timeframes); i>=1; i--) {
if(CopyRates(Symbol(), timeframes[i - 1], 1, MyPeriod, rates)!=MyPeriod) {
Print("Error CopyRates errcode = ",GetLastError());
return;
}
// Using bullish engulfing pattern:
if ((rates[numCandle].open < rates[numCandle].close) &&
(rates[numCandle + 1].open > rates[numCandle + 1].close) &&
(rates[numCandle + 1].open < rates[numCandle].close) &&
(rates[numCandle + 1].close > rates[numCandle].open)) {
// Not too certain what should be done here
}
}
这是另一个相关代码:
input int numCandle=0;
MqlRates rates[];
ENUM_TIMEFRAMES timeframes[7] = {PERIOD_H2, PERIOD_H1, PERIOD_M30, PERIOD_M20, PERIOD_M15, PERIOD_M12, PERIOD_M10};
void OnInit() {
ArraySetAsSeries(rates, true);
}
已更新
以下是看涨吞没形态的定义:
如上图所示的看涨吞没形态是一根看跌蜡烛,然后是一根看涨蜡烛。看跌蜡烛的开盘价低于看涨蜡烛的收盘价,看跌蜡烛的收盘价高于看涨蜡烛的开盘价。请注意,在某些情况下,看跌蜡烛的收盘价仅略高于看涨蜡烛的开盘价。每根蜡烛的主体尺寸都大于上下灯芯的总和。
假设 MyPeriod 初始化为 2,其余代码似乎是正确的。您应该创建一个变量来保持具有最大比率的时间范围。在您的 if
中,您必须计算 candle+1
和 candle
的烛台主体尺寸并计算比率,然后如果计算的比率大于之前计算的比率,则更改值并更新您找到它的时间范围。
在 for
循环结束时,您可以决定要在哪个时间范围内下订单。
ENUM_TIMEFRAMES timeframes[7] = {PERIOD_H2, PERIOD_H1, PERIOD_M30, PERIOD_M20, PERIOD_M15, PERIOD_M12, PERIOD_M10};
//ENUM_TIMEFRAMES timeframes[4] = {PERIOD_H1, PERIOD_M30, PERIOD_M15, PERIOD_M5};
//---
const int LONG=1, SHORT=-1, NO_DIR=0;
const ENUM_TIMEFRAMES timeframeHighest = PERIOD_H4;
string bestRatioObjectName="bestBullish2BearishPattern!";
datetime lastCandleTime=0;
void OnTick()
{
if(!isNewBar(PERIOD_H4))
return;
//most likely you will call this block after new bar check?
MqlRates rates[];
ArraySetAsSeries(rates,true);
if(CopyRates(_Symbol,timeframeHighest,0,2,rates)==-1)
{
printf("%i %s: failed to load/copy rates on %d. error=%d",__LINE__,__FILE__,PeriodSeconds(timeframeHighest)/60,_LastError);
return;
}
if(getCandleDir(rates[1])!=LONG)
return;
const datetime timeStart=rates[1].time, timeEnd=rates[0].time; //within a bullish H4 candle - DONE
double bestRatio = -1;//once a bearish2bullish ratio is higher, we'll move to new place
for(int i=ArraySize(timeframes)-1;i>=0;i--)
{
if(CopyRates(_Symbol,timeframes[i],timeStart,timeEnd,rates)<0)
{
printf("%i %s: failed to copy rates on %d. error=%d",__LINE__,__FILE__,PeriodSeconds(timeframeHighest)/60,_LastError);
return;
}
processRates(rates,bestRatio,bestRatioObjectName);
}
printf("%i %s: best=%.5f, objName =%s: %.5f-%.5f",__LINE__,__FILE__,bestRatio,bestRatioObjectName,
ObjectGetDouble(0,bestRatioObjectName,OBJPROP_PRICE1),ObjectGetDouble(0,bestRatioObjectName,OBJPROP_PRICE2));
//ExpertRemove();//for scripting, a one time call
}
bool isNewBar(const ENUM_TIMEFRAMES tf)
{
const datetime time=iTime(_Symbol,tf,0);
if(time>lastCandleTime)
{
lastCandleTime=time;
return true;
}
return false;
}
int getCandleDir(const MqlRates& rate) // candle direction: +1 for BULL, -1 for BEAR
{
if(rate.close-rate.open>_Point/2.)
return 1;
if(rate.open-rate.close>_Point/2.)
return-1;
return 0;
}
void processRates(const MqlRates& rates[],double &best,const string bestObjName)
{
for(int i=ArraySize(rates)-2; i>0; /* no sense to catch last candle - we cant compare it with anybody */ i--)
{
if(getCandleDir(rates[i])!=LONG)
continue;//current - bullish
if(getCandleDir(rates[i+1])!=SHORT)
continue;//prev - bearish
if(rates[i].close-rates[i+1].open>_Point/2.){}
else continue;
if(rates[i+1].close-rates[i].open>_Point/2.){}
else continue;
const double body=rates[i].close-rates[i].open, twoWicks = rates[i].high-rates[i].low- body;
if(body<twoWicks)
continue; //Each of the candles has a body size bigger than it’s upper and lower wicks combined.
//---
const double prevBody = rates[i+1].open - rates[i+1].close;
const double newRatio = body / prevBody;
if(newRatio>best) // eventually we'll find best bull2bear ratio
{
moveRectangle(rates[i+1],rates[i].time,bestObjName);
best = newRatio;
}
}
}
void moveRectangle(const MqlRates& rate,const datetime rectEnd,const string objectName)
{
if(ObjectFind(0,objectName)<0)
{
if(!ObjectCreate(0,objectName,OBJ_RECTANGLE,0,0,0,0,0))
{
printf("%i %s: failed to draw %s. error=%d",__LINE__,__FILE__,objectName,_LastError);
return;
}
//add GUI things like how to display the rectangle
}
//moving the rectangle to a new place, even for the first time
ObjectSetDouble(0,objectName,OBJPROP_PRICE,0,rate.open);
ObjectSetDouble(0,objectName,OBJPROP_PRICE,1,rate.close);
ObjectSetInteger(0,objectName,OBJPROP_TIME,0,rate.time);
ObjectSetInteger(0,objectName,OBJPROP_TIME,1,rectEnd);
}
我正在尝试使用 CopyRates()
在多个时间框架(所有时间框架 H2
到 M10
上搜索看涨吞没烛台模式(看跌蜡烛后跟更大的看涨蜡烛)在收盘后的 H4
看涨蜡烛内)。我阅读了 CopyRates()
的定义,但发现实施起来有点困难。这里的想法来自我想要过滤具有最大看跌与看涨蜡烛对比率的模式的模式。在下面查看我到目前为止所做的工作:
在OnTick()
中:
for (int i=ArraySize(timeframes); i>=1; i--) {
if(CopyRates(Symbol(), timeframes[i - 1], 1, MyPeriod, rates)!=MyPeriod) {
Print("Error CopyRates errcode = ",GetLastError());
return;
}
// Using bullish engulfing pattern:
if ((rates[numCandle].open < rates[numCandle].close) &&
(rates[numCandle + 1].open > rates[numCandle + 1].close) &&
(rates[numCandle + 1].open < rates[numCandle].close) &&
(rates[numCandle + 1].close > rates[numCandle].open)) {
// Not too certain what should be done here
}
}
这是另一个相关代码:
input int numCandle=0;
MqlRates rates[];
ENUM_TIMEFRAMES timeframes[7] = {PERIOD_H2, PERIOD_H1, PERIOD_M30, PERIOD_M20, PERIOD_M15, PERIOD_M12, PERIOD_M10};
void OnInit() {
ArraySetAsSeries(rates, true);
}
已更新
以下是看涨吞没形态的定义:
如上图所示的看涨吞没形态是一根看跌蜡烛,然后是一根看涨蜡烛。看跌蜡烛的开盘价低于看涨蜡烛的收盘价,看跌蜡烛的收盘价高于看涨蜡烛的开盘价。请注意,在某些情况下,看跌蜡烛的收盘价仅略高于看涨蜡烛的开盘价。每根蜡烛的主体尺寸都大于上下灯芯的总和。
假设 MyPeriod 初始化为 2,其余代码似乎是正确的。您应该创建一个变量来保持具有最大比率的时间范围。在您的 if
中,您必须计算 candle+1
和 candle
的烛台主体尺寸并计算比率,然后如果计算的比率大于之前计算的比率,则更改值并更新您找到它的时间范围。
在 for
循环结束时,您可以决定要在哪个时间范围内下订单。
ENUM_TIMEFRAMES timeframes[7] = {PERIOD_H2, PERIOD_H1, PERIOD_M30, PERIOD_M20, PERIOD_M15, PERIOD_M12, PERIOD_M10};
//ENUM_TIMEFRAMES timeframes[4] = {PERIOD_H1, PERIOD_M30, PERIOD_M15, PERIOD_M5};
//---
const int LONG=1, SHORT=-1, NO_DIR=0;
const ENUM_TIMEFRAMES timeframeHighest = PERIOD_H4;
string bestRatioObjectName="bestBullish2BearishPattern!";
datetime lastCandleTime=0;
void OnTick()
{
if(!isNewBar(PERIOD_H4))
return;
//most likely you will call this block after new bar check?
MqlRates rates[];
ArraySetAsSeries(rates,true);
if(CopyRates(_Symbol,timeframeHighest,0,2,rates)==-1)
{
printf("%i %s: failed to load/copy rates on %d. error=%d",__LINE__,__FILE__,PeriodSeconds(timeframeHighest)/60,_LastError);
return;
}
if(getCandleDir(rates[1])!=LONG)
return;
const datetime timeStart=rates[1].time, timeEnd=rates[0].time; //within a bullish H4 candle - DONE
double bestRatio = -1;//once a bearish2bullish ratio is higher, we'll move to new place
for(int i=ArraySize(timeframes)-1;i>=0;i--)
{
if(CopyRates(_Symbol,timeframes[i],timeStart,timeEnd,rates)<0)
{
printf("%i %s: failed to copy rates on %d. error=%d",__LINE__,__FILE__,PeriodSeconds(timeframeHighest)/60,_LastError);
return;
}
processRates(rates,bestRatio,bestRatioObjectName);
}
printf("%i %s: best=%.5f, objName =%s: %.5f-%.5f",__LINE__,__FILE__,bestRatio,bestRatioObjectName,
ObjectGetDouble(0,bestRatioObjectName,OBJPROP_PRICE1),ObjectGetDouble(0,bestRatioObjectName,OBJPROP_PRICE2));
//ExpertRemove();//for scripting, a one time call
}
bool isNewBar(const ENUM_TIMEFRAMES tf)
{
const datetime time=iTime(_Symbol,tf,0);
if(time>lastCandleTime)
{
lastCandleTime=time;
return true;
}
return false;
}
int getCandleDir(const MqlRates& rate) // candle direction: +1 for BULL, -1 for BEAR
{
if(rate.close-rate.open>_Point/2.)
return 1;
if(rate.open-rate.close>_Point/2.)
return-1;
return 0;
}
void processRates(const MqlRates& rates[],double &best,const string bestObjName)
{
for(int i=ArraySize(rates)-2; i>0; /* no sense to catch last candle - we cant compare it with anybody */ i--)
{
if(getCandleDir(rates[i])!=LONG)
continue;//current - bullish
if(getCandleDir(rates[i+1])!=SHORT)
continue;//prev - bearish
if(rates[i].close-rates[i+1].open>_Point/2.){}
else continue;
if(rates[i+1].close-rates[i].open>_Point/2.){}
else continue;
const double body=rates[i].close-rates[i].open, twoWicks = rates[i].high-rates[i].low- body;
if(body<twoWicks)
continue; //Each of the candles has a body size bigger than it’s upper and lower wicks combined.
//---
const double prevBody = rates[i+1].open - rates[i+1].close;
const double newRatio = body / prevBody;
if(newRatio>best) // eventually we'll find best bull2bear ratio
{
moveRectangle(rates[i+1],rates[i].time,bestObjName);
best = newRatio;
}
}
}
void moveRectangle(const MqlRates& rate,const datetime rectEnd,const string objectName)
{
if(ObjectFind(0,objectName)<0)
{
if(!ObjectCreate(0,objectName,OBJ_RECTANGLE,0,0,0,0,0))
{
printf("%i %s: failed to draw %s. error=%d",__LINE__,__FILE__,objectName,_LastError);
return;
}
//add GUI things like how to display the rectangle
}
//moving the rectangle to a new place, even for the first time
ObjectSetDouble(0,objectName,OBJPROP_PRICE,0,rate.open);
ObjectSetDouble(0,objectName,OBJPROP_PRICE,1,rate.close);
ObjectSetInteger(0,objectName,OBJPROP_TIME,0,rate.time);
ObjectSetInteger(0,objectName,OBJPROP_TIME,1,rectEnd);
}