// マイライブラリー
#include <MyLib.mqh>
// マジックナンバー
#define MAGIC 20094021
#define COMMENT "ダブルボトム・ダブルトップ"
// 外部パラメータ
extern double Lots = 0.1;
extern int Slippage = 3;
extern double SL_Percent = 0.0; // 損切り値幅(pips)
extern double TP_Percent = 2.0; // 利食い値幅(pips)
//状態管理
enum ZigzagPos
{
Top = 0,
Bottom = 1,
Unknown = 2,
};
ZigzagPos LatestZigzag = Unknown;
double Zigzag_Top_0 = 0;
double Zigzag_Top_1 = 0;
double Zigzag_Bottom_0 = 0;
double Zigzag_Bottom_1 = 0;
double ZigzagMaxTop = 0;
double ZigzagMinBottom = 0;
double Width_M=0;
double Width_W=0;
datetime LatestTime;
input int ZigzagDepth = 12;
input int ZigzagDeviation = 5;
input int ZigzagBackstep = 3;
input int AllowableErrorPoint = 30; // Maximum distance between the twin tops/bottoms
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int EntrySignal(int magic)
{
// オープンポジションの計算
double pos = MyCurrentOrders(MY_OPENPOS, magic);
bool sellSignal=false;
bool buySignal=false;
//ダブルトップが形成されているか確認する
if(Zigzag_Top_0<Zigzag_Top_1+AllowableErrorPoint*Point
&&Zigzag_Top_0>Zigzag_Top_1-AllowableErrorPoint*Point
&&ZigzagMaxTop!=0
&&LatestZigzag==Top)
{
/*
以下の2つを同時に満たす場合、取引チャンスを逃す場合があると考え、当初はelse文を通るようにしていた。
・Zigzagインジケータの最新の点が現在の足である
・W(M)字のネックラインを超えていない
しかし、このelse文を追加してしまうと以下の条件を満たす時に余計なエントリーをする場合があり、最終的にいったん撤廃した。
・ネックラインを超えた後、Zigzagインジケータの最新の点が更新されている
・W(M)字のネックラインを一度は超えたが、再度ネックラインまで下がった場合
*/
//if(LatestZigzag==Top)
//{
Width_M=ZigzagMaxTop-Zigzag_Bottom_0;
//}
//else
//{
//Width_M=ZigzagMaxTop-Zigzag_Bottom_1;
//}
double nowPos=100*(ZigzagMaxTop-Close[0])/Width_M;
if(nowPos>101&&nowPos<105)
{
sellSignal=true;
}
}
//ダブルボトムが形成されているか確認する
if(Zigzag_Bottom_0<Zigzag_Bottom_1+AllowableErrorPoint*Point
&&Zigzag_Bottom_0>Zigzag_Bottom_1-AllowableErrorPoint*Point
&&ZigzagMinBottom!=0
&&LatestZigzag==Bottom)
{
//if(LatestZigzag==Bottom)
// {
Width_W=Zigzag_Top_0-ZigzagMinBottom;
//}
//else
//{
//Width_W=Zigzag_Top_1-ZigzagMinBottom;
//}
nowPos=100*(Close[0]-ZigzagMinBottom)/Width_W;
if(nowPos>101&&nowPos<105)
{
buySignal=true;
}
}
int ret = 0;
// 買いシグナル
if(pos <= 0 && buySignal)
ret = 1;
// 売りシグナル
if(pos >= 0 && sellSignal)
ret = -1;
return(ret);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void UpdateZigZag()
{
double zigzagValue[4];
int zigzagValueCount=0;
for(int i=1; i<iBars(Symbol(),0); i++)
{
double Zigzag=iCustom(Symbol(),0,"ZigZag",ZigzagDepth,ZigzagDeviation,ZigzagBackstep,0,i);
if(Zigzag!=0)
{
zigzagValue[zigzagValueCount]=NormalizeDouble(Zigzag,Digits);
zigzagValueCount++;
}
if(zigzagValueCount==4)
{
if(zigzagValue[0]>zigzagValue[1])
{
LatestZigzag = Top;
Zigzag_Top_0 = zigzagValue[0];
Zigzag_Bottom_0 = zigzagValue[1];
Zigzag_Top_1 = zigzagValue[2];
Zigzag_Bottom_1 = zigzagValue[3];
}
else
{
LatestZigzag = Bottom;
Zigzag_Bottom_0= zigzagValue[0];
Zigzag_Top_0= zigzagValue[1];
Zigzag_Bottom_1= zigzagValue[2];
Zigzag_Top_1= zigzagValue[3];
}
ZigzagMinBottom=Zigzag_Bottom_0<Zigzag_Bottom_1? Zigzag_Bottom_0:Zigzag_Bottom_1;
ZigzagMaxTop=Zigzag_Top_0>Zigzag_Top_1? Zigzag_Top_0:Zigzag_Top_1;
break;
}
}
}
// スタート関数
int start()
{
if(Time[0] != LatestTime)
{
UpdateZigZag();
LatestTime = Time[0];
}
// エントリーシグナル
int sig_entry = EntrySignal(MAGIC);
// 買い注文
if(sig_entry > 0)
{
MyOrderClose(Slippage, MAGIC);
MyOrderSend(OP_BUY, Lots, Ask, Slippage, ZigzagMinBottom+(SL_Percent*Width_W), ZigzagMinBottom+(TP_Percent*Width_W), COMMENT, MAGIC);
}
// 売り注文
if(sig_entry < 0)
{
MyOrderClose(Slippage, MAGIC);
MyOrderSend(OP_SELL, Lots, Bid, Slippage, ZigzagMaxTop-(SL_Percent*Width_M), ZigzagMaxTop-(TP_Percent*Width_M), COMMENT, MAGIC);
}
return(0);
}
//+------------------------------------------------------------------+