今回は、MT4のEAサンプルソース(FX用)を公開します。
トレードに使うテクニカル分析はZigZagで、ナンピン手法を使いながら順張りエントリーをしています。
はじめに
MT4のEAには、 ナンピンを用いた物もよくあります。
ナンピンするとなった場合、実際プログラムでナンピンする方法はいたって簡単です。難しいのは、ナンピンする場所・タイミングだと思いますが、現在私が公開しているZigZagのサンプルEAはここでナンピンできたらなーというタイミングが結構あったのでZigZagのサンプルEAにナンピン手法を取り入れていきます。
※ナンピンしないタイプのベースになったZigZagサンプルEAの記事はこちら
EAの仕様
エントリータイミング
ロングエントリー
高値の切り上げ、安値の切り上げ中の、ZigZagの最新の底値が確定した後にロングしています。
ショートエントリー
高値切り下げ、安値切り下げ中の、ZigZagの最新の高値が確定した後にショートしています。
ナンピン
上記のエントリータイミングのデメリットとして下図の事が発生していましたが、それを補う感じでデメリットが発生したら追加でエントリーするという感じでナンピンを行っています。
※最大4ポジションまで
ナンピン修正を加える前と後の違いを実際のエントリーポイントで確認してみるとこんな感じです。
修正前でもうまく利益を取れていますが、さらに利益をあげる事ができそうです。
黄色〇の部分を見て頂ければわかるように、エントリー後悪い方向に値が動くとナンピンして3つエントリーが増えている事がわかります。
EAレポート結果
修正前のZigZagのEAと同じ期間でバックテストを行いました。プロフィットファクターの値が1.09から1.15に改善されています。逆指値40pipsに対して指値を10pipsにしたので、勝率が52%から82%にまであがってますね。また、ここ近年の成績はかなり良い感じになってます。
ダウンロード
上記のEAファイルになります。
“ZigZagナンピンEA” をダウンロード 17_Nanpin.ex4 – 4205 回のダウンロード – 15.33 KBソースコード
以下サンプルソースコードになります。
※丸々コピペでコンパイルできます
//+------------------------------------------------------------------+
//| ZigZag_Sample.mq4 |
//| Copyright 2020, mef Software. |
//| https://fx-prog.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, mef Software."
#property link "https://fx-prog.com/"
#property version "1.00"
input int E_Depth = 16;
input int E_Deviation = 5;
input int E_Backstep = 3;
input int A_SPREAD = 20;
input double Lots = 0.01;
input int STOP_LOSS = 400;
input int TP = 100;
double ZigTop[5]; //ジグザグの山保存用
double ZigBottom[5]; //ジグザグの谷保存用
int TopPoint;
int BottomPoint;
datetime prevtime;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
int start()
{
int orderPtn=0; //0:何もしない 1:買い 2:売り
int total=0;
double ea_order_stop_price=0,ea_order_good_price=0; //ストップロスレート,利確レート,エントリーレート
bool OrderKekka;
//---
//新しい足ができた時だけやる
if(Time[0] != prevtime){
prevtime = Time[0];
}else{
return(0);
}
//***売買判断箇所***//
//チェック用変数の初期化
TopPoint=0;
BottomPoint=0;
//ZigZagの高値安値を構造体に再セット
getZigZag(1);
//高値切り上げ安値切り上げでロング
if(ZigTop[0] > ZigTop[1] && ZigTop[1] > ZigTop[2] &&
ZigBottom[0] > ZigBottom[1] && ZigBottom[1] > ZigBottom[2] && BottomPoint==1)
{
orderPtn=1;
}
//高値切り下げ安値切り下げでショート
else if(ZigTop[0] < ZigTop[1] && ZigTop[1] < ZigTop[2] &&
ZigBottom[0] < ZigBottom[1] && ZigBottom[1] < ZigBottom[2] && TopPoint==1)
{
orderPtn=2;
}
else
{
orderPtn=0;
}
//***売買判断箇所***//
//***決済判断箇所***//
total=OrdersTotal();
//ナンピン処理
if(total > 0 && orderPtn > 0){
OrderKekka = OrderSelect(total-1,SELECT_BY_POS,MODE_TRADES);
if(OrderType()==OP_BUY && orderPtn == 2){
orderPtn =0;
}else if(OrderType()==OP_SELL && orderPtn == 1){
orderPtn =0;
}
if(OrderType()==OP_BUY && (OrderOpenPrice() - 40 * Point < Ask)){
orderPtn =0;
}else if(OrderType()==OP_SELL && (OrderOpenPrice() + 40 * Point > Bid)){
orderPtn =0;
}
//既にナンピンを4回している場合は追加ナンピンしない
if(total>3){
orderPtn =0;
}
}
if(orderPtn > 0)
{
if(orderPtn == 1)
{
ea_order_stop_price = Ask - STOP_LOSS * Point;
ea_order_good_price = Ask + TP * Point;
}
else if(orderPtn == 2)
{
ea_order_stop_price = Bid + STOP_LOSS * Point;
ea_order_good_price = Bid - TP * Point;
}
//新規注文
OrderKekka = funcOrder_Send(orderPtn - 1,ea_order_stop_price,ea_order_good_price,0,0);
}
return(0);
}
//+------------------------------------------------------------------+
//|【関数】新規注文関数 |
//| |
//|【引数】 ea_order_entry_Type:売買(0:買 1:売) |
//|【引数】 ea_order_stop_price:損切値 ea_order_good_price:利確値 |
//|【引数】 orderComment:オーダーコメント ea_order_MagicNo:マジックNo |
//| |
//|【戻値】True:成功 |
//| |
//|
bool funcOrder_Send(int ea_order_entry_Type, double ea_order_stop_price, double ea_order_good_price,int orderComment,int ea_order_MagicNo)
{
int order_resend_num; // エントリー試行回数
int ea_ticket_res; // チケットNo
int errorcode; // エラーコード
double ea_order_entry_price; // エントリーレート
color order_Color;
bool kekka;
for( order_resend_num = 0; order_resend_num < 10; order_resend_num++ ) { // エントリー試行回数上限:10回
if(MarketInfo(NULL,MODE_SPREAD) < A_SPREAD ){
if(ea_order_entry_Type == OP_BUY){
ea_order_entry_price = Ask; // 現在の買値でエントリー
order_Color = clrBlue;
Print(Ask+"でロングするよ!");
}else if(ea_order_entry_Type == OP_SELL){
ea_order_entry_price = Bid; // 現在の売値でエントリー
order_Color = clrRed;
Print(Bid+"でショートするよ!");
}
// FXCMでは新規エントリー時にストップ/リミットを設定出来ない。
ea_ticket_res = OrderSend( // 新規エントリー注文
NULL, // 通貨ペア
ea_order_entry_Type, // オーダータイプ[OP_BUY / OP_SELL]
Lots , // ロット[0.01単位](FXTFは1=10Lot)
ea_order_entry_price, // オーダープライスレート
20, // スリップ上限 (int)[分解能 0.1pips]
ea_order_stop_price, // ストップレート
ea_order_good_price, // リミットレート
orderComment, // オーダーコメント
ea_order_MagicNo, // マジックナンバー(識別用)
0, // オーダーリミット時間
order_Color // オーダーアイコンカラー
);
Print("結果:"+ea_ticket_res);
if ( ea_ticket_res == -1) { // オーダーエラー
errorcode = GetLastError(); // エラーコード取得
if( errorcode != ERR_NO_ERROR) { // エラー発生
printf("エラー");
}
Sleep(2000); // 1000msec待ち
RefreshRates(); // レート更新
printf("再エントリー要求回数:%d, 更新エントリーレート:%g",order_resend_num+1 ,ea_order_entry_price);
} else { // 注文約定
Print("新規注文約定。 チケットNo=",ea_ticket_res," レート:",ea_order_entry_price);
Sleep(300); // 300msec待ち(オーダー要求頻度が多過ぎるとエラーになる為)
break;
}
}else{
Print("スプレッドNG 許容スプレッド:"+A_SPREAD+"pips未満 環境スプレッド:"+MarketInfo(NULL,MODE_SPREAD)+"pips");
Sleep(2000); // 2000msec待ち
RefreshRates();
}
}
return kekka;
}
//+------------------------------------------------------------------+
//|【関数】ジグザグの値をセット
//|
//|
//|【備考】なし
//+------------------------------------------------------------------+
bool getZigZag(int i)
{
int n,m,t;
bool kekka;
m=0;
t=0;
kekka=false;
for(n=i;n<=i+200;n++)
{
//ZigZagの値を取得
double Zg=NormalizeDouble(iCustom(NULL,0,"ZigZag",E_Depth,E_Deviation,E_Backstep,0,n),5);
//ZigZagの値と最高値が同じ場合、頂点なのでZigTopにセット
if(Zg!=0 && Zg==NormalizeDouble(High[n],5))
{
if(n==1){
TopPoint=1;
}
ZigTop[m++]=Zg;
if(m>=4)break;
}
//ZigZagの値と最安値が同じ場合、底なのでZigBottomにセット
if(Zg!=0 && Zg==NormalizeDouble(Low[n],5))
{
if(n==1){
BottomPoint=1;
}
ZigBottom[t++]=Zg;
if(t>=4)break;
}
}
kekka=true;
//目視確認用コメント
Comment(
"│ ZigTOP0=", ZigTop[0], "│ ZigBTM0=", ZigBottom[0], "|\n",
"│ ZigTOP1=", ZigTop[1], "│ ZigBTM1=", ZigBottom[1], "|\n",
"│ ZigTOP2=", ZigTop[2], "│ ZigBTM2=", ZigBottom[2], "|\n",
"│ ZigTOP3=", ZigTop[3], "│ ZigBTM3=", ZigBottom[3], "|\n",
"│ TopP=", TopPoint, "│ BottomP=", BottomPoint, "|\n"
);
return(kekka);
}
一応前述したナンピン修正を加えたZigZagEAのサンプルソースコードになります。
あと設定で、ZigZagのDepth値、指値、逆指値を少し変えてます。
それ以外の処理はZigZagのサンプルEAから何も変えていません。
このナンピン型のZigZagロジックの調整例としては、ナンピン時に既に保持しているポジションの指値を変更してやったり、ナンピン時のロット数を変える等があると思います。ロット数を変える方法は、かなりマーチンゲール手法に近くなるので安定性はさらに増すと思います。(また別のタイミングでサンプルソースを作ってみようと思います)
主な構文
ナンピンはポジション管理になるので、こういう関数を使えばナンピンできるとかはありません。
プログラムでポジションを持っているかどうかを確認していく形になります。
ポジションを複数持たせたい
私が作るプログラムの場合、エントリー前にポジションを持っているかどうかを判断している場所があります。既にポジションがあればエントリーしない作りになっているためここを修正します。
修正前の状態
if(total ==0 && orderPtn > 0)
修正後の状態
if(total > 0 && orderPtn > 0)
{
OrderKekka = OrderSelect(total-1,SELECT_BY_POS,MODE_TRADES);
if(OrderType()==OP_BUY && orderPtn == 2){
orderPtn =0;
}else if(OrderType()==OP_SELL && orderPtn == 1){
orderPtn =0;
}
if(OrderType()==OP_BUY && (OrderOpenPrice() - 40 * Point < Ask)){
orderPtn =0;
}else if(OrderType()==OP_SELL && (OrderOpenPrice() + 40 * Point > Bid)){
orderPtn =0;
}
//既にナンピンを4回している場合は追加ナンピンしない
if(total>3){
orderPtn =0;
}
}
if(orderPtn > 0)
こんな感じに修正すると、前回ポジションが4pips以上マイナスになっている場合に、同一方向に4ポジションまで持つようになります。5pips以上にしたい場合は2つの『40 * Point』の箇所を『50 * Point』にすればOKです。
また、ポジションを最大5つまで持たせたい場合は『if(total>3){』の箇所を『if(total>4){』にすればOKです。
さいごに
以上、ZigZagでナンピンを使ったEAのサンプルソースでした。
カーブフィッティングしてしまうようなナンピン手法の修正を加えてはいないと思うので、ZigZagEAに対して、ナンピンは結構有効なのかなという印象です。
※2021/04/03追記
このZigZagEA(ナンピン版)をメンテして、ロット数や変更注文をするZigZagEAのサンプルソースを公開しました。
※ EAのサンプルソースを一覧表にまとめました
※EA作成依頼はこちら
※オンラインレッスンやってます
コメント
いつも読ませていただきとても参考になり感謝しかないです!
今作っているのがMACDナンピンのロングのみEAなんですがやはり含み損回避の為にナンピンし一定の含み損になると損切りをしたいと思い、色々試したんですがコンパイルしてもエラーが出て全然上手くいきません。
そこてナンピン+損切りのソースコードが分かりません。
設定としてはシグナル線とMACD線クロスでロング、20%下落でナンピンですが100%下落すると損切りって可能ですか?
佐藤さとし さん
ブログを読んで頂き有難うございます!
少し質問させてください。
一定の含み損になると損切りという事は、ストップロス(SL)ではなくOrderClose()関数で決済させるような作りにするという事ですか?
20%下落でナンピンという事ですが、20%は何の数値を表しているでしょうか?(MACD値とか証拠金維持率でしょうか?)
りょう 様
初めまして。いつもりょうさんのブログを拝見させて頂いております。
丁寧で分かりやすく、とても役立っています。
私はプログラムに関しては素人に毛が生えた程度なのですが、りょうさんのプログラムを参考にし今までMT4でEAを作って来ましたが、最近MT5でも作り始めるようになり、今回のこの『ZigZag』も参考にさせて頂いて自分なりにMT5で作りコンパイルまでは完了したのですが、テスターやデモ口座でテストをしてみたところ全く注文されず、オーダーなどの関数は今まで使っていたものの流用なので間違いないのですが、どうも『iCustom関数』がうまく取得出来ていないようでCommentで『iCustom関数』の取得数値をチャート上に表示させてみたところ『210.0』や『411.0』などとても通貨の価格ではないような数値が表示されていました。
ネットで調べてみると『iCustom関数』はMQL4とMQL5ではかなり動作が違うようで、もしりょうさんの分かる範囲で結構ですので何か参考になるような事があれば教えて頂けないでしょうか?
(因みにMT4で同じように『iCustom関数』をCommentで数値の取得してみると、正しい通貨の価格が表示されました)
不躾な質問で申し訳ありませんが、宜しくお願いします。
ブログを拝見して頂き有難うございます。
MLQ5はほぼ知識が無い&開発環境も整えていないため、憶測の部類になってしまうのですが、MLQ5では確かi〇〇系(iCustom含む)で値を取得すると、ハンドル値(MQL4では実値だった)が返ってくるので、それをCopyBuffer()を使って実値に変換する必要があったかと思います。
お力になれず申し訳ございませんm(__)m
りょう 様へ
早速のお返事ありがとございます。
いえいえ、こちらこそ不躾な質問、本当にすみませんでした。
それにもかかわらずしっかりとお答え頂き、りょうさんの誠実なお人柄を
感じることが出来ました。 とても感謝しております。
今後もりょうさんのブログを参考にさせて頂きます。応援しております。
ありがとうございました。