ロット数をNormalizeDouble(lots, 2)で丸めているのに、

発注時にエラーが出た、または思っていたロット数と違う発注になった。

そんな経験はないでしょうか。

原因は、NormalizeDoubleが「小数点以下の桁数」を丸める関数であり、

ブローカーが指定する「ロットの刻み値(0.1や0.01)の倍数」に

揃えてくれる関数ではないことにあります。

この記事では、MathRound(四捨五入)とMathAbs(絶対値)という

基礎的な数学関数の使い方と、この2つを組み合わせて

「刻み値の倍数」に丸める方法まで解説します。

この記事で分かること
・MathRound/MathAbsのシグネチャと戻り値の型
・NormalizeDoubleとの役割の違い
・ロット数を刻み値の倍数に丸める計算式
・損切り幅や損失額で絶対値が必要になる理由

MathRound・MathAbsが必要になる場面

まず、この2つの関数がどんな場面で必要になるか確認します。

四捨五入が必要な場面

ロット数の計算結果や、表示用の数値を

扱いやすい形に丸めたいときにMathRoundを使います。

絶対値が必要な場面

売買方向によってプラスとマイナスが入れ替わる数値

(損切り幅や損失額など)を、方向に関係なく扱いたいときにMathAbsを使います。

この記事で扱う内容の概要

関数 役割 戻り値の型
MathRound(value) 最も近い整数に四捨五入する double
MathAbs(value) 符号を外した絶対値を返す double

戻り値がどちらもdouble型である点は、

後の章で説明する落とし穴に関係してきます。

MathRoundの使い方

MathRoundの具体的な使い方を見ていきます。

シグネチャと戻り値がdouble型である点

double MathRound(double value);

引数・戻り値ともにdouble型です。

四捨五入しても「整数」にはなりますが、型は整数(int)ではありません。

整数が欲しい場合のキャスト

int rounded = (int)MathRound(value);

int型の変数へ代入したい場合は、

このように明示的にキャスト(型変換)するか、代入時の暗黙変換に任せます。

0.5の丸め方向は要注意

補足
・MQL4公式リファレンスには「最も近い整数に丸める」としか書かれていません
・0.5のような境界値をどちら方向に丸めるかは明記されていません
・境界値が結果に影響するロジックでは、丸め後の値を必ずPrint()で確認してください

MathAbsの使い方

MathAbsの具体的な使い方を見ていきます。

シグネチャ

double MathAbs(double value);

符号がプラスでもマイナスでも、必ずゼロ以上の値が返ります。

損切り幅の計算での使用例

double slDistance = MathAbs(OrderOpenPrice() - OrderStopLoss());

買い注文か売り注文かによって、

エントリー価格と損切り価格の大小関係は逆になります。

MathAbsを使えば、方向を気にせず「距離」だけを取り出せます。

損失額を絶対値で扱う例

Print("損失額: ", DoubleToString(MathAbs(profit), 2));

含み損はマイナスの数値で表されるため、

ログやアラートの文言として「損失額◯◯円」のように

分かりやすく表示したいときにMathAbsが役立ちます。

NormalizeDoubleとの違いという落とし穴

ここが、この記事で最も伝えたい実務的な落とし穴です。

役割の違いの表

関数 丸める基準 用途
NormalizeDouble 小数点以下の桁数 価格・ロットの表示桁数を整える
MathRound+刻み値計算 任意の数値の倍数 ロットを刻み値の倍数に揃える

NormalizeDoubleは「桁数」を揃えるだけで、

「0.1刻み」のような倍数のルールまでは揃えてくれません。

混同するとどうなるか

注意
・刻み値0.1でNormalizeDouble(0.15,1)を使うと結果があいまいです
・0.15自体が刻み値0.1の倍数ではないため、丸めた後も不正なロットになることがあります
・エラー131(不正なロット)の原因がここにあると気づきにくいです

ロット数計算での正しい組み合わせ方

double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
double lots = MathRound(rawLots / lotStep) * lotStep;

生のロット数(rawLots)を刻み値で割ってMathRoundし、

