ロット数を入力して、そのまま`OrderSend()`や`CTrade::Buy()`を呼んでいませんか。
注文が拒否されてから証拠金不足に気づく設計では、EAのログに失敗だけが残り、
想定していた売買機会を逃します。
MQL5では`OrderCalcMargin()`で必要証拠金、
`OrderCalcProfit()`で指定価格まで動いた場合の損益を、
注文前に口座通貨で試算できます。
この記事では、買い注文を例に「このロットを建てるのに証拠金はいくら必要か」
「損切り・利確まで動いたら何円相当か」を同時に表示するスクリプトを作ります。
2つの関数が計算するもの
bool OrderCalcMargin( ENUM_ORDER_TYPE action, string symbol, double volume, double price, double& margin ); bool OrderCalcProfit( ENUM_ORDER_TYPE action, string symbol, double volume, double price_open, double price_close, double& profit );
どちらも成功時は`true`を返し、計算結果を最後の参照引数へ書き込みます。
結果は口座通貨建てです。
円口座なら円、ドル口座ならドルで表示されるため、銘柄ごとの契約サイズを手計算するより安全です。
`OrderCalcProfit()`で指定できる注文種別は`ORDER_TYPE_BUY`または`ORDER_TYPE_SELL`です。
買いの損失を計算するなら、始値より低い価格を`price_close`へ渡します。
重要な制約:計算できても発注できるとは限らない
`OrderCalcMargin()`は、現在の未決済ポジションや保留中注文がないものとして必要証拠金を計算します。
ヘッジ・ネットティング方式、既存ポジション、証拠金率の変化まで含めた最終的な発注可否を保証する関数ではありません。
実務では次の二段階に分けます。
- `OrderCalcMargin()`で予定注文単体の概算を取得する
- `ACCOUNT_MARGIN_FREE`と比較して余裕を確認し、実際の発注結果も必ず検査する
必要証拠金と損切り・利確時の損益を表示するコード
//+------------------------------------------------------------------+
//| PreTradeCalculator.mq5 |
//+------------------------------------------------------------------+
#property script_show_inputs
input double Lots = 0.10;
input int StopLossPoints = 300;
input int TakeProfitPoints = 600;
input double SafetyRate = 1.20;//必要証拠金に持たせる余裕
void OnStart()
{
if(Lots <= 0 || StopLossPoints <= 0 || TakeProfitPoints <= 0)
{
Print("入力値は0より大きくしてください");
return;
}
MqlTick tick={};
if(!SymbolInfoTick(_Symbol,tick))
{
Print("価格取得失敗: ",GetLastError());
return;
}
double openPrice = tick.ask;
double stopPrice = NormalizeDouble(openPrice-StopLossPoints*_Point,_Digits);
double takePrice = NormalizeDouble(openPrice+TakeProfitPoints*_Point,_Digits);
double margin=0.0, loss=0.0, profit=0.0;
ResetLastError();
if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,Lots,openPrice,margin))
{
Print("必要証拠金の計算失敗: ",GetLastError());
return;
}
if(!OrderCalcProfit(ORDER_TYPE_BUY,_Symbol,Lots,openPrice,stopPrice,loss) ||
!OrderCalcProfit(ORDER_TYPE_BUY,_Symbol,Lots,openPrice,takePrice,profit))
{
Print("損益の計算失敗: ",GetLastError());
return;
}
double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
double requiredWithBuffer = margin*SafetyRate;
string currency = AccountInfoString(ACCOUNT_CURRENCY);
PrintFormat("%s %.2f lot / 必要証拠金 %.2f %s / 余裕込み %.2f / 余剰証拠金 %.2f",
_Symbol,Lots,margin,currency,requiredWithBuffer,freeMargin);
PrintFormat("損切り時 %.2f %s / 利確時 %.2f %s / 判定 %s",
loss,currency,profit,currency,
freeMargin>=requiredWithBuffer ? "概算上は余裕あり" : "証拠金不足の可能性");
}
`StopLossPoints`はpipsではなくpointです。
5桁表示のFX通貨ペアでは一般に10 pointが1 pipですが、
銘柄やブローカーで異なるため、入力値を固定観念で決めないでください。
MetaEditorでの実行手順
- MT5からMetaEditorを開き、「新規作成」→「スクリプト」を選ぶ
- 名前を`PreTradeCalculator`にし、上のコードへ置き換える
- F7でコンパイルし、エラーと警告が0件であることを確認する
- スクリプトを対象銘柄のチャートへドラッグする
- 「エキスパート」タブで必要証拠金・想定損益・判定を確認する
値がおかしいときの確認点
- 損失が正数になった:買いなのに損切り価格を始値より上へ設定していないか
- 金額が想定より大きい:`Lots`とpoint/pipの単位を混同していないか
- 関数が`false`を返す:気配値が取得できる銘柄か、`GetLastError()`の値を確認する
- 概算上は余裕ありでも注文が失敗する:既存ポジションや取引条件を含む最終判定ではない
まとめ
`OrderCalcMargin()`と`OrderCalcProfit()`を組み合わせると、
発注前に必要証拠金と損益シナリオを同じ口座通貨で確認できます。
ただし、これは予定注文の事前試算です。
余剰証拠金との比較に安全率を持たせ、注文送信後の戻り値・リターンコード確認までを一連の処理として実装してください。
コメント