今回は、MT4のEAサンプルソース(FX用)を公開します。
はじめに
前回作ったマーチンゲール法を使ったEAを作ったのですが面白い成績になったため、別のEAにもマーチンゲール法を取り入れたくなりました。
そこで、手軽に展開する事ができるようにマーチンゲール法の関数を作りました。
ソースに関数をコピペし、あとはOrderSend()関数のロット数の所をちょろっと書き換えるだけで簡単にマーチンゲール法が実現できるようになります。
マーチンゲール法を試してみたい方は是非ご活用下さい。
※ナンピン&マーチン型ではなく1つのポジションで過去の履歴をみて次回トレードに反映させる型です
マーチンゲール法を使った結果の例
マーチンゲール法を使うとあまり全然成績の良くないEAが右肩上がりのEAに化けます。こちらのマーチンゲール法適用前と適用後のバックテスト結果をご覧ください。
勝率も33%のEAで最大10Lot縛りですが、こんな感じで変わってきます。
ソースコード
取引履歴からマーチンゲールを適用したロット数を計算する関数です。
//+------------------------------------------------------------------+
//|【関数】取引履歴からマーチンゲールを適用したロット数を計算する
//|
//|【引数】 基本のロット数,最大ロット数,マジックナンバー
//|(最大ロット数はマーチンゲールを適用したとして、最大限度とするロット数を設定する 0で無限)
//|【戻値】Lot数
//|
double getMartingale(double BaseLots, double MaxLots, int ea_order_MagicNo){
double profit = 0,ans = 0,total = BaseLots;
//過去の取引履歴を検索
for(int cnt = OrdersHistoryTotal(); cnt > 0; cnt--){
if(OrderSelect(cnt-1,SELECT_BY_POS,MODE_HISTORY) == true){
//マジックナンバーが同一の場合
if(OrderMagicNumber() == ea_order_MagicNo){
//収支計算
if(OrderType()==OP_SELL){
profit = OrderOpenPrice()-OrderClosePrice();
}else if(OrderType()==OP_BUY){
profit = OrderClosePrice()-OrderOpenPrice();
}
if(Digits==2 || Digits==3){
profit *= 100;
}else if(Digits==4 || Digits==5){
profit *= 10000;
}
//プラス収支の場合は初期ロット数で抜ける
if(profit > 0){
break;
//イーブンの場合は保留とする
}else if(profit == 0){
total = total;
//マイナス収支の場合は倍数とする
}else{
total = total*2;
}
}
}
}
ans = total;
//枚数が最大を超えた場合、最大に制御する
if(ans>MaxLots){
ans=MaxLots;
}
return(ans);
}
この関数をEAのソースコードの一番下等にコピペで貼り付けてください。
解説
引数
引数1は基本のロット数です。EAのパラメータ設定にあるLotにする感じでOKです。
引数2は最大ロット数を、ロット数の値で渡す形にしています。
※FX業者によって最大ロット数は決められており、10ロットまでしか対応していない場合、11ロットでエントリーしようとしてもエラーでエントリーできないため
また、10ロットは大きすぎるので、『5』に設定する事でどれだけ連敗しても最大は5Lotとなります。
引数3はマジックナンバーです。これもパラメータ設定のマジックナンバーにする感じでOKです。
戻り値
過去のトレード連敗数に応じた、ロット数を返します。 ※1ロット=10万通貨
(引数2に設定した値を超えることはありません)
上記関数の使用例
// 新規エントリー注文
int CNo = OrderSend(
NULL, // 通貨ペア
OP_BUY, // オーダータイプ[OP_BUY / OP_SELL]
getMartingale(Lots,10,MagicNo), // ロット[0.01単位]
Ask, // オーダープライスレート
・・・
OrderSend()関数のロット数のところに書き込む感じです。
使用した結果はこんな感じで、マーチンゲール法が適用されている事がわかります。
修正の具体例
では、現在私が公開している以下記事のアリゲーターのソースコードに今回のマーチンゲール法を適用してみます。
関数の追加の仕方とか、あまり修正内容がわからない方は参考にしてみてください。
修正箇所①
まずは、アリゲーターのソースコードの一番下に今回のgetMartingale()関数を追加します。
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;
}
}
return kekka;
}
//+------------------------------------------------------------------+
//|【関数】取引履歴からマーチンゲールを適用したロット数を計算する
//|
//|【引数】 基本のロット数,最大ロット数,マジックナンバー
//|(最大ロット数はマーチンゲールを適用したとして、最大限度とするロット数を設定する 0で無限)
//|【戻値】Lot数
//|
double getMartingale(double BaseLots, double MaxLots, int ea_order_MagicNo){
double profit = 0,ans = 0,total = BaseLots;
//過去の取引履歴を検索
for(int cnt = OrdersHistoryTotal(); cnt > 0; cnt--){
if(OrderSelect(cnt-1,SELECT_BY_POS,MODE_HISTORY) == true){
//マジックナンバーが同一の場合
if(OrderMagicNumber() == ea_order_MagicNo){
//収支計算
if(OrderType()==OP_SELL){
profit = OrderOpenPrice()-OrderClosePrice();
}else if(OrderType()==OP_BUY){
profit = OrderClosePrice()-OrderOpenPrice();
}
if(Digits==2 || Digits==3){
profit *= 100;
}else if(Digits==4 || Digits==5){
profit *= 10000;
}
//プラス収支の場合は初期ロット数で抜ける
if(profit > 0){
break;
//イーブンの場合は保留とする
}else if(profit == 0){
total = total;
//マイナス収支の場合は倍数とする
}else{
total = total*2;
}
}
}
}
ans = total;
//枚数が最大を超えた場合、最大に制御する
if(ans>MaxLots){
ans=MaxLots;
}
return(ans);
}
修正箇所②
次にロット数の箇所を修正します。
修正前
// 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]
修正後
// FXCMでは新規エントリー時にストップ/リミットを設定出来ない。
ea_ticket_res = OrderSend( // 新規エントリー注文
NULL, // 通貨ペア
ea_order_entry_Type, // オーダータイプ[OP_BUY / OP_SELL]
getMartingale(Lots,10,ea_order_MagicNo), // ロット[0.01単位](FXTFは1=10Lot)
ea_order_entry_price, // オーダープライスレート
修正は以上です。上記の修正を適用した全体ソースコードはこんな感じです。
//+------------------------------------------------------------------+
//| Alligator_TEST.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 J_KIKAN = 13;
input int J_Shift = 8;
input int T_KIKAN = 8;
input int T_Shift = 5;
input int L_KIKAN = 5;
input int L_Shift = 3;
input int A_SPREAD = 20;
input double Lots = 0.01;
input int SL = 300;
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);
}
//***売買判断箇所***//
//ジョーズライン
double JAW_ATAI_1 = iAlligator(NULL, 0, J_KIKAN, J_Shift, T_KIKAN, T_Shift, L_KIKAN ,L_Shift, MODE_SMMA, PRICE_MEDIAN, MODE_GATORJAW, 1);
double JAW_ATAI_2 = iAlligator(NULL, 0, J_KIKAN, J_Shift, T_KIKAN, T_Shift, L_KIKAN ,L_Shift, MODE_SMMA, PRICE_MEDIAN, MODE_GATORJAW, 2);
//ティースライン
double TEETH_ATAI_1 = iAlligator(NULL, 0, J_KIKAN, J_Shift, T_KIKAN, T_Shift, L_KIKAN ,L_Shift, MODE_SMMA, PRICE_MEDIAN, MODE_GATORTEETH, 1);
double TEETH_ATAI_2 = iAlligator(NULL, 0, J_KIKAN, J_Shift, T_KIKAN, T_Shift, L_KIKAN ,L_Shift, MODE_SMMA, PRICE_MEDIAN, MODE_GATORTEETH, 2);
//リップスライン
double LIPS_ATAI_1 = iAlligator(NULL, 0, J_KIKAN, J_Shift, T_KIKAN, T_Shift, L_KIKAN ,L_Shift, MODE_SMMA, PRICE_MEDIAN, MODE_GATORLIPS, 1);
double LIPS_ATAI_2 = iAlligator(NULL, 0, J_KIKAN, J_Shift, T_KIKAN, T_Shift, L_KIKAN ,L_Shift, MODE_SMMA, PRICE_MEDIAN, MODE_GATORLIPS, 2);
//ローソク足の1つ前のクローズ値情報を取得しておく
double rosokuValueCloseP = iClose(NULL, 0, 1);
//リップスラインのゴールデンクロスでロング(ジョーズラインが上を向いている事)
if(LIPS_ATAI_1 > TEETH_ATAI_1 && LIPS_ATAI_1 > JAW_ATAI_1 && JAW_ATAI_2 < JAW_ATAI_1 && rosokuValueCloseP > LIPS_ATAI_1)
{
//ロングエントリー
orderPtn=1;
}
//リップスラインのデッドクロスでショート(ジョーズラインが下を向いている事)
else if(LIPS_ATAI_1 < TEETH_ATAI_1 && LIPS_ATAI_1 < JAW_ATAI_1 && JAW_ATAI_2 > JAW_ATAI_1 && rosokuValueCloseP < LIPS_ATAI_1)
{
//ショートエントリー
orderPtn=2;
}
else
{
//エントリーしない
orderPtn=0;
}
//***売買判断箇所***//
total=OrdersTotal();
if(total == 1){
OrderKekka = OrderSelect(0,SELECT_BY_POS,MODE_TRADES);
//買いエントリー中に、ショートエントリーのサインが出たら決済する
if(OrderKekka == true && OrderType() == OP_BUY && LIPS_ATAI_1 > rosokuValueCloseP){
if(orderPtn==2 || LIPS_ATAI_1 < JAW_ATAI_1){
OrderKekka = OrderClose(OrderTicket(),OrderLots(),Bid,10,Violet);
}
}
//売りエントリー中に、ロングエントリーのサインが出たら決済する
else if(OrderKekka == true && OrderType() == OP_SELL && LIPS_ATAI_1 < rosokuValueCloseP){
if(orderPtn==1 || LIPS_ATAI_1 > JAW_ATAI_1){
OrderKekka = OrderClose(OrderTicket(),OrderLots(),Ask,10,Violet);
}
}
}
//***決済判断箇所***//
total=OrdersTotal();
if(total ==0 && orderPtn > 0)
{
if(orderPtn == 1)
{
ea_order_stop_price = JAW_ATAI_1 - SL * Point;
ea_order_good_price = 0;
}
else if(orderPtn == 2)
{
ea_order_stop_price = JAW_ATAI_1 + SL * Point;
ea_order_good_price = 0;
}
//新規注文
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;
}else if(ea_order_entry_Type == OP_SELL){
ea_order_entry_price = Bid; // 現在の売値でエントリー
order_Color = clrRed;
}
// FXCMでは新規エントリー時にストップ/リミットを設定出来ない。
ea_ticket_res = OrderSend( // 新規エントリー注文
NULL, // 通貨ペア
ea_order_entry_Type, // オーダータイプ[OP_BUY / OP_SELL]
getMartingale(Lots,10,ea_order_MagicNo), // ロット[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 // オーダーアイコンカラー
);
}
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;
}
}
return kekka;
}
//+------------------------------------------------------------------+
//|【関数】取引履歴からマーチンゲールを適用したロット数を計算する
//|
//|【引数】 基本のロット数,最大ロット数,マジックナンバー
//|(最大ロット数はマーチンゲールを適用したとして、最大限度とするロット数を設定する 0で無限)
//|【戻値】Lot数
//|
double getMartingale(double BaseLots, double MaxLots, int ea_order_MagicNo){
double profit = 0,ans = 0,total = BaseLots;
//過去の取引履歴を検索
for(int cnt = OrdersHistoryTotal(); cnt > 0; cnt--){
if(OrderSelect(cnt-1,SELECT_BY_POS,MODE_HISTORY) == true){
//マジックナンバーが同一の場合
if(OrderMagicNumber() == ea_order_MagicNo){
//収支計算
if(OrderType()==OP_SELL){
profit = OrderOpenPrice()-OrderClosePrice();
}else if(OrderType()==OP_BUY){
profit = OrderClosePrice()-OrderOpenPrice();
}
if(Digits==2 || Digits==3){
profit *= 100;
}else if(Digits==4 || Digits==5){
profit *= 10000;
}
//プラス収支の場合は初期ロット数で抜ける
if(profit > 0){
break;
//イーブンの場合は保留とする
}else if(profit == 0){
total = total;
//マイナス収支の場合は倍数とする
}else{
total = total*2;
}
}
}
}
ans = total;
//枚数が最大を超えた場合、最大に制御する
if(ans>MaxLots){
ans=MaxLots;
}
return(ans);
}
既存のソースコードをほぼほぼ変更せずにマーチンゲール法が適用されましたね!
さいごに
勝率の高いEAだと、マーチンゲール法を利用するとかなり安定するので使う場面は出てきそうなので関数化しました。
勝率が90%とかだと10連敗する確率は0.1*0.1*0.1*・・・=0.00000001%なので0.01Lot開始のトレードで10lotまでいく事は滅多にないと考え出すと危ないですが夢がありますね。
※ EAのサンプルソースを一覧表にまとめました
※オンラインレッスンやってます
コメント
りょうさんが公開しているソースコードのどれかに、今回のマーチン関数を入れたソースを例として掲載して欲しいです。
初歩的な事もままならない私にとって、今回の記事の内容を試しましたがコンパイル時にエラーが出てしまい、解決方法がわからなかったため、具体的な例をいただきたいです。
宜しくお願い致します。
新さん、ご意見ありがとうございます!
記事に修正の具体例の章を追加しました。
早速の対応ありがとうございます!
はじめまして
1つ教えて頂きたい事があります。
マーチン倍数部分 total = total*2;
をロットを0.1負けたら次0.2負けたら0.3
と+1ずつ足す方法教えて頂けるとありがたいです。
よろしくお願い致します。
ラドローさん
初めまして。コメント有難うございます。
+1ずつ足す方法ですが242行目の、
『total = total*2;』の箇所を『total = total+Lots;』と書き換えて頂ければ対応可能です。
りょうさん
ありがとうございます!出来ました!