ここでは、MT4のEAによる取引で連勝中はロット数を増やして、連敗中はロット数を減らす機能を追加する方法を解説します。
過去の記事【MT4のEAに複利(MM)機能を搭載する方法】のサンプルEAに、今回の機能を追加していきます。
過去の記事【MT4のEAに複利(MM)機能を搭載する方法】へ
MM機能搭載例のサンプルEA【Sample_MM.mq4】をダウンロード
ロット数増減の計算ルール
ロット数の増減量
連勝中のロット数は、2連勝で10%増し、3連勝で20%増しとしていき、最大100%(2倍)までとします。
連敗中のロット数は、2連敗で1/2(2分の1)、3連敗で1/3(3分の1)としていきます。
勝敗の基準
EA稼働開始または前回勝敗判定以降に決済済みのポジションがあり、現在保有ポジションがない状態に勝敗判定を行い、決済済みのポジションの損益合計がプラスなら勝ち、マイナスなら負け、±0ならノーカウントとします。
追加コードの解説
今回完成したEAのコードがこちらじゃ。
extern double Lots = 0.1; extern bool UseMM = true; extern double BalancePerLots = 100000; extern int MagicNumber = 20191114; double max_lot; // 最大ロット数 double min_lot; // 最小ロット数 int lot_digit; // ロット小数桁数 int win_cnt; // 連勝・連敗数 datetime last_cnt_time; // 最終判定時間 int OnInit() { max_lot = MarketInfo(Symbol(), MODE_MAXLOT); min_lot = MarketInfo(Symbol(), MODE_MINLOT); double lotstep = MarketInfo(Symbol(), MODE_LOTSTEP); if(NormalizeDouble(lotstep, 3) <= 0.001) lot_digit = 3; else if(NormalizeDouble(lotstep, 2) <= 0.01) lot_digit = 2; else if(NormalizeDouble(lotstep, 1) <= 0.1) lot_digit = 1; else lot_digit = 0; win_cnt = 0; last_cnt_time = TimeCurrent(); if (IsTesting() == false) return(INIT_FAILED); return(INIT_SUCCEEDED); } void OnTick() { int i; // ポジションの有無を確認 int pos_cnt = 0; for (i=0; i<OrdersTotal(); i++) { if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) return; if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue; pos_cnt++; } // 連勝・連敗カウント static int last_hist_cnt = 0; int now_hist_cnt = OrdersHistoryTotal(); if (pos_cnt == 0 && last_hist_cnt != now_hist_cnt) { last_hist_cnt = now_hist_cnt; double total_profit = 0; for (i=0; i<now_hist_cnt; i++) { if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) == false) continue; if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue; if (OrderCloseTime() <= last_cnt_time) continue; total_profit += OrderProfit() + OrderSwap() + OrderCommission(); } if (total_profit > 0) { if (win_cnt < 0) win_cnt = 1; else win_cnt++; } if (total_profit < 0) { if (win_cnt > 0) win_cnt = -1; else win_cnt--; } last_cnt_time = TimeCurrent(); } // 適当な取引 if (pos_cnt == 0) { // ロット数を算出 double lots = Lots; if (UseMM == true) lots = AccountBalance() / BalancePerLots * Lots; // 連勝時のロット数 if (win_cnt > 1) lots += lots * 10 * MathMin(win_cnt-1, 10) * 0.01; // 連敗時のロット数 if (win_cnt < -1) lots *= -1.0 / win_cnt; lots = MathFloor(lots * MathPow(10, lot_digit)) * MathPow(0.1, lot_digit); if (lots > max_lot) lots = max_lot; if (lots < min_lot) lots = 0; if (lots > 0) int ticket = OrderSend(Symbol(), OP_BUY, lots, Ask, 0, Ask - 100*Point, Ask + 100*Point, NULL, MagicNumber, 0, clrBlue); else Print("残高不足です"); } }
今回完成EAファイル【Sample_MM_LotSize.mq4】をダウンロード
当該EAでのポジションかを判別可能にする
サンプルEAでは、テスターでのみの実行を前提としたコードなので、パラメーターMagicNumberを追加して、他のポジションをカウントしないようにします。
extern int MagicNumber = 20191114;
OnTick()関数の最初に次のコードを追加します。
int i; // ポジションの有無を確認 int pos_cnt = 0; for (i=0; i<OrdersTotal(); i++) { if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) return; if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue; pos_cnt++; }
ポジションの有無をpos_cntで判定するようにif (pos_cnt == 0)としておき、OrderSend()関数のマジックナンバー部分にMagicNumberを指定します。
int ticket = OrderSend(Symbol(), OP_BUY, lots, Ask, 0, Ask - 100*Point, Ask + 100*Point, NULL, MagicNumber, 0, clrBlue);
グローバル変数を追加
グローバル変数には、連勝・連敗をカウントしておく整数変数と勝敗判定した時の時間を格納する変数を宣言します。
int win_cnt; // 連勝・連敗数 datetime last_cnt_time; // 最終判定時間
連敗の場合は、win_cntにマイナス値を入れていくようにします。
OnInit()関数内でグローバル変数を初期化
今回は、EA再稼働やパラメーター設定変更時に前回稼働時の連勝・連敗データを引き継がず、リセットするようにします。
win_cnt = 0; last_cnt_time = TimeCurrent();
OnTick()関数内で勝敗を判定
OnTick()関数内に次のコードを追加して、勝敗を判定します。
static int last_hist_cnt = 0; int now_hist_cnt = OrdersHistoryTotal(); if (pos_cnt == 0 && last_hist_cnt != now_hist_cnt) { last_hist_cnt = now_hist_cnt; double total_profit = 0; for (i=0; i<now_hist_cnt; i++) { if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) == false) continue; if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue; if (OrderCloseTime() <= last_cnt_time) continue; total_profit += OrderProfit() + OrderSwap() + OrderCommission(); } if (total_profit > 0) { if (win_cnt < 0) win_cnt = 1; else win_cnt++; } if (total_profit < 0) { if (win_cnt > 0) win_cnt = -1; else win_cnt--; } last_cnt_time = TimeCurrent(); }
もしポジションなしで、前回勝敗判定時の取引履歴と異なる場合、 { 取引履歴数を記録しておく。 前回判定時の時間より後に決済されたポジションの損益合計を算出。 もし損益がプラスなら { もしwin_cnt がマイナスならwin_cntに1を代入。 そうでないなら、win_cntに1を足す。 } もし損益がマイナスなら { もしwin_cnt がプラスならwin_cntに-1を代入。 そうでないなら、win_cntから1を引く。 } 判定時間を記録しておく。 }
エントリー注文前にロット数増減をする
UseMMのロット算出の下に、次のコードを追加します。
// 連勝時のロット数 if (win_cnt > 1) lots += lots * 10 * MathMin(win_cnt-1, 10) * 0.01; // 連敗時のロット数 if (win_cnt < -1) lots *= (-1.0 / win_cnt);
UseMMの括弧内の切り捨てやmax_lotなどの補正は、上記コードの下に移動します。
あとがき
最初、連敗時のロット数算出部分を、if (win_cnt < -1) lots *= (-1 / win_cnt);にしていて、ロット数が0になってしまいました。
整数÷整数は切り捨て整数になることを常に意識していないといけないですね^^;
次回は、今回のロット算出法を自作EAに搭載して検証をします。
FXブロガーのための、FX専門ランキング
ポプログ人気fxブログランキングが、装いも新たに
パワーアップしました。
■■■そのユニークな特徴は!?
★総合ランキングに加え、投資スタイル別ランキングが登場!
★ブログをランダムにサムネイルで紹介!ピックアップブログ!
★新着記事をトップページで紹介! 新着ブログ記事リスト!
★自分の順位が一目でわかる! パーソナルランクエリア!
他にも、使いやすい機能が目白押しです!
是非一度みにきてください!
のぞいてみるならこちらから⇒ http://fx.pop-log.com/
■■■上位ランカーを目指すあなたにグッドニュース!
ポプログの順位は、INポイントのみで決まります。
順位が固定されにくく、上位ランクへのチャンスも
広がります。
あなたのブログに、ポプログという新しいドアを
加えてみませんか。
登録はこちらから⇒
http://fx.pop-log.com/register/register.html
(ポプログは全てのコンテンツが無料です)
※ 当ご案内は、FX関連のブログ(サイト)様を訪問し、
同一文章にて書き込みさせていただいております
コメント欄をお借りする失礼も併せ、何卒お許し下さい
ポプログ人気fxブログランキング
http://fx.pop-log.com/
登録させていただきました!
慶次さんこんばんわ!
MT4はすごいですねポジションサイジングまで、できてしまうんですね!
エントリー、仕切り、ポジションサイジング、色々な要素を組み合わせて
良いシステムができるのですね!
次回の記事も楽しみにしております!
たま
こちらでははじめまして、えぎです^^
今このポジションサイジングに興味がありまして、覗かせていただいて勉強させてもらってます。
少し気になるところがあるので質問させてください。
int ilots = AccountBalance() * leverage / 10000;
double lots = ilots * 0.1 ;
これで使用ロットの計算がなされていると思うのですが、例えばleverageが1だとして、使用資金が200000だとすると、この計算だと2になりますよね?
で、metatraderの単位は10万通貨単位ですよね?
ということはlotsが2だと、20万通貨単位を投入してしまうことになりませんか?
疑問に思いコメントさせていただきました。
またおかしな解釈をしているとは思うのですが、ご指南くださいませ。
そうですね。
この場合は、複利システムにする方法と同様、米ドルの口座で米ドル通貨の取引(USDJPY や USDCAD など)において、口座残高に応じて取引額を決定するといった方法です。
円の口座ではまた違った計算になりますね!
あ、そうですね。
ドルでの取引なのですね?
なるほど・・・。
そのあたりを理解してませんでした。
自分、頭が固いです・・・。