今回はMT4の自動売買用EAサンプルソース(FX用)を、プログラミング初心者の方向けに解説しています。
許容できる損失額からエントリーする際のロット数を自動計算する関数となっておりますので、是非使ってみて下さい。
はじめに
今回は、許容できる損失額からロット数を計算する関数について公開します。
エントリー時にストップロスを設定する際、
-30pipsをストップロスにしたけど口座残高の5%分の損失を許容できる場合のロット数はいくつになるんだろう
-30pipsをストップロスにしたけど1万円の損失を許容できる場合のロット数はいくつになるんだろう
と、こういった場合に役に立ちます。
以前、証拠金維持率からロット数を計算する関数を作ったのですが少し切り口を変えた形になります。
証拠金維持率からロット数を計算する関数はこちら↓
ソースコード
以下、関数のサンプルソースです。
許容できる損失額からロット数を計算する関数(許容損失計算関数)です。
//+------------------------------------------------------------------+
//|【関数】許容損失額に対してのロット数を取得する
//|
//|【引数】Type:0か1(0:% 1:額)Pips:ストップロスのPips(50=50pips) PerSec:許容損失額(5% 50000円等)
//|
//|【戻値】ロット数(1000通貨=0.01)
//|
double funcLotGet(int Type,double Pips,double PerSec)
{
double RiyouGaku=0,SaidaiLot=0,KouzaMoney=0,Kekka=0;
if(Pips == 0){
Print("ストップロス値が設定されていません");
return(0);
}
//最大ロット数確認
double server_Lot = MarketInfo(Symbol(),MODE_MAXLOT);
if(SaidaiLot == 0 || SaidaiLot > server_Lot){
SaidaiLot = server_Lot;
}
//口座残高(余剰証拠金)
KouzaMoney = AccountInfoDouble(ACCOUNT_FREEMARGIN);
if(Type == 0){
//利用可能金額算出
RiyouGaku = NormalizeDouble(KouzaMoney * (PerSec / 100),0);
}else{
//利用可能金額算出
RiyouGaku = PerSec;
}
Print("余剰証拠金:" + DoubleToString(KouzaMoney,0) + " 利用可能金額:" + DoubleToString(RiyouGaku,0));
//通貨ペア取得
string Tuuka = Symbol();
//通貨ペア名称保持
int MojiCnt = StringLen(Tuuka);
string subMoji = "";
if(MojiCnt > 6){
subMoji = StringSubstr(Tuuka, 6, MojiCnt - 6);
}
//クロス円
if(StringFind(Tuuka, "JPY",0) != -1){
//ロット数計算
Kekka = RiyouGaku / Pips /1000;
//ドルストレート
}else if(StringFind(Tuuka, "USD",3) != -1){
//double Nedan = MarketInfo("USDJPY"+subMoji, MODE_ASK);
double Nedan = iOpen("USDJPY"+subMoji,PERIOD_CURRENT,0);
//ロット数計算
Kekka = RiyouGaku / Pips / Nedan / 10;
}else if(Tuuka == "GOLD" || Tuuka == "goldmicro" || Tuuka == "GOLDmicro"){
double Nedan1 = iOpen("USDJPY"+subMoji,PERIOD_CURRENT,0);
//ロット数計算
Kekka = RiyouGaku / Pips / Nedan1 / 10;
}else{
Print("計算対象外通貨です:"+Tuuka);
return(0);
}
//少数点を0.01単位までにする
Kekka = NormalizeDouble(Kekka, 2);
//最大ロット数を超えている場合は、最大ロット数にする
if(Kekka > SaidaiLot){
Kekka = SaidaiLot;
}
return Kekka;
}
解説
引数
引数1はタイプです。タイプ1は需要があるかわかりませんがお好みで設定してください。
- 0の場合 ➡ 余剰証拠金から許容できる損失額をパーセンテージで計算するタイプ(引数3は%で渡す)
- 1の場合 ➡ 引数3に直接損失額を直打ちするタイプ(引数3は金額で渡す)
引数2はストップロス(Pips)です。エントリー時にストップロスを何Pipsに設定するかの際の値を渡すようにしてください
(例)20Pipsの場合は、20を渡す
引数3は許容損失額です。引数1でも説明しましたが、余剰証拠金から許容できる損失額をパーセンテージで渡してください。
- 引数1が0だった場合 ➡ 余剰証拠金から許容できる損失額をパーセンテージで渡す
- 引数1が1だった場合 ➡ 引数3は直接損失許容金額で渡す
例
以下、状況別の引数の例です。
余剰証拠金が50万円あり、1トレード10%(5万円)失ってもいい場合でストップロスは30Pips
↓
funcLotGet(0,30,10)
1トレード7万円失ってもいい場合でストップロスは50Pips
↓
funcLotGet(1,50,70000)
タイプによって引数3の数値の意味合いが変わるのは少し気持ち悪いですが、汎用性を意識しています。
戻り値
許容損失額に応じた、ロット数を返します。 ※1=10万通貨
(ブローカーによる最大ロットをオーバーしている場合は、ブローカーの最大ロット数になります)
また、ストップロス値が設定されていない場合や対円・ドルストレート以外(AUDCAD、GBPNZD等)の場合は0を返しています。
処理内容
まず自分の口座の口座残高(余剰証拠金)を取得し、引数3の許容損失額(%)を使って利用可能金額を算出しています。
Kekka = NormalizeDouble(KouzaMoney * (PerSec / 100),0);
↓
(利用可能金額:50,000)= (余剰証拠金:500,000) * (許容損失額:0.1 )
次に、対円なのかドルストレートかで計算方法が変わってくるので通貨ペアの確認をしています。
対円の場合は計算は簡単ですが、ドルストレートの場合はドル/円の値段が必要になってきます。
※補足情報・・・MarketInfo(Tuuka, MODE_ASK)でドル値段を取得してもよかったのですが、バックテストで値が取れないためiOpen()で開始値を取得しています。
最後に、ロット数の確認をし最大ロット数を超えている場合は最大ロット数にしています。
許容損失計算関数の使用例
// 新規エントリー注文
int CNo = OrderSend(
NULL, // 通貨ペア
OP_BUY, // オーダータイプ[OP_BUY / OP_SELL]
funcLotGet(0,20,10), // ロット[0.01単位](10%損失許容)
Ask, // オーダープライスレート
・・・
OrderSend()関数のロット数のところに書き込む感じです。あとは、funcLotGet()関数をソース内にそのまま貼り付けてください。

使用した結果はこんな感じで、履歴は下から上へ流れているので余剰証拠金が50万円あり、1トレード10%(50,000円)失っても良い場合(ストップロスは30Pips)のロット数は1.67という事がわかりますね。
で、このトレードはストップロスになり50,100円失い余剰証拠金が449,900円になったため、次回のトレードの10%(44,990円)失っても良い場合(ストップロスは30Pips)のロット数は1.50という事がわかります。
その他注意点
今回の関数は、価格差益のみの計算となっておりスワップポイントのマイナスやプラス分までは考慮されていません。
主な使用関数
MarketInfo()
マーケット情報を返す。
MarketInfo(Symbol(),MODE_MAXLOT));でそのブローカーの取引通貨の最大ロット数を取得します。
AccountInfoDouble()
アカウント情報を返す。
AccountInfoDouble(ACCOUNT_FREEMARGIN)を使って自分の口座の余剰証拠金を取得します。
NormalizeDouble()
少数点以下の桁数を四捨五入した値を返す。
NormalizeDouble(x, 0)で小数点を四捨五入し整数にした値を取得します。
StringFind()
文字列検索。
見つかったワードが開始される文字列位置を返します。
見つからなかった場合は-1を返します。
さいごに
以上、許容できる損失額からロット数を計算する処理となります。
今回は読者さんからの要望でしたが、自分の普段考えていないロット数計算だったため新鮮でした。
また、対円・ドルストレート以外の計算(AUDCAD、GBPNZD等)も対応したいと思います。
※ EAのサンプルソース一覧表へ
コメント
さっそく記事にしてくださって、ありがとうございます!
今日もMQLの勉強をしていますが、本当にいつも参考にさせていただいております。
これからもよろしくお願いします!
MQLの勉強頑張ってくださいね!
こちらこそよろしくお願いします!
お世話になっております。
以前に、教えていただいた許容損失額によってロットサイズが変動する関数を使用して決まった時間に取引するコードを書いてみました。
しかし、爆テストするとロット数量が1.00のままでどこが原因か自分では理解に及んでいません。
もし可能でしたら、ご教授お願いいたしますm(__)m
//+——————————————————————+
//| TokyoTime.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 A_SPREAD = 10; //エントリー及び決済時に許容するスプレッドの値です(10 = 10pips)
~
//口座残高(余剰証拠金)
KouzaMoney = AccountInfoDouble(ACCOUNT_FREEMARGIN);
if(Type == 0){
//利用可能金額算出
RiyouGaku = NormalizeDouble(KouzaMoney * (PerSec / 100),0);
}else{
//利用可能金額算出
RiyouGaku = PerSec;
}
Print(“余剰証拠金:” + DoubleToString(KouzaMoney,0) + ” 利用可能金額:” + DoubleToString(RiyouGaku,0));
//通貨ペア取得
string Tuuka = Symbol();
//通貨ペア名称保持
int MojiCnt = StringLen(Tuuka);
string subMoji = “”;
if(MojiCnt > 6){
subMoji = StringSubstr(Tuuka, 6, MojiCnt – 6);
}
//クロス円
if(StringFind(Tuuka, “JPY”,0) != -1){
//ロット数計算
Kekka = RiyouGaku / Pips /1000;
//ドルストレート
}else if(StringFind(Tuuka, “USD”,3) != -1){
//double Nedan = MarketInfo(“USDJPY”+subMoji, MODE_ASK);
double Nedan = iOpen(“USDJPY”+subMoji,PERIOD_CURRENT,0);
//ロット数計算
Kekka = RiyouGaku / Pips / Nedan / 10;
}else{
Print(“計算対象外通貨です:”+Tuuka);
return(0);
}
//少数点を0.01単位までにする
Kekka = NormalizeDouble(Kekka, 2);
//最大ロット数を超えている場合は、最大ロット数にする
if(Kekka > SaidaiLot){
Kekka = SaidaiLot;
}
return Kekka;
}
お世話になっております。
ソースコードをコピペしてみたところ、文字列がトリミングされているかなにかでうまい事コンパイルできませんでした。
ですのでソースコードをざっと見た感じでお伝えしますと、
まず、『lotSize = funcLotGet(0, stopLossPips, 2);』でlotSize変数にロット数をセットしています。
その後、『OrderKekka = funcOrder_Send(orderPtn – 1, ea_order_stop_price, 0, lotSize, 0);』
で引数にもlotSize変数があり、ロット数を新規注文関数側に引き渡している所まではOKです。
※ただここも引数が1つ少ないですが取り合えず保留
ただし、新規注文関数(funcOrder_Send)に問題点が2点あります。
●1つ目
『bool funcOrder_Send(int ea_order_entry_Type, double ea_order_stop_price, double ea_order_good_price,int orderComment,int ea_order_MagicNo)
{』
ここでロット数を引き取れていないのでロット数が新規注文関数で分からない状態になっています。
●2つ目
新規注文関数(funcOrder_Send)内の、OrderSend()関数のロット数の部分(3つ目の引数)が1固定になっています。
ここは、lotSize変数の値にしてあげる必要があります。
簡単に修正方法です。
【修正方法①】
[OrderKekka = funcOrder_Send(orderPtn – 1, ea_order_stop_price,]でソースコード検索する。
ヒットした箇所を以下のように不足している引数を追加する。
OrderKekka = funcOrder_Send(orderPtn – 1, ea_order_stop_price, 0, 0,lotSize, 0);
【修正方法②】
[bool funcOrder_Send(]でソースコード検索する。
ヒットした箇所を以下のようにロットサイズ引数を追加する。
bool funcOrder_Send(int ea_order_entry_Type, double ea_order_stop_price, double ea_order_good_price,int orderComment,double ea_lotSize,int ea_order_MagicNo)
【修正方法③】
[// ロット[0.01単位](FXTFは1=10Lot)]でソースコード検索する。
ヒットした箇所を以下のようにea_lotSize値を反映する。
ea_lotSize, // ロット[0.01単位](FXTFは1=10Lot)
こんな感じでいけると思います。
ご丁寧な返信ありがとうございます!
できました!嬉しいです(‘◇’)ゞ
はじめまして。
非常に参考になる記事を有難うございます!
固定損失額からのロット計算はまさに今やりたいことで、こちらを参考に取り組んでいるのですが、本文ソースコード内で何点かお教え下さいませんでしょうか。
>>43行目 : string subMoji = “”;
通貨ペア名称保持と説明が入っていますが、こちらの一行はどのような処理をされているのでしょうか?
subMojiに””という文字列を保持???
>>57行目 : double Nedan = iOpen(“USDJPY”+subMoji,PERIOD_CURRENT,0);
iOpen関数一つ目の引数で「USDJPY」ではなく「”USDJPY”+subMoji」とされているのはどういう狙いでしょうか?
お手すきの際にご返答頂けると幸いです!
とくろさん
初めまして、記事を参考にして頂き有難うございます!
ご質問の件ですが、以下回答します。
>>43行目 : string subMoji = “”;
ここは、subMojiというstring(文字列型)の変数を宣言しております。
その後“”となっているのは何も入れていません(空)というのをあえて明記しています。
理由は次に疑問になっている箇所です。
>>57行目 : double Nedan = iOpen(“USDJPY”+subMoji,PERIOD_CURRENT,0);
ここで
「USDJPY」としていない理由としましては、「USDJPY」で取得できないブローカー
(FXTFはUSDJPY-cd,OANDAはUSDJPY.oj1m等)が存在するためです。
上記ブローカーは「USDJPY-cd」といった通貨名称でiOpen()しなければ米ドル/円の価格を取得できません。
ただし、XM等は「USDJPY」で取得できます。
※MT4画面で「USDJPY」となっているブローカーは取得可能
ですので、45行目~47行目で文字数が6文字を超える通貨名称の場合はsubMoji変数に6文字目以降の文字列を格納しています。
if(MojiCnt > 6){
subMoji = StringSubstr(Tuuka, 6, MojiCnt – 6);
}
FXTFだとsubMoji変数にはEURUSD(-cd)とカッコ内の値がセットされます。
※XMは6文字なので初期値(“”)のままです
そして57行目でそれをくっつけて価格を取得しにいくという作りになっております。
●FXTFだと iOpen(“USDJPY”+subMoji(-cd),PERIOD_CURRENT,0);
●XMだと iOpen(“USDJPY”+subMoji(“”),PERIOD_CURRENT,0);
少々ややこしいので不明点等あれば再度ご質問ください。
なるほどです!
この記述なら様々なブローカーに対応可能ですね。
勉強になりました。
大変ご丁寧に有り難うございます!
いつも勉強させていただいております。
この関数を、ゴールドで使用したいのですがどう書き換えればよいのでしょうか?
らいらいさん
記事を参考にして頂き有難うございます!
記事のソースコードを修正(60~63行目)しましたので参考にしてみてください。
元々はゴールドの名称がXAUUSDの通貨ペアであれば使えていたのですが、
XM等ではXAUUSDではなくGOLDやGOLDmicr表記でしたのでうまく動きませんでした。