EAの含み損益を記録するインジケーター
MT4などのプラットフォームでEAを運用する場合、「口座履歴」で詳細レポートを保存すると運用実績を確認できます。
口座残高の推移については、以下のようにグラフで表示されます。

このグラフだけを見ると、右肩上がりで優秀なEAに見えます。
しかしながら、実際に運用してみた人はわかると思いますが、特にナンピンやマーチンゲールを多用する爆益型のEAの場合は含み損益が重要なファクターになります。
含み損が口座残高を下回ればロスカットになってしまうわけなので、上図のように右肩上がりのグラフを見て「このEAは使える!」と思って運用したらあっさり破綻した経験のある人も多いはず。これは「EAあるある」と言えるでしょう。
この「含み損益」に関しては口座履歴では確認できませんし、後から算出することも困難です。
そこで、含み損益をリアルタイムで記録するインジケーターを作成してみました。
//+------------------------------------------------------------------+
//| AccountProfit_Record.mq4 |
//| Copyright 2026, iNak Engineering, LLC |
//| https://inak-eng.jp/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, iNak Engineering, LLC"
#property link "https://inak-eng.jp/"
#property version "1.00"
#property strict
#property indicator_chart_window
input string filename = "ProfitData"; //Output CSV File Name
int oldBars = 0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
oldBars = Bars;
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//---
bool ret_us = DST_US();
bool ret_eu = DST_EU();
datetime JS_Time;
if(ret_us == true){
if(ret_eu == true){
JS_Time = TimeGMT() + 8 * 3600;
}else{
JS_Time = TimeGMT() + 9 * 3600;
}
}else{
if(ret_eu == true){
JS_Time = TimeGMT() + 8 * 3600;
}else{
JS_Time = TimeGMT() + 9 * 3600;
}
}
int newBars = Bars;
if(newBars == oldBars) return(rates_total);
int year = TimeYear(JS_Time);
int month = TimeMonth(JS_Time);
int day = TimeDay(JS_Time);
string output_filename = filename + StringFormat("%04d", year) + StringFormat("%02d", month) + StringFormat("%02d", day) + ".csv";
bool File_Exist = FileIsExist(output_filename,0);
if(File_Exist == false){
int handle = FileOpen(output_filename, FILE_READ | FILE_WRITE | FILE_CSV, ",");
FileWrite(handle, "DateTime,Balance,Credit,Equity,Margin,FreeMargin,StopoutLevel,Profit,Balance+Credit,Balance+Credit+Profit");
FileWrite(handle, "日付時刻,口座残高,クレジット,有効証拠金,必要証拠金,余剰証拠金,証拠金維持率,損益,口座残高+クレジット,口座残高+クレジット+損益");
FileClose(handle);
}
double Account_StopoutLevel;
double Account_Equity = AccountEquity();
double Account_Margin = AccountMargin();
double Account_Profit = AccountProfit();
if(Account_Margin == 0){
Account_StopoutLevel = 0;
}else{
Account_StopoutLevel = Account_Equity / Account_Margin * 100;
}
int handle = FileOpen(output_filename, FILE_READ | FILE_WRITE | FILE_CSV, ",");
FileSeek(handle,0, SEEK_END);
FileWrite(handle, TimeToString(JS_Time, TIME_DATE | TIME_MINUTES),
DoubleToString(AccountBalance(), 0),
DoubleToString(AccountCredit(), 0),
DoubleToString(Account_Equity, 0),
DoubleToString(Account_Margin, 0),
DoubleToString(AccountFreeMargin(), 0),
DoubleToString(Account_StopoutLevel, 2) + "%",
DoubleToString(Account_Profit, 0),
DoubleToString(AccountBalance() + AccountCredit(), 0),
DoubleToString(AccountBalance() + AccountCredit() + Account_Profit, 0));
FileClose(handle);
oldBars = newBars;
return(rates_total);
}
bool DST_US()
{
// アメリカ夏時間は true、冬時間は false を返す
bool ret = false;
datetime DST_Start;
datetime DST_End;
datetime Local_Time = TimeCurrent();
//サマータイム開始日(3/14の前の日曜日)
DST_Start = StringToTime(IntegerToString(Year()) + ".03.14");
DST_Start = DST_Start - TimeDayOfWeek(DST_Start) * 24 * 60 * 60;
//サマータイム終了日(11/7の前の日曜日)
DST_End = StringToTime(IntegerToString(Year()) + ".11.07");
DST_End = DST_End - TimeDayOfWeek(DST_End) *24 * 60 * 60;
if(Local_Time > DST_Start && Local_Time < DST_End) ret = true;
return ret;
}
bool DST_EU()
{
// ヨーロッパ夏時間は true、冬時間は false を返す
bool ret = false;
datetime DST_Start;
datetime DST_End;
datetime Local_Time = TimeCurrent();
//サマータイム開始日(3/31の前の日曜日)
DST_Start = StringToTime(IntegerToString(Year()) + ".03.31");
DST_Start = DST_Start - TimeDayOfWeek(DST_Start) * 24 * 60 * 60;
//サマータイム終了日(10/31の前の日曜日)
DST_End = StringToTime(IntegerToString(Year()) + ".10.31");
DST_End = DST_End - TimeDayOfWeek(DST_End) *24 * 60 * 60;
if(Local_Time > DST_Start && Local_Time < DST_End) ret = true;
return ret;
}
//+------------------------------------------------------------------+
前の記事で紹介した「アメリカとヨーロッパの夏時間/冬時間を判定するMQL4コード」をそのまま使用しているため、少し冗長になっています。
本来はアメリカ夏時間の判定は必要ないので「DST_US」は不要ですが、何か加工したい人がいるかもしれないので残してあります。
上記コードをメタエディターでコンパイルすれば使用できるようになりますが、面倒な人は以下からダウンロードして下さい。
このインジケーターをMT4チャートに適用すると、以下の項目がcsvファイルに出力されます。ロウソク足が確定したときに出力されるため、チャートが1時間足であれば1時間おき、1分足であれば1分おきの出力になります。
- 日付時刻
- 口座残高
- クレジット
- 有効証拠金
- 必要証拠金
- 余剰証拠金
- 証拠金維持率
- 損益
- 口座残高+クレジット
- 口座残高+クレジット+損益
ファイルの出力場所は「MQL4」フォルダー内の「Files」フォルダーで、「損益」に含み損益が記録されています。ファイル名はパラメーターの「Output CSV File Name」で指定できます。
csvファイルは1日ごとになっており、日本時間の午前0時に新しいファイルが作成されます。
例として、ローリスクローリターン型のEAで記録してみた口座残高と含み損益の履歴は下のグラフの通りとなります。横軸の期間は2週間。

縦軸を拡大すると、この期間の含み損は最大で約1万7千円ほど。初期資金10万円で数ヶ月間運用しているEAで、たしかにローリスクだと確認できます。

続いて、こちらはナンピンとマーチンゲールを多用するハイリスクハイリターン型EAの例。横軸の期間は3日。

運用途中で破綻しています。もちろん破綻したから駄目なEAというわけではなく、こういうタイプは「利益をこまめに他の口座に移し、破綻したら資金を戻してトータルでプラスになるような運用」が基本ですから、資金管理次第で爆益になります。
このEAですが、一時的に含み損が大きくなっていたことが確認できていたので、その時点でしばらく運用を止めるという判断もあったかもしれません。

このインジケーターは、EAを運用する際の判断基準として「最低ロットで一定期間運用し、最大含み損を確認してから実際の運用ロットを決定」みたいに様々な使い方ができると思うので、興味があれば使用してみて下さい。