もう一度刻み値を掛け直すことで、必ず刻み値の倍数になります。

実際に動くコード全体

ロット計算と損切り幅の表示をまとめたスクリプトです。

//+------------------------------------------------------------------+
//|                                  MathRoundAbsDemo.mq4             |
//|                     Copyright 2026, FX-EA System Project Creator  |
//|                        https://creator.fx-ea-system-project.com/  |
//+------------------------------------------------------------------+
#property strict
#property script_show_inputs

input double InpRawLots = 0.17;

void OnStart()
  {
   double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   double minLot   = MarketInfo(Symbol(), MODE_MINLOT);
   double maxLot   = MarketInfo(Symbol(), MODE_MAXLOT);

   double rounded = MathRound(InpRawLots / lotStep) * lotStep;

   if(rounded < minLot)
      rounded = minLot;
   if(rounded > maxLot)
      rounded = maxLot;

   Print("刻み値: ", lotStep, " 丸め前: ", InpRawLots, " 丸め後: ", rounded);

   double entryPrice = Ask;
   double stopPrice  = Ask - 100 * Point;
   double slDistance = MathAbs(entryPrice - stopPrice);

   Print("損切り幅(絶対値): ", DoubleToString(slDistance, Digits));

   double dummyProfit = -1234.5;
   Print("損失額の表示: ", DoubleToString(MathAbs(dummyProfit), 2), "円");
  }

MetaEditorでのコンパイル・実行手順

  1. MetaEditorで新規スクリプト「MathRoundAbsDemo」を作成し、上のコードを貼り付けてコンパイルする
  2. MT4のナビゲーターからチャートへドラッグ&ドロップして実行する
  3. 「エキスパート」タブで刻み値・丸め前・丸め後のロット数が表示されることを確認する
  4. 損切り幅・損失額の表示が両方ゼロ以上の値になっていることを確認する

よくあるエラーと注意点

実際に使うときにつまずきやすいポイントをまとめます。

int型への代入で起きる誤解

MathRoundの戻り値はdouble型なので、

int型の変数へ代入すると自動的に小数部が切り捨てられます。

丸めた後の値をPrint()で確認する習慣をつけてください。

MathAbsとfabsの違い

実践アドバイス
・MQL4公式リファレンスはfabs()を代替として挙げています
・MathAbs・fabsどちらも同じ結果になるため、既存コードとの統一性で選べば十分です
・このサイトの既存記事はMathAbsの表記で統一しています

MQL5での違い

MQL5にもMathRound・MathAbsは同じシグネチャで存在するため、

この記事の考え方はMQL4・MQL5どちらでもそのまま使えます。

よくある質問

MathRound・MathAbsについて、よく検索される疑問に回答します。

MathRoundとMathFloor・MathCeilの違いは何ですか?

MathRoundは四捨五入、MathFloorは小数部を切り捨て、

MathCeilは小数部を切り上げます。

ロットを刻み値の倍数に揃える場面では、

意図的に切り捨てたい場合はMathFloorを使う設計もあります。

NormalizeDoubleはもう使わなくていいですか?

いいえ、価格やロットの表示桁数を整える用途では

NormalizeDoubleは引き続き必要です。

この記事が指摘しているのは、

「桁数を整える」ことと「倍数に揃える」ことは別の処理だという点です。

エラー131(不正なロット)が出たらまず何を確認しますか?

MarketInfo(Symbol(), MODE_LOTSTEP)で刻み値を取得し、

発注直前のロット数がその倍数になっているかをPrint()で確認してください。

【MQL4】MathRound・MathAbsの使い方とロット数を『刻み値の倍数』に丸める応用についてわかりやすく解説してみた:まとめ

MathRoundは四捨五入、MathAbsは絶対値を返す基礎的な関数ですが、

NormalizeDoubleと役割を混同すると、

ロットが刻み値の倍数からズレるという実害につながります。

生のロット数を刻み値で割ってMathRoundし、

もう一度刻み値を掛け直すという組み合わせを覚えておけば、

エラー131のような不正なロットのトラブルを避けやすくなります。

関連記事