イベント処理

OnStart

この関数はStartイベントの発生時にスクリプトとサービスで呼び出されます。この関数は、プログラムに実装されているアクションの1回限りの実行を目的としています。関数には2種類あります。

結果を返すバージョン

int  OnStart(void);

戻り値

操作ログタブで表示されるint型の値。

スクリプトの実行が完成すると「script script_name removed (result code N)」というエントリがターミナルの操作ログに作成されます。ここで、NはOnStart()関数によって返される値です。

サービスの実行が完了すると、エントリ「service service_name stopped (result code N)」がターミナル操作ログに作成されます。ここで、NはOnStart()関数によって返される値です。

実行結果を返すOnStart()の呼び出しは、スクリプトまたはサービスの実行を許可するだけでなく、プログラムの実行結果を分析するためのエラーコードまたはその他の有用なデータも返すため、使用をお勧めします。

結果を返さないバージョンは古いコードとの相互性の為のみに残されています。使用は推奨されません。

void  OnStart(void);

注意事項

OnStart()はスクリプトおよびサービス内のイベントを処理するための唯一の関数です。これらのプログラムに他のイベントは送信されません。その結果、StartイベントはEAおよびカスタム指標には渡されません。

スクリプトの例:

//— 色を使うためのマクロ
#define XRGB(r,g,b)    (0xFF000000|(uchar(r)<<16)|(uchar(g)<<8)|uchar(b))
#define GETRGB(clr)    ((clr)&0xFFFFFF)
//+——————————————————————+
//| スクリプトプログラムを開始する関数                                          |
//+——————————————————————+
void OnStart()
{
//— 下降ローソク足の色を設定する
Comment(“Set a downward candle color”);
ChartSetInteger(0,CHART_COLOR_CANDLE_BEAR,GetRandomColor());
ChartRedraw(); // 新しいティックを待たずにチャートをすぐに更新する
Sleep(1000);   // すべての変更を表示するために1秒間一時停止する
//— 上昇ローソク足の色を設定する
Comment(“Set an upward candle color”);
ChartSetInteger(0,CHART_COLOR_CANDLE_BULL,GetRandomColor());
ChartRedraw();
Sleep(1000);
//— 背景色を設定する
Comment(“Set the background color”);
ChartSetInteger(0,CHART_COLOR_BACKGROUND,GetRandomColor());
ChartRedraw();
Sleep(1000);
//— 買値線の色を設定する 
Comment(“Set color of Ask line”);
ChartSetInteger(0,CHART_COLOR_ASK,GetRandomColor());
ChartRedraw();
Sleep(1000);
//— 売値線の色を設定する 
Comment(“Set color of Bid line”);
ChartSetInteger(0,CHART_COLOR_BID,GetRandomColor());
ChartRedraw();
Sleep(1000);
//— 下向きバーと下向きローソク足フレームの色を設定する
Comment(“Set color of a downward bar and a downward candle frame”);
ChartSetInteger(0,CHART_COLOR_CHART_DOWN,GetRandomColor());
ChartRedraw();
Sleep(1000);
//— チャートの線と同時ローソク足の色を設定する
Comment(“Set color of a chart line and Doji candlesticks”);
ChartSetInteger(0,CHART_COLOR_CHART_LINE,GetRandomColor());
ChartRedraw();
Sleep(1000);
//— 上向きバーと上向きローソク足フレームの色を設定する  
Comment(“Set color of an upward bar and an upward candle frame”);
ChartSetInteger(0,CHART_COLOR_CHART_UP,GetRandomColor());
ChartRedraw();
Sleep(1000);
//— 軸、スケール、OHLCラインの色を設定する
Comment(“Set color of axes, scale and OHLC line”);
ChartSetInteger(0,CHART_COLOR_FOREGROUND,GetRandomColor());
ChartRedraw();
Sleep(1000);
//— グリッドの色を設定する
Comment(“Set a grid color”);
ChartSetInteger(0,CHART_COLOR_GRID,GetRandomColor());
ChartRedraw();
Sleep(1000);
//— 直近値の色を設定する
Comment(“Set Last price color”);
ChartSetInteger(0,CHART_COLOR_LAST,GetRandomColor());
ChartRedraw();
Sleep(1000);
//— ストップロスおよびテイクプロフィット注文値の色を設定する
Comment(“Set color of Stop Loss and Take Profit order levels”);
ChartSetInteger(0,CHART_COLOR_STOP_LEVEL,GetRandomColor());
ChartRedraw();
Sleep(1000);
//— ボリュームとマーケットエントリーレベルの色を設定する
Comment(“Set color of volumes and market entry levels”);
ChartSetInteger(0,CHART_COLOR_VOLUME,GetRandomColor());
ChartRedraw();
}
//+——————————————————————+
//| ランダムに生成された色を返す                                             |
//+——————————————————————+
color GetRandomColor()
{
color clr=(color)GETRGB(XRGB(rand()%255,rand()%255,rand()%255));
return clr;
}

参照

Event handling functions、Program running、Client terminal events

OnInit

この関数は、Initイベントが発生するときに指標やEAで呼び出され、実行中のMQL5プログラムを初期化するのに使用されます。この関数の型は 2 つあります。

結果を返すバージョン

int  OnInit(void);

戻り値

int型の値、ゼロは正常な初期化

実行結果を返すOnInit()を呼び出すと、プログラムを初期化できるだけでなく、プログラムが異常に終了した場合にはエラーコードが返されるため、これを使用することをお勧めします。

結果を返さないバージョンは古いコードとの相互性の為のみに残されています。使用は推奨されません。

void OnInit(void);

注意事項

Initイベントは、EAまたは指標を読み込んだ直後に生成されます。このイベントはスクリプトでは生成されません。OnInit()関数は、MQL5プログラムを初期化するために使用されます。OnInit()の戻り値がint型の場合、ゼロ以外の戻り値は初期化が失敗したことを示し、DeinitイベントをREASON_INITFAILED初期化解除の理由コードで作成します。

void型のOnInit()関数は常に初期化が成功したことを示すので、使用は推奨されません。

EAの入力を最適化するために、リターンコードとしてENUM_INIT_RETCODE列挙体からの値を使用することがおすすめです。これらの値は、最も適切なテストエージェントの選択などの最適化プロセス管理を確立するためのものです。テストを始める前に、EAの初期化中にTerminalInfoInteger()関数を使用して、エージェントの設定とリソース(コア数、空きメモリ量など)のデータをリクエストすることができます。 取得したデータに基づいて、テストエージェントの使用を許可するか、EAの最適化を禁止することができます。

ID

説明

INIT_SUCCEEDED

初期化が成功し、EAのテストを続けることが出来ます。

このコードはゼロ値と同じ意味を持ちます。EAはテスター内で正常に初期化されています。

INIT_FAILED

初期化が失敗しました。致命的なエラーが起こったのでテストを続ける理由がありません。たとえば、EAの操作に必要な指標を作成することは不可能です。

この戻り値はゼロ以外の値と同じ意味です。 テスター内でのEAの初期化は失敗しました。

INIT_PARAMETERS_INCORRECT

プログラマーの間違った入力パラメータを示すように設計されています。一般最適化テーブルでは、この戻りコードを含む結果文字列が赤で強調表示されます。

このようなEA入力セットのテストは実行されません。エージェントは新しいタスクを受け取る用意ができています。

この値を受け取ると、ストラテジーテスターはこのタスクを他のエージェントに再試行のために渡しません。

INIT_AGENT_NOT_SUITABLE

初期化時にプログラム実行エラーはありませんでしたが、エージェントが何らかの理由でテストに適していません。例えば、RAM不足、OpenCLサポートがないなどです。

このコードが返された後は、エージェントは この最適化が終了するまでタスクを受信しません。

OnInit()を使用してテスターでINIT_FAILED/INIT_PARAMETERS_INCORRECTを返すと、EAの最適化の際に考慮されるべきことがあります。

  • OnInit()がINIT_PARAMETERS_INCORRECTを返すのに使用したパラメータはテストには不向きとみなされ、遺伝的最適化では次世代の取得には使用されません。最適なEAパラメータを検索する際に、「廃棄された」パラメータセットが多すぎると誤った結果につながる可能性があります。検索アルゴリズムでは、最適化基準関数は滑らかで、多数の入力パラメータにギャップがないと仮定しています。
  • OnInit()がINIT_FAILEDを返した場合、これはテストを起動できないことを意味するため、EAはエージェントのメモリからアンロードされます。EAは新しいパラメータのセットで次のパスを実行するために再び読み込まれます。次の最適化パスを起動すると、TesterStop()を呼び出すよりもはるかに時間がかかります。

EAのOnInit()関数の例

//— 入力パラメータ
input int     ma_period=20; // 移動平均期間

//— EAで使用される指標のハンドル
int indicator_handle;
//+——————————————————————+
//| エキスパート初期化関数                                                 |
//+——————————————————————+
int OnInit()
{
//— check ma_period validity
if(ma_period<=0)
{
PrintFormat(“Invalid ma_period input value: %d”,ma_period);
return (INIT_PARAMETERS_INCORRECT);
}
//— 最適化中
if(MQLInfoInteger(MQL_OPTIMIZATION))
{
//— エージェントが利用できるRAMを確認する
int available_memory_mb=TerminalInfoInteger(TERMINAL_MEMORY_TOTAL);
if(available_memory_mb<2000)
{
PrintFormat(“Insufficient memory for the test agent: %d MB”,
available_memory_mb);
return (INIT_AGENT_NOT_SUITABLE);
}
}
//— 指標を確認する
indicator_handle=iCustom(_Symbol,_Period,“My_Indicator”,ma_period);
if(indicator_handle==INVALID_HANDLE)
{
PrintFormat(“Failed to generate My_Indicator handle. Error code %d”,
GetLastError());
return (INIT_FAILED);
}
//— EA初期化完了
return(INIT_SUCCEEDED);
}

参照

OnDeinit, Event handling functions、Program running、Client terminal events、Initialization of variables、Creating and deleting objects

OnDeinit

この関数はDeinitイベントが発生するときに指標やEAで呼び出され、実行中のMQL5プログラムの初期化を解除するのに使用されます。

void OnDeinit(
const int  reason        // 初期化解除の理由コード
);

パラメータ

reason

[in]  初期化解除の理由コード

戻り値

なし

注意事項

以下の場合、DeinitイベントがEAと指標に生成されます。

  • MQL5 プログラムが接続されているシンボルまたはチャートの期間の変更に伴う再初期化の前
  • 入力の変更に伴う再初期化の前
  • MQL5プログラムをアンロードする前

reasonパラメータには下記の値を含むことができます。

定数

説明

REASON_PROGRAM

0

ExpertRemove()関数の呼び出しでEAが作動しなくなった

REASON_REMOVE

1

プログラムがチャートから削除された

REASON_RECOMPILE

2

プログラムが再コンパイルされた

REASON_CHARTCHANGE

3

シンボルまたはチャート期間が変更された

REASON_CHARTCLOSE

4

チャートが閉じられた

REASON_PARAMETERS

5

ユーザが入力を変更した

REASON_ACCOUNT

6

別のアカウントが有効化されるか、アカウントの設定変更によって取引サーバへの再接続が発生した

REASON_TEMPLATE

7

他のチャートテンプレートが適用された

REASON_INITFAILED

8

OnInit()ハンドラーがゼロ以外の値を返した

REASON_CLOSE

9

端末が閉じられた

EAの初期化解除の理由コードはUninitializeReason()関数または事前定義された _UninitReason変数から受信されます。

EAのOnInit()およびOnDeinit()関数の例

input int fake_parameter=3;     // 無用のパラメータ
//+——————————————————————+
//| エキスパート初期化関数                                                |
//+——————————————————————+
int OnInit()
{
//— プログラムがコンパイルされるビルド数を取得する
Print(__FUNCTION__,” Build #”,__MQLBUILD__);
//— リセットされた理由コードはOnInit()でも取得できる
Print(__FUNCTION__,” Deinitialization reason code can be received during the EA reset”);
//— 初期化解除の理由コードを取得する1番目の方法
Print(__FUNCTION__,” _UninitReason = “,getUninitReasonText(_UninitReason));
//— 初期化解除の理由コードを取得する2番目の方法  
Print(__FUNCTION__,” UninitializeReason() = “,getUninitReasonText(UninitializeReason()));
//—
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| エキスパート初期化解除に使用される関数                                    |
//+——————————————————————+
void OnDeinit(const int reason)
{
//— 初期化解除の理由コードを取得する1番目の方法
Print(__FUNCTION__,” Deinitialization reason code = “,reason);
//— 初期化解除の理由コードを取得する2番目の方法
Print(__FUNCTION__,” _UninitReason = “,getUninitReasonText(_UninitReason));
//— 初期化解除の理由コードを取得する3番目の方法  
Print(__FUNCTION__,” UninitializeReason() = “,getUninitReasonText(UninitializeReason()));
}
//+——————————————————————+
//| 初期化理由コードのテキスト記述を返す                                      |
//+——————————————————————+
string getUninitReasonText(int reasonCode)
{
string text=“”;
//—
switch(reasonCode)
{
case REASON_ACCOUNT:
text=“Account was changed”;break;
case REASON_CHARTCHANGE:
text=“Symbol or timeframe was changed”;break;
case REASON_CHARTCLOSE:
text=“Chart was closed”;break;
case REASON_PARAMETERS:
text=“Input-parameter was changed”;break;
case REASON_RECOMPILE:
text=“Program “+__FILE__+” was recompiled”;break;
case REASON_REMOVE:
text=“Program “+__FILE__+” was removed from chart”;break;
case REASON_TEMPLATE:
text=“New template was applied to chart”;break;
default:text=“Another reason”;
}
//—
return text;
}

参照

OnInit, Event handling functions、Program running、Client terminal events、Uninitialization reason codes、Visibility scope and lifetime of variables、Creating and deleting objects

OnTick

この関数は、NewTickイベントが発生して新しい相場が処理されるときに、EAで呼び出されます。

void  OnTick(void);

戻り値

なし

注意事項

NewTickイベントは、EAが取り付けられているチャートのシンボルに対して新しいティックを受け取ったときに、EAに対してのみ生成されます。NewTickイベントが生成されていないため、カスタム指標またはスクリプトでOnTick()関数を定義することはできません。

TickイベントはEAに対してのみ生成されますが、Timer、BookEvent、およびChartEventイベントはNewTickに加えてEAに対しても生成されるため、EAにOnTick()関数を実装する必要はありません。

全てのイベントは、受信された順に次々に処理されます。キューにすでに NewTickイベントがある、またはこのイベントが処理段階にある場合、新しいNewTickイベントはMQL5アプリケーションキューには追加されません。

NewTickイベントは、自動取引が有効になっているかどうかに関係なく生成されます(自動取引ボタン)。自動取引の無効化とは、EAからの取引リクエスト送信を禁止することのみを意味します。EAの動作は停止されません。

AutoTradingボタンを押して自動取引を無効にしても、OnTick()関数の現在の実行が中断されることはありません。

OnTick()関数内の取引ロジック全体を特長とするEAの例

//+——————————————————————+
//|                                                   TradeByATR.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+——————————————————————+
#property copyright “Copyright 2018, MetaQuotes Software Corp.”
#property link     “https://www.mql5.com”
#property version   “1.00”
#property description “Sample EA trading in the \”explosive\” candle direction”
#property description “\”Explosive\” candle has the body size exceeding k*ATR”
#property description “The \”revers\” parameter reverses the signal direction”

input double lots=0.1;       // ロット単位のボリューム
input double kATR=3;         // ATRのシグナルローソク足の長さ
input int   ATRperiod=20;   // ATR指標期間
input int   holdbars=8;     // ポジションのバー数
input int   slippage=10;     // 許容されるスリッページ
input bool   revers=false;   // シグナルを反転するかどうか
input ulong EXPERT_MAGIC=0; // EAのマジックナンバー
//— ATR指標ハンドルを格納
int atr_handle;
//— ここで最後のATR値とローソク足のの実体を保存する
double last_atr,last_body;
datetime lastbar_timeopen;
double trade_lot;
//+——————————————————————+
//| エキスパート初期化関数                                                |
//+——————————————————————+
int OnInit()
{
//— グローバル変数を初期化する
last_atr=0;
last_body=0;
//— 正しいボリュームを設定する
double min_lot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
trade_lot=lots>min_lot?lots:min_lot;
//— ATR指標ハンドルを作成する
atr_handle=iATR(_Symbol,_Period,ATRperiod);
if(atr_handle==INVALID_HANDLE)
{
PrintFormat(“%s: failed to create iATR, error code %d”,__FUNCTION__,GetLastError());
return(INIT_FAILED);
}
//— EA初期化が成功した
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| エキスパート初期化解除に使用される関数                                    |
//+——————————————————————+
void OnDeinit(const int reason)
{
//— EA操作終了コードを通知する
Print(__FILE__,“: Deinitialization reason code = “,reason);
}
//+——————————————————————+
//| エキスパートティック関数                                                 |
//+——————————————————————+
void OnTick()
{
//— 取引シグナル
static int signal=0; // +1は買いシグナル、 -1は売りシグナル
//— ‘holdbars’バーより前に開かれた以前のポジションを確認して決済する
ClosePositionsByBars(holdbars,slippage,EXPERT_MAGIC);
//— 新しいバーを確認する
if(isNewBar())
{
//— シグナルの存在を確認する
signal=CheckSignal();
}
//— ネットポジションが開かれている場合は、信号をスキップして終了する
if(signal!=0 && PositionsTotal()>0 && (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_NETTING)
{
signal=0;
return; // NewTickイベントハンドラを終了し、新しいバーが現れる前に市場に入らない
}
//— ヘッジ口座の場合、各ポジションは個別に保持され、決済される
if(signal!=0)
{
//— 買いシグナル
if(signal>0)
{
PrintFormat(“%s: Buy signal!Revers=%s”,__FUNCTION__,string(revers));
if(Buy(trade_lot,slippage,EXPERT_MAGIC))
signal=0;
}
//— 売りシグナル
if(signal<0)
{
PrintFormat(“%s: Sell signal!Revers=%s”,__FUNCTION__,string(revers));
if(Sell(trade_lot,slippage,EXPERT_MAGIC))
signal=0;
}
}
//— OnTick関数の終わり
}
//+——————————————————————+
//| 新しい取引シグナルを確認する                                            |
//+——————————————————————+
int CheckSignal()
{
//— 0はシグナルが不在なことを意味する
int res=0;
//— 終わりから2番目の完全なバーにATR値を取得する(バーのインデックスは2)
double atr_value[1];
if(CopyBuffer(atr_handle,0,2,1,atr_value)!=-1)
{
last_atr=atr_value[0];
//— 最後に閉じたバーのデータをMqlRates型配列に取得する
MqlRates bar[1];
if(CopyRates(_Symbol,_Period,1,1,bar)!=-1)
{
//— 最後の完全なバーでバー本体のサイズを計算する
last_body=bar[0].close-bar[0].open;
//— 最後のバー(インデックス1)の本体が以前のATR値(インデックス2のバー上)を超える場合、取引シグナルが受信される
if(MathAbs(last_body)>kATR*last_atr)
res=last_body>0?1:-1; // 上昇ローソク足では正の値
}
else
PrintFormat(“%s: Failed to receive the last bar!Error”,__FUNCTION__,GetLastError());
}
else
PrintFormat(“%s: Failed to receive ATR indicator value!Error”,__FUNCTION__,GetLastError());
//— 反転取引モードが有効な場合
res=revers?-res:res; // 必要に応じてシグナルを反転させる(1の代わりに-1を返し、逆も同様)
//— 取引シグナル値を返す
return (res);
}
//+——————————————————————+
//|   新しいバーが現れると’true’                                           |
//+——————————————————————+
bool isNewBar(const bool print_log=true)
{
static datetime bartime=0; // 現在のバーの開いた時刻を格納する
//— ゼロバーの開いた時間を取得する
datetime currbar_time=iTime(_Symbol,_Period,0);
//— 新しいバーが到着すると開いた時刻が変わる
if(bartime!=currbar_time)
{
bartime=currbar_time;
lastbar_timeopen=bartime;
//— ログに新しいバーが開いている時間のデータを表示する
if(print_log && !(MQLInfoInteger(MQL_OPTIMIZATION)||MQLInfoInteger(MQL_TESTER)))
{
//— 新しいバーを開いた時間のメッセージを表示する
PrintFormat(“%s: new bar on %s %s opened at %s”,__FUNCTION__,_Symbol,
StringSubstr(EnumToString(_Period),7),
TimeToString(TimeCurrent(),TIME_SECONDS));
//— 最後のティックのデータを取得する
MqlTick last_tick;
if(!SymbolInfoTick(Symbol(),last_tick))
Print(“SymbolInfoTick() failed, error = “,GetLastError());
//— 最後のティックタイムをミリ秒まで表示する
PrintFormat(“Last tick was at %s.%03d”,
TimeToString(last_tick.time,TIME_SECONDS),last_tick.time_msc%1000);
}
//— 新しいバーがある
return (true);
}
//— 新しいバーがない
return (false);
}
//+——————————————————————+
//| 成行価格で指定された量で買う                                           |
//+——————————————————————+
bool Buy(double volume,ulong deviation=10,ulong  magicnumber=0)
{
//— 成行価格で買う
return (MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber));
}
//+——————————————————————+
//| 成行価格で指定された量で売る                                           |
//+——————————————————————+
bool Sell(double volume,ulong deviation=10,ulong  magicnumber=0)
{
//— 成行価格で売る
return (MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber));
}
//+——————————————————————+
//| バー数によるポジション保留時間ごとにポジションを決済する                          |
//+——————————————————————+
void ClosePositionsByBars(int holdtimebars,ulong deviation=10,ulong  magicnumber=0)
{
int total=PositionsTotal(); // ポジション数
//— ポジションをすべて見る
for(int i=total-1; i>=0; i–)
{
//— ポジションパラメータ
ulong  position_ticket=PositionGetTicket(i);                                     // ポジションチケット
string position_symbol=PositionGetString(POSITION_SYMBOL);                       // シンボル
ulong  magic=PositionGetInteger(POSITION_MAGIC);                                 // ポジションマジックナンバー
datetime position_open=(datetime)PositionGetInteger(POSITION_TIME);               // ポジションの開かれた時刻
int bars=iBarShift(_Symbol,PERIOD_CURRENT,position_open)+1;                       // ポジションがどれだけ前(バー数)に開かれたか

//— マジックナンバーとシンボルが一致していてポジションがすでに長くある場合
if(bars>holdtimebars && magic==magicnumber && position_symbol==_Symbol)
{
int   digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);           // 小数点以下桁数
double volume=PositionGetDouble(POSITION_VOLUME);                             // ポジションボリューム
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // ポジションの種類
string str_type=StringSubstr(EnumToString(type),14);
StringToLower(str_type); // 正しいメッセージ書式設定のために小文字にする
PrintFormat(“Close position #%d %s %s %.2f”,
position_ticket,position_symbol,str_type,volume);
//— 注文タイプを設定し、取引リクエストを送信する
if(type==POSITION_TYPE_BUY)
MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber,position_ticket);
else
MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber,position_ticket);
}
}
}
//+——————————————————————+
//| 取引リクエストを準備して送信する                                          |
//+——————————————————————+
bool MarketOrder(ENUM_ORDER_TYPE type,double volume,ulong slip,ulong magicnumber,ulong pos_ticket=0)
{
//— 構造体の宣言と初期化
MqlTradeRequest request={0};
MqlTradeResult  result={0};
double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
if(type==ORDER_TYPE_BUY)
price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
//— リクエストパラメータ
request.action   =TRADE_ACTION_DEAL;                     // 取引操作の種類
request.position =pos_ticket;                           // 決済する場合のポジションチケット
request.symbol   =Symbol();                             // シンボル
request.volume   =volume;                               // ボリューム
request.type     =type;                                 // 注文の種類
request.price    =price;                                 // 取引価格
request.deviation=slip;                                 // 価格からの許容偏差
request.magic    =magicnumber;                           // 注文のマジックナンバー
//— リクエストを送信する
if(!OrderSend(request,result))
{
//— 失敗したらデータを表示する
PrintFormat(“OrderSend %s %s %.2f at %.5f error %d”,
request.symbol,EnumToString(type),volume,request.price,GetLastError());
return (false);
}
//— 操作の成功を知らせる
PrintFormat(“retcode=%u  deal=%I64u  order=%I64u”,result.retcode,result.deal,result.order);
return (true);
}

参照

Event handling functions、Program running、Client terminal events、OnTimer、OnBookEvent、OnChartEvent

OnCalculate

この関数は、Calculateイベントが発生して価格の変化が処理されるときに、指標で呼び出されます。この関数の型は 2 つあります。1つの指標内では1つだけ使用できます。

データ配列に基づく計算

int OnCalculate(
const int        rates_total,       // price[]配列サイズ
const int        prev_calculated,   // 以前の呼び出しで処理されたバーの数
const int        begin,             // 意味のあるデータが始まるprice []配列のインデックス番号
const double&    price[]           // 計算のための値の配列
);

現在の時間枠に基づいた計算

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[]         // スプレッドの配列
);

パラメータ

rates_total

[in]  計算のために指標に使用できるprice[]配列または入力系列のサイズ第2の関数タイプでは、パラメータ値は、それが開始されたチャート上の棒の数に対応します。

prev_calculated

[in] 直前の呼び出しでOnCalculate()関数によって返された値が含まれます。この関数が前回起動されて以来変更されていないバーをスキップするように設計されています。

begin

[in]  price[]配列で有意義なデータが始まるインデックス。正しい値を持たない失われたデータや初期のデータをスキップすることができます。

price[]

[in]  計算のための値の配列。価格時系列または指標バッファのうちの一つがprice[]配列として渡されます。計算に渡されるデータの種類は_AppliedTo事前定義変数を使用して定義できます。

time{}

[in]  バーの開いた時間の配列

open[]

[in]  バーの始値の配列

high[]

[in]  バーの高値の配列

low[]

[in]  バーの安値の配列

close[]

[in]  バーの終値の配列

tick_volume[]

[in]  ティックボリューム値の配列

volume[]

[in]  取引量値の配列

spread[]

[in]  バーのスプレッド値の配列

戻り値

次に関数が呼び出されるときにprev_calculatedパラメータとして渡されるint 型の値

注意事項

OnCalculate()関数がゼロに等しい場合、クライアント端末のデータウィンドウには指標値が表示されません。

OnCalculate()関数の最後の呼び出し以降に価格データが変更された場合(より長期間の履歴が読み込まれているか、履歴のギャップが埋められている場合)、 prev_calculated入力パラメータは、端末自身によってゼロに設定されます。

time[]open[]high[]low[]close[]tick_volume[]volume[]spread[]配列で索引付けの方向を定義するには、ArrayGetAsSeries()関数を呼び出します。デフォルトに依存しないためには、作業する配列でArraySetAsSeries()関数を呼び出します。

最初の関数タイプを使用する場合、指標を起動するときに必要な時系列または指標がパラメータタブのprice[]配列としてユーザによって選択されます。そのためには “Apply to”(適用)フィールドのドロップダウンリストに必要な項目を指定する必要があります。

カスタム指標値を他のMQL5プログラムから取得するにはiCustom()関数が使用されます。これは、後の操作のために指標ハンドルを返します。また、必要なprice [] 配列または他の指標ハンドルを指定することも出来ます。このパラメータは、カスタム指標の入力変数のリストに最後に送信されるべきです。

OnCalculate()の戻り値とprev_calculated の2番目の入力パラメータとの関係はここで指摘される必要があります。関数が呼び出されたとき、prev_calculatedパラメータは以前のOnCalculate() 呼び出しで返された値を持ちます。これにより、この関数が前回実行されてから変更されていないバーの繰り返した計算を避けてカスタム指標を計算するためのリソース節約アルゴリズムを実装することができます。

 

指標の例

//+——————————————————————+
//|                                           OnCalculate_Sample.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+——————————————————————+
#property copyright “Copyright 2018, MetaQuotes Software Corp.”
#property link     “https://www.mql5.com”
#property version   “1.00”
#property description “Sample Momentum indicator calculation”

//—- 指標の設定
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_color1  Blue
//—- 入力
input int MomentumPeriod=14; // 計算期間
//—- 指標バッファ
double    MomentumBuffer[];
//— 計算期間を格納するグローバル変数
int       IntPeriod;
//+——————————————————————+
//| カスタム指標を初期化する関数                                            |
//+——————————————————————+
void OnInit()
{
//— 入力パラメータを確認する
if(MomentumPeriod<0)
{
IntPeriod=14;
Print(“Period parameter has an incorrect value. The following value is to be used for calculations “,IntPeriod);
}
else
IntPeriod=MomentumPeriod;
//—- バッファ  
SetIndexBuffer(0,MomentumBuffer,INDICATOR_DATA);
//—- データウィンドウとサブウィンドウで表示される指標名
IndicatorSetString(INDICATOR_SHORTNAME,“Momentum”+“(“+string(IntPeriod)+“)”);
//— 描画が始まるバーのインデックスを設定する
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,IntPeriod-1);
//— 描画されない空の値を0.0に設定する
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
//— 表示される指標の精度
IndicatorSetInteger(INDICATOR_DIGITS,2);
}
//+——————————————————————+
//|  モメンタム指標計算                                                   |
//+——————————————————————+
int OnCalculate(const int rates_total,     // price[]配列サイズ
const int prev_calculated, // 以前に処理されたバーの数
const int begin,           // 有意義なデータの始まり
const double &price[])     // 処理される値の配列
{
//— 初期の計算位置
int StartCalcPosition=(IntPeriod-1)+begin;
//—- 計算データが不十分の場合
if(rates_total<StartCalcPosition)
return(0); // ゼロ値で終了 – 指標は未計算
//— 正しい描画を開始する
if(begin>0)
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,StartCalcPosition+(IntPeriod-1));
//— 計算を開始し、開始位置を定義する
int pos=prev_calculated-1;
if(pos<StartCalcPosition)
pos=begin+IntPeriod;
//— 計算のメインループ
for(int i=pos;i<rates_total && !IsStopped();i++)
MomentumBuffer[i]=price[i]*100/price[i-IntPeriod];
//— OnCalculateの実行が完了したので、後に続く呼び出しのために新しいprev_calculated値を返す
return(rates_total);
}

参照

ArrayGetAsSeries、ArraySetAsSeries、iCustom、Event handling functions、Program running、Client terminal events、Access to timeseries and indicators

OnTimer

この関数は、一定の時間間隔で端末によって生成されるTimerイベント中に、EAで呼び出されます。

void  OnTimer(void);

戻り値

なし

注意事項

Timerイベントは、EventSetTimer()関数を使用してタイマーを起動したEAのクライアント端末によって定期的に生成されます。. 通常この関数はOnInit()関数で呼び出されます。EAの動作が止まった場合、タイマーはEventKillTimer()を使用して破壊されるべきです。これは通常OnDeinit()関数で呼び出されます。

それぞれのエキスパートアドバイザーと指標は独自のタイマーを操作しそのタイマーのみからイベントを受信します。MQL5 プログラムが停止した場合、作成されて EventKillTimer() 関数で無効にされていないタイマーは強制的に破壊されます。

タイマーイベントを1秒間に1回よりも頻繁に受信する必要がある場合は、高解像度タイマーを作成するためにEventSetMillisecondTimer()を使用します。

ストラテジーテスターでは、最小で1000ミリ秒の間隔が使用されます。一般的に、タイマー期間が減少する際にはタイマーイベントのハンドラがより頻繁に呼び出されるようにテスト時間が増加します。リアルタイムモードで操作している場合、タイマーイベントは、ハードウェアの制約のために10〜16ミリ秒に1回以下で生成されます。

1 つのプログラムでは 1 つのタイマーのみが起動出来ます。各MQL5アプリケーションとチャートは、新たに到着したイベントが配置される独自のイベントキューを持っています。キューにすでにタイマーイベントがある、またはこのイベントが処理段階にある場合、新しいタイマーイベントは MQL5 アプリケーションキューには追加されません。

OnTimer()ハンドラーを持つEAの例

//+——————————————————————+
//|                                               OnTimer_Sample.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+——————————————————————+
#property copyright “Copyright 2018, MetaQuotes Software Corp.”
#property link     “https://www.mql5.com”
#property version   “1.00”
#property description “Example of using the timer for calculating the trading server time”
#property description “It is recommended to run the EA at the end of a trading week before the weekend”
//+——————————————————————+
//| エキスパート初期化関数                                                 |
//+——————————————————————+
int OnInit()
{
//— 1秒の周期でタイマーを作成する
EventSetTimer(1);

//—
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| エキスパート初期化解除に使用される関数                                    |
//+——————————————————————+
void OnDeinit(const int reason)
{
//— 作業終了後にタイマーを破壊する
EventKillTimer();

}
//+——————————————————————+
//| エキスパートティック関数                                                 |
//+——————————————————————+
void OnTick()
{
//—

}
//+——————————————————————+
//| Timer 関数                                                        |
//+——————————————————————+
void OnTimer()
{
//— OnTimer()の最初の呼び出しの時刻
static datetime start_time=TimeCurrent();
//— 最初のOnTimer() 呼び出し中の取引サーバ時刻
static datetime start_tradeserver_time=0;
//— 計算された取引サーバ時刻
static datetime calculated_server_time=0;
//— ローカルPC時刻
datetime local_time=TimeLocal();
//— 現在の推測取引サーバ時刻
datetime trade_server_time=TimeTradeServer();
//— 何らかの理由でサーバの時刻が不明な場合は、先に終了する
if(trade_server_time==0)
return;
//— 取引サーバ初期値がまだ設定されていない場合
if(start_tradeserver_time==0)
{
start_tradeserver_time=trade_server_time;
//— 取引サーバの計算された現在時刻を設定する
Print(trade_server_time);
calculated_server_time=trade_server_time;
}
else
{
//— OnTimer()の初めの呼び出しの時刻を増やす
if(start_tradeserver_time!=0)
calculated_server_time=calculated_server_time+1;;
}
//—
string com=StringFormat(”                  Start time: %s\r\n”,TimeToString(start_time,TIME_MINUTES|TIME_SECONDS));
com=com+StringFormat(”                  Local time: %s\r\n”,TimeToString(local_time,TIME_MINUTES|TIME_SECONDS));
com=com+StringFormat(“TimeTradeServer time: %s\r\n”,TimeToString(trade_server_time,TIME_MINUTES|TIME_SECONDS));
com=com+StringFormat(” EstimatedServer time: %s\r\n”,TimeToString(calculated_server_time,TIME_MINUTES|TIME_SECONDS));
//— チャート上のすべてのカウンタの値を表示する
Comment(com);
}

参照

EventSetTimer、EventSetMillisecondTimer、EventKillTimer、GetTickCount、GetMicrosecondCount、Client terminal events

OnTrade

この関数はTradeイベントが発生するときにEAで呼び出され、注文、ポジション、取引リストの変更を処理するためのものです。

void  OnTrade(void);

戻り値

なし

注意事項

OnTrade()はエキスパートアドバイザーでのみ呼び出されます。同じ名前と型の関数をそこに追加しても、指標やスクリプトには使用されません

指値注文の実行、ポジションの開閉、ストップの設定、指値注文の発動などの取引操作によって、注文および取引の履歴、および/またはポジションおよび現在の注文のリストが適切に変更されます。

注文を処理する際、取引サーバは、着信されるTrade イベントに関するメッセージを端末に送信します。履歴から注文と取引に関する関連データを検索するには、まずHistorySelect()を使用して取引履歴リクエストを実行する必要があります。

取引イベントは、次の場合にサーバによって生成されます。

  • アクティブ注文の変更
  • ポジションの変更
  • 約定の変更
  • 取引履歴の変更

 

それぞれの Tradeイベントは、1つまたは複数の取引要求の結果として表示されることがあります。取引リクエストは、 OrderSend()またはOrderSendAsync()を使用してサーバに送信されます。それぞれのリクエストは、いくつかの取引イベントにつながる可能性があります。イベントの処理はいくつかの段階で実行されることがあり、各操作によって注文、ポジション、取引履歴の状態が変更される可能性があるため、「1つのリクエスト – 1つの取引イベント」という声明に頼ることはできません。

 

OnTrade()ハンドラーはOnTradeTransaction()が呼び出された後で呼び出されます。一般に、OnTrade()とOnTradeTransaction()の呼び出しの数には正確な相関関係はありません。1つのOnTrade()コールは、1つまたは複数のOnTradeTransactionコールに対応します。

OnTrade()を持つEAの例

//+——————————————————————+
//|                                               OnTrade_Sample.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+——————————————————————+
#property copyright “Copyright 2018, MetaQuotes Software Corp.”
#property link     “https://www.mql5.com”
#property version   “1.00”

input   int days=7;           // 取引履歴の日数
//— グローバルスコープで取引履歴の上限を設定する
datetime     start;             // キャッシュ内の取引履歴の開始日
datetime     end;               // キャッシュ内の取引履歴の終了日
//— グローバルカウンタ
int          orders;           // アクティブ注文数
int          positions;         // ポジション数
int          deals;             // 取引履歴キャッシュ内の約定数
int          history_orders;   // 取引履歴キャッシュ内の注文数
bool         started=false;     // カウンタ有効性のフラグ

//+——————————————————————+
//| エキスパート初期化関数                                                 |
//+——————————————————————+
int OnInit()
{
//—
end=TimeCurrent();
start=end-days*PeriodSeconds(PERIOD_D1);
PrintFormat(“Limits of the history to be loaded: start – %s, end – %s”,
TimeToString(start),TimeToString(end));
InitCounters();
//—
return(0);
}
//+——————————————————————+
//|  ポジション、注文、取引カウンタの初期化                                     |
//+——————————————————————+
void InitCounters()
{
ResetLastError();
//— 履歴を読み込む
bool selected=HistorySelect(start,end);
if(!selected)
{
PrintFormat(“%s. Failed to load history from %s to %s to cache. Error code: %d”,
__FUNCTION__,TimeToString(start),TimeToString(end),GetLastError());
return;
}
//— 現在値を取得する
orders=OrdersTotal();
positions=PositionsTotal();
deals=HistoryDealsTotal();
history_orders=HistoryOrdersTotal();
started=true;
Print(“Counters of orders, positions and deals successfully initialized”);
}
//+——————————————————————+
//| エキスパートティック関数                                                 |
//+——————————————————————+
void OnTick()
{
if(started) SimpleTradeProcessor();
else InitCounters();
}
//+——————————————————————+
//| Tradeイベントが到着すると呼び出される                                     |
//+——————————————————————+
void OnTrade()
{
if(started) SimpleTradeProcessor();
else InitCounters();
}
//+——————————————————————+
//| 取引と履歴の変更を処理する例                                           |
//+——————————————————————+
void SimpleTradeProcessor()
{
end=TimeCurrent();
ResetLastError();
//— 指定された間隔でプログラムキャッシュに取引履歴をダウンロードする
bool selected=HistorySelect(start,end);
if(!selected)
{
PrintFormat(“%s. Failed to load history from %s to %s to cache. Error code: %d”,
__FUNCTION__,TimeToString(start),TimeToString(end),GetLastError());
return;
}
//— 現在値を取得する
int curr_orders=OrdersTotal();
int curr_positions=PositionsTotal();
int curr_deals=HistoryDealsTotal();
int curr_history_orders=HistoryOrdersTotal();
//— アクティブ注文の数が変更されているかどうかを確認する
if(curr_orders!=orders)
{
//— アクティブ注文の数が変更されている
PrintFormat(“Number of orders has been changed. Previous value is %d, current value is %d”,
orders,curr_orders);
//— 値を更新する
orders=curr_orders;
}
//— ポジション数の変更
if(curr_positions!=positions)
{
//— ポジション数が変更されている
PrintFormat(“Number of positions has been changed. Previous value is %d, current value is %d”,
positions,curr_positions);
//— 値を更新する
positions=curr_positions;
}
//— 取引履歴キャッシュ内の約定数の変更
if(curr_deals!=deals)
{
//— 取引履歴キャッシュ内の約定数が変更されている
PrintFormat(“Number of deals has been changed. Previous value is %d, current value is %d”,
deals,curr_deals);
//— 値を更新する
deals=curr_deals;
}
//— 取引履歴キャッシュ内の履歴注文数の変更
if(curr_history_orders!=history_orders)
{
//— 取引履歴キャッシュ内の履歴注文数が変更されている
PrintFormat(“Number of orders in history has been changed. Previous value is %d, current value is %d”,
history_orders,curr_history_orders);
//— 値を更新する
history_orders=curr_history_orders;
}
//— キャッシュ内でリクエストされる取引履歴の上限を変更する必要があるかどうかを確認する
CheckStartDateInTradeHistory();
}
//+——————————————————————+
//|  取引履歴リクエストの開始日の変更                                        |
//+——————————————————————+
void CheckStartDateInTradeHistory()
{
//— 今すぐ作業を始めると仮定した場合の最初の間隔、
datetime curr_start=TimeCurrent()-days*PeriodSeconds(PERIOD_D1);
//— 取引履歴の開始制限が意図された日から1日以上経過して
//— いないことを確認する
if(curr_start-start>PeriodSeconds(PERIOD_D1))
{
//— キャッシュに読み込まれる履歴の開始日を修正する
start=curr_start;
PrintFormat(“New start limit of the trade history to be loaded: start => %s”,
TimeToString(start));
//—更新された期間の取引履歴を再度読み込む
HistorySelect(start,end);
//— さらなる比較のために約定および注文カウンタを修正する
history_orders=HistoryOrdersTotal();
deals=HistoryDealsTotal();
}
}
//+——————————————————————+
/* 出力例:
Limits of the history to be loaded: start – 2018.07.16 18:11, end – 2018.07.23 18:11
The counters of orders, positions and deals are successfully initialized
Number of orders has been changed. Previous value 0, current value 1
Number of orders has been changed. Previous value 1, current value 0
Number of positions has been changed. Previous value 0, current value 1
Number of deals has been changed. Previous value 0, current value 1
Number of orders in the history has been changed. Previous value 0, current value 1
*/

参照

OrderSend、OrderSendAsync、OnTradeTransaction, Client terminal events

OnTradeTransaction

この関数はTradeTransactionイベントが発生するときにEAで呼び出され、取引リクエストの実行結果を処理するためのものです。

void  OnTradeTransaction()
const MqlTradeTransaction&    trans,     // 取引トランザクション構造体
const MqlTradeRequest&        request,   // リクエスト構造体
const MqlTradeResult&        result     // 返答構造体
);

パラメータ

trans

[in] MqlTradeTransaction取引口座で行われた取引を記述する型変数

request

[in] MqlTradeRequestトランザクションにつながった取引リクエストを記述する型変数で、TRADE_TRANSACTION_REQUEST型トランザクション値のみを含む

result

[in] MqlTradeResultトランザクションにつながった取引リクエストの実行結果を含む型変数で、TRADE_TRANSACTION_REQUEST型トランザクション値のみを含む

戻り値

なし

注意事項

OnTradeTransaction()は、下記の場合に取引サーバが端末に送信したTradeTransactionイベントを処理するために呼び出されます。

  • OrderSend()/OrderSendAsync()関数を使ったMQL5プログラムからの取引リクエストの送信とそれに続く実行
  • GUIを介した手動での取引リクエストの送信とそれに続く実行
  • サーバでの指値注文やストップ注文のアクティベーション
  • 取引サーバ側での操作の実行

 

トランザクション型のデータはtrans変数のtypeフィールドに含まれています。トランザクションの型はENUM_TRADE_TRANSACTION_TYPE列挙体に記述されています。

  • TRADE_TRANSACTION_ORDER_ADD – 新規アクティブ注文の追加
  • TRADE_TRANSACTION_ORDER_UPDATE – 既存注文の変更
  • TRADE_TRANSACTION_ORDER_DELETE – アクティブ注文リストからの注文の削除
  • TRADE_TRANSACTION_DEAL_ADD – 履歴への約定の追加
  • TRADE_TRANSACTION_DEAL_UPDATE – 履歴での約定の変更
  • TRADE_TRANSACTION_DEAL_DELETE – 履歴での約定の削除
  • TRADE_TRANSACTION_HISTORY_ADD – 実行またはキャンセルの結果としての履歴への注文の追加
  • TRADE_TRANSACTION_HISTORY_UPDATE – 注文履歴内の注文の変更
  • TRADE_TRANSACTION_HISTORY_DELETE – 注文履歴内の注文の削除
  • TRADE_TRANSACTION_POSITION – 取引の実行に関連していないポジション変更
  • TRADE_TRANSACTION_REQUEST – 取引リクエストがサーバで処理され結果が受け取られたことの通知

TRADE_TRANSACTION_REQUEST型のトランザクションを処理するには、OnTradeTransaction()関数の第2及び第3パラメータ(requestresult)を分析し追加情報を受け取る必要があります。

買い取引リクエストを送信すると、取引口座では下記の一連の取引トランザクションが発生します。1)処理リクエストの受領、2)口座に対した適切な注文書の作成、3)注文実行、4) 実行された注文をアクティブ注文のリストから削除、5)同注文を注文履歴に追加、6)後続のトランザクションを履歴に追加、7)新しいポジションを作成これらの段階はすべて取引トランザクションです。このようなトランザクションの端末への到着がTradeTransactionイベントです。端末におけるこれらのトランザクションの到着の優先順位は保証されません。よって取引アルゴリズムを開発する際にトランザクション到着の順番を仮定すべきではありません。

EAのOnTradeTransaction()ハンドラで取引トランザクションを処理する場合、端末は新たに到着した取引トランザクションの処理を継続します。したがって、取引口座の状態は、OnTradeTransaction()操作の過程で変更される可能性があります。例えば、MQL5 プログラムが新しい注文の追加を処理している間に、注文が実行されて注文のリストから削除され、履歴に移動されることもあります。プログラムは、これらのイベントすべてを通知されます。

トランザクションキューは1,024要素を備えます。OnTradeTransaction()ハンドラーが新しいトランザクションを処理するのに長くかかりすぎると、代わりにキュー内の新しいトランザクションが処理されることがあります。

OnTrade()ハンドラーは適切なOnTradeTransaction()が呼び出された後で呼び出されます。一般に、OnTrade()とOnTradeTransaction()の呼び出しの数には正確な相関関係はありません。1つのOnTrade()コールは、1つまたは複数のOnTradeTransactionコールに対応します。

それぞれの<t1> </t1><li2>Trade</li2><t3>イベントは、1つまたは複数の取引要求の結果として表示されることがあります。取引リクエストは、OrderSend()またはOrderSendAsync()を使用してサーバに送信されます。それぞれのリクエストは、いくつかの取引イベントにつながる可能性があります。イベントの処理はいくつかの段階で実行されることがあり、各操作によって注文、ポジション、取引履歴の状態が変更される可能性があるため、「1つのリクエスト – 1つの取引イベント」という声明に頼ることはできません。

OnTradeTransaction()ハンドラーを持つEAの例

//+——————————————————————+
//|                                    OnTradeTransaction_Sample.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+——————————————————————+
#property copyright “Copyright 2018, MetaQuotes Software Corp.”
#property link     “https://www.mql5.com”
#property version   “1.00”
#property description “Sample listener of TradeTransaction events”
//+——————————————————————+
//| エキスパート初期化関数                                                |
//+——————————————————————+
int OnInit()
{
//—
PrintFormat(“LAST PING=%.f ms”,
TerminalInfoInteger(TERMINAL_PING_LAST)/1000.);
//—
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| エキスパートティック関数                                                 |
//+——————————————————————+
void OnTick()
{
//—

}
//+——————————————————————+
//| TradeTransaction 関数                                             |
//+——————————————————————+
void OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result)
{
//—
static int counter=0;   // OnTradeTransaction()呼び出しのカウンタ
static uint lasttime=0; // OnTradeTransaction()の最後の呼び出し時刻
//—
uint time=GetTickCount();
//— 最後のトランザクションが1秒以上前に実行された場合
if(time-lasttime>1000)
{
counter=0; // これは新しい取引であり、カウンタをリセットできる
if(IS_DEBUG_MODE)
Print(” New trade operation”);
}
lasttime=time;
counter++;
Print(counter,“. “,__FUNCTION__);
//— 取引リクエストの実行結果
ulong            lastOrderID   =trans.order;
ENUM_ORDER_TYPE  lastOrderType =trans.order_type;
ENUM_ORDER_STATE lastOrderState=trans.order_state;
//— トランザクションが実行される取引シンボルの名称
string trans_symbol=trans.symbol;
//— トランザクションの種類
ENUM_TRADE_TRANSACTION_TYPE  trans_type=trans.type;
switch(trans.type)
{
case TRADE_TRANSACTION_POSITION:   // ポジション修正
{
ulong pos_ID=trans.position;
PrintFormat(“MqlTradeTransaction: Position  #%d %s modified: SL=%.5f TP=%.5f”,
pos_ID,trans_symbol,trans.price_sl,trans.price_tp);
}
break;
case TRADE_TRANSACTION_REQUEST:     // 取引リクエストの送信
PrintFormat(“MqlTradeTransaction: TRADE_TRANSACTION_REQUEST”);
break;
case TRADE_TRANSACTION_DEAL_ADD:   // 取引の追加
{
ulong          lastDealID   =trans.deal;
ENUM_DEAL_TYPE lastDealType =trans.deal_type;
double        lastDealVolume=trans.volume;
//— 外部システムの取引ID – 取引所で割り当てられたチケット
string Exchange_ticket=“”;
if(HistoryDealSelect(lastDealID))
Exchange_ticket=HistoryDealGetString(lastDealID,DEAL_EXTERNAL_ID);
if(Exchange_ticket!=“”)
Exchange_ticket=StringFormat(“(Exchange deal=%s)”,Exchange_ticket);

PrintFormat(“MqlTradeTransaction: %s deal #%d %s %s %.2f lot   %s”,EnumToString(trans_type),
lastDealID,EnumToString(lastDealType),trans_symbol,lastDealVolume,Exchange_ticket);
}
break;
case TRADE_TRANSACTION_HISTORY_ADD: // 履歴への注文の追加
{
//— 外部システムの注文ID – 取引所で割り当てられたチケット
string Exchange_ticket=“”;
if(lastOrderState==ORDER_STATE_FILLED)
{
if(HistoryOrderSelect(lastOrderID))
Exchange_ticket=HistoryOrderGetString(lastOrderID,ORDER_EXTERNAL_ID);
if(Exchange_ticket!=“”)
Exchange_ticket=StringFormat(“(Exchange ticket=%s)”,Exchange_ticket);
}
PrintFormat(“MqlTradeTransaction: %s order #%d %s %s %s   %s”,EnumToString(trans_type),
lastOrderID,EnumToString(lastOrderType),trans_symbol,EnumToString(lastOrderState),Exchange_ticket);
}
break;
default: // 他のトランザクション
{
//— 外部システムの注文ID – 取引所で割り当てられたチケット
string Exchange_ticket=“”;
if(lastOrderState==ORDER_STATE_PLACED)
{
if(OrderSelect(lastOrderID))
Exchange_ticket=OrderGetString(ORDER_EXTERNAL_ID);
if(Exchange_ticket!=“”)
Exchange_ticket=StringFormat(“Exchange ticket=%s”,Exchange_ticket);
}
PrintFormat(“MqlTradeTransaction: %s order #%d %s %s   %s”,EnumToString(trans_type),
lastOrderID,EnumToString(lastOrderType),EnumToString(lastOrderState),Exchange_ticket);
}
break;
}
//— 注文チケット    
ulong orderID_result=result.order;
string retcode_result=GetRetcodeID(result.retcode);
if(orderID_result!=0)
PrintFormat(“MqlTradeResult: order #%d retcode=%s “,orderID_result,retcode_result);
//—  
}
//+——————————————————————+
//| 数値をテキスト文字列に変換する                                           |
//+——————————————————————+
string GetRetcodeID(int retcode)
{
switch(retcode)
{
case 10004: return(“TRADE_RETCODE_REQUOTE”);             break;
case 10006: return(“TRADE_RETCODE_REJECT”);             break;
case 10007: return(“TRADE_RETCODE_CANCEL”);             break;
case 10008: return(“TRADE_RETCODE_PLACED”);             break;
case 10009: return(“TRADE_RETCODE_DONE”);               break;
case 10010: return(“TRADE_RETCODE_DONE_PARTIAL”);       break;
case 10011: return(“TRADE_RETCODE_ERROR”);               break;
case 10012: return(“TRADE_RETCODE_TIMEOUT”);             break;
case 10013: return(“TRADE_RETCODE_INVALID”);             break;
case 10014: return(“TRADE_RETCODE_INVALID_VOLUME”);     break;
case 10015: return(“TRADE_RETCODE_INVALID_PRICE”);       break;
case 10016: return(“TRADE_RETCODE_INVALID_STOPS”);       break;
case 10017: return(“TRADE_RETCODE_TRADE_DISABLED”);     break;
case 10018: return(“TRADE_RETCODE_MARKET_CLOSED”);       break;
case 10019: return(“TRADE_RETCODE_NO_MONEY”);           break;
case 10020: return(“TRADE_RETCODE_PRICE_CHANGED”);       break;
case 10021: return(“TRADE_RETCODE_PRICE_OFF”);           break;
case 10022: return(“TRADE_RETCODE_INVALID_EXPIRATION”); break;
case 10023: return(“TRADE_RETCODE_ORDER_CHANGED”);       break;
case 10024: return(“TRADE_RETCODE_TOO_MANY_REQUESTS”);   break;
case 10025: return(“TRADE_RETCODE_NO_CHANGES”);         break;
case 10026: return(“TRADE_RETCODE_SERVER_DISABLES_AT”); break;
case 10027: return(“TRADE_RETCODE_CLIENT_DISABLES_AT”); break;
case 10028: return(“TRADE_RETCODE_LOCKED”);             break;
case 10029: return(“TRADE_RETCODE_FROZEN”);             break;
case 10030: return(“TRADE_RETCODE_INVALID_FILL”);       break;
case 10031: return(“TRADE_RETCODE_CONNECTION”);         break;
case 10032: return(“TRADE_RETCODE_ONLY_REAL”);           break;
case 10033: return(“TRADE_RETCODE_LIMIT_ORDERS”);       break;
case 10034: return(“TRADE_RETCODE_LIMIT_VOLUME”);       break;
case 10035: return(“TRADE_RETCODE_INVALID_ORDER”);       break;
case 10036: return(“TRADE_RETCODE_POSITION_CLOSED”);     break;
default:
return(“TRADE_RETCODE_UNKNOWN=”+IntegerToString(retcode));
break;
}
//—
}

参照

OrderSend、OrderSendAsync、OnTradeTransaction、Trade request structure、Trade transaction structure、Trade transaction types、Trade operation types、Client terminal events

OnBookEvent

この関数は、BookEventイベントが発生するときに指標やEAで呼び出され、板情報の変化を処理するために設計されています。

void OnBookEvent(
const string&  symbol        // 銘柄
);

パラメータ

symbol

[in] BookEventが到着した銘柄の名称

戻り値

なし

注意事項

任意のシンボルのBookEventイベントを受け取るには、MarketBookAdd() 関数を使用してこのシンボルのBookEventイベント受信を事前に設定する必要があります。指定されたシンボルのBookEventへの購読を停止するにはMarketBookRelease()関数を呼ぶ必要があります。

BookEventはすべてのチャートにブロードキャストされます。これは、1 つのアプリケーションがMarketBookAddを使用してBookEventイベントの受信に購読した場合、同じチャートにある他のすべてのOnBookEvent() ハンドラを持っている指標とEAがこのイベントを受け取ることを意味します。よって、symbolパラメータとしてOnBookEvent()ハンドラに渡された銘柄名を分析する必要があります。

同じチャートで実行されているすべてのアプリケーションについて銘柄でソートされた個別のBookEventカウンターが提供されます。これは、各チャートが異なるシンボルに対して複数のサブスクリプションを持つことができ、各シンボルに対してカウンタが提供されることを意味します。BookEventを購読および購読解除すると、指定したシンボルの購読カウンタが1つのチャート内でのみ変更されます。言い換えれば、同じシンボルであるにもかかわらず購読カウンタの値が異なるBookEventには、2つの隣接するチャートが存在する可能性があります。

購読カウンタの初期値はゼロです。MarketBookAdd()が呼び出されるごとに、チャート上の指定されたシンボルの購読カウンタが1つ増えます(チャートシンボルと MarketBookAdd()内のシンボルは一致する必要はありません)。MarketBookRelease()を呼び出すと、チャート内の特定のシンボルに対する購読カウンタが1つ減少します。任意のシンボルのBookEventイベントは、カウンタが0になるまでチャート内でブロードキャストされます。したがって、MarketBookAdd ()の呼び出しを含むMQL5プログラムが全て、動作後にMarketBookRelease()を使用して正しくイベントの購読を解除することが重要です。これを達成するためには、MQL5プログラムの全体のライフタイムでのMarketBookAdd()とMarketBookRelease()の呼び出し数は偶数であるべきです。プログラム内でフラグやカスタム購読カウンタを使用することで、BookEventイベントを安全に扱うことができ、購読を無効にして、同じイベントのサードパーティプログラムでイベントを取得することを防ぐことができます。

BookEventイベントはスキップされることはなく、前のBookEventの処理がまだ終わっていなくても、常にキューに入れられます。

 

//+——————————————————————+
//|                                           OnBookEvent_Sample.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+——————————————————————+
#property copyright “Copyright 2018, MetaQuotes Software Corp.”
#property link     “https://www.mql5.com/en/articles/2635”
#property version   “1.00”
#property description “Example of measuring the market depth refresh rate using OnBookEvent()”
#property description “The code is taken from the article https://www.mql5.com/en/articles/2635”
//— 入力パラメータ
input ulong ExtCollectTime   =30; // 秒単位でのテスト時間
input ulong ExtSkipFirstTicks=10; // 初めに抜かされるティックの数
//— BookEventイベント購読のフラグ
bool book_subscribed=false;
//— 板情報からリクエストを受け取る配列
MqlBookInfo  book[];
//+——————————————————————+
//| エキスパート初期化関数                                                |
//+——————————————————————+
int OnInit()
{
//— 初めを表示する
Comment(StringFormat(“Waiting for the first %I64u ticks to arrive”,ExtSkipFirstTicks));
PrintFormat(“Waiting for the first %I64u ticks to arrive”,ExtSkipFirstTicks);
//— 板情報ブロードキャストを有効にする
if(MarketBookAdd(_Symbol))
{
book_subscribed=true;
PrintFormat(“%s: MarketBookAdd(%s) function returned true”,__FUNCTION__,_Symbol);
}
else
PrintFormat(“%s: MarketBookAdd(%s) function returned false!GetLastError()=%d”,__FUNCTION__,_Symbol,GetLastError());
//— 初期化が正常に完了
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| エキスパートの初期化を解除する                                           |
//+——————————————————————+
void OnDeinit(const int reason)
{
//— 初期化解除の理由コードを表示する
Print(__FUNCTION__,“: Deinitialization reason code = “,reason);
//— 板情報イベント受信の購読を取り消す
if(book_subscribed)
{
if(!MarketBookRelease(_Symbol))
PrintFormat(“%s: MarketBookRelease(%s) returned false!GetLastError()=%d”,_Symbol,GetLastError());
else
book_subscribed=false;
}
//—
}
//+——————————————————————+
//| BookEvent関数                                                     |
//+——————————————————————+
void OnBookEvent(const string &symbol)
{
static ulong starttime=0;             // テスト開始時刻
static ulong tickcounter=0;           // 板情報更新カウンタ
//— 板情報イベントを扱うのは、自分たちで購読している場合のみである
if(!book_subscribed)
return;
//— 特定シンボルのみの更新を数える
if(symbol!=_Symbol)
return;
//— 最初のティックをスキップしてキューをクリアする
tickcounter++;
if(tickcounter<ExtSkipFirstTicks)
return;
//— 開始時刻を記憶する
if(tickcounter==ExtSkipFirstTicks)
starttime=GetMicrosecondCount();
//— 板情報データをリクエストする
MarketBookGet(symbol,book);
//— 終了時  
ulong endtime=GetMicrosecondCount()-starttime;
ulong ticks  =1+tickcounter-ExtSkipFirstTicks;
// テストの開始からどれくらいの時間が経過したか
if(endtime>ExtCollectTime*1000*1000)
{
PrintFormat(“%I64u ticks for %.1f seconds: %.1f ticks/sec “,ticks,endtime/1000.0/1000.0,ticks*1000.0*1000.0/endtime);
ExpertRemove();
return;
}
//— カウンタをコメント欄に表示する
if(endtime>0)
Comment(StringFormat(“%I64u ticks for %.1f seconds: %.1f ticks/sec “,ticks,endtime/1000.0/1000.0,ticks*1000.0*1000.0/endtime));
}

 

 

参照

MarketBookAdd、MarketBookRelease、MarketBookGet、OnTrade、OnTradeTransaction、OnTick、イベント処理関数、プログラムの実行、クライエント端末イベント

OnChartEvent

この関数はChartEventイベントが発生するときに指標やEAで呼び出されます。この関数は、ユーザまたはMQL5プログラムによって行われたチャートの変更を処理するためのものです。

void  OnChartEvent()
const int       id,       // イベントID
const long&    lparam,   // long型イベントパラメータ
const double&  dparam,   // double型イベントパラメータ
const string&  sparam   // string型イベントパラメータ
);

パラメータ

id

[in] ENUM_CHART_EVENT列挙体からのイベントID

lparam

[in] long型イベントパラメータ

dparam

[in] double型イベントパラメータ

sparam

[in] string型イベントパラメータ

戻り値

なし

注意事項

事前定義されたOnChartEvent()関数を使用して処理出来るイベントには11種類あります。CHARTEVENT_CUSTOMからCHARTEVENT_CUSTOM_LASTまでの65535のIDはカスタムイベントのために提供されています。カスタムイベントの作成にはEventChartCustom()関数が使用されます。

ENUM_CHART_EVENT列挙体からの短いイベントの記述

  • CHARTEVENT_KEYDOWN — チャートウィンドウがフォーカスされている時のキー押下
  • CHARTEVENT_MOUSE_MOVE — マウスの移動、マウスボタンクリック(チャートのCHART_EVENT_MOUSE_MOVE=trueの場合)
  • CHARTEVENT_OBJECT_CREATE — グラフィックオブジェクトの作成(チャートの CHART_EVENT_OBJECT_CREATE=trueの場合)
  • CHARTEVENT_OBJECT_CHANGE — プロパティダイアログを介してのオブジェクトプロパティ変更
  • CHARTEVENT_OBJECT_DELETE — グラフィックオブジェクト削除(チャートのCHART_EVENT_OBJECT_DELETE=trueの場合)
  • CHARTEVENT_CLICK — チャートのクリック
  • CHARTEVENT_OBJECT_CLICK — チャートに属するグラフィックオブジェクトでのマウスクリック
  • CHARTEVENT_OBJECT_DRAG — マウスを使用してのグラフィカルオブジェクトのドラッグ
  • CHARTEVENT_OBJECT_ENDEDIT — グラフィックオブジェクトの入力ボックスのテキスト編集(OBJ_EDIT)の完成
  • CHARTEVENT_CHART_CHANGE — チャート変更
  • CHARTEVENT_CUSTOM+n — カスタムイベントID(nは0〜65535)CHARTEVENT_CUSTOM_LAST — カスタムイベントの最大の使用可能なID(CHARTEVENT_CUSTOM +65535)

すべてのMQL5プログラムは、アプリケーションのメインスレッド以外のスレッドで動作します。メインのアプリケーションスレッドは、すべてのWindowsシステムメッセージを処理し、この処理の結果、独自のアプリケーション用のWindowsメッセージを生成します。たとえば、チャート上でマウスを動かすと(WM_MOUSE_MOVEイベント)、後のアプリケーションウインドウでのレンダリングのためにいくつかのシステムメッセージが生成され、内部メッセージがチャート上で起動されたエキスパートや指標に送信されます。EAまたは指標が既にマウス移動イベントを受信している間に、メインアプリケーションスレッドがWM_PAINTシステムメッセージをまだ処理していない(したがって、まだ変更されたチャートをレンダリングしていない)状況が発生する可能性があります。この場合、チャートプロパティCHART_FIRST_VISIBLE_BARはチャートがレンダリングされた後にのみ変更されます。

各イベントタイプに対して、OnChartEvent()関数の入力には、そのイベントを処理するために必要な特定の値があります。この表では、パラメータを介して渡されるイベントと値が一覧できます。

イベント

‘id’パラメータ値

‘lparam’パラメータ値

‘dparam’パラメータ値

‘sparam’パラメータ値

キーストロークイベント

CHARTEVENT_KEYDOWN

押下されたボタンのコード

キーが長押しされた状態で生成されたキー押下の数

キーボードのキーの状態を表すビットマスクの文字列値

マウスイベント(チャートのCHART_EVENT_MOUSE_MOVE=trueの場合)

CHARTEVENT_MOUSE_MOVE

X座標

Y座標

マウスキーの状態を表すビットマスクの文字列値

マウスホイールイベント(チャートのCHART_EVENT_MOUSE_WHEEL=trueの場合)

CHARTEVENT_MOUSE_WHEEL

キーとマウスボタンの状態のフラグ、カーソルのX座標とY座標。例をご覧ください。

マウスホイールスクロールのデルタ値

グラフィックオブジェクト作成(チャートのCHART_EVENT_OBJECT_CREATE=trueの場合)

CHARTEVENT_OBJECT_CREATE

作成したグラフィックオブジェクトの名称

プロパティダイアログを介してのオブジェクトプロパティ変更

CHARTEVENT_OBJECT_CHANGE

変更したグラフィックオブジェクトの名称

グラフィックオブジェクトの削除(チャートのCHART_EVENT_OBJECT_DELETE=trueの場合)

CHARTEVENT_OBJECT_DELETE

削除したグラフィックオブジェクトの名称

チャート上でのマウスクリック

CHARTEVENT_CLICK

X座標

Y座標

グラフィックオブジェクトでのマウスクリック

CHARTEVENT_OBJECT_CLICK

X座標

Y座標

イベントが発生したグラフィック•オブジェクトの名称

マウスでのグラフィックオブジェクトの移動

CHARTEVENT_OBJECT_DRAG

移動したグラフィックオブジェクトの名称

“Input field”(入力フィールド)グラフィックオブジェクトのテキスト編集の完成

CHARTEVENT_OBJECT_ENDEDIT

テキスト編集が完成した「入力フィールド」グラフィックオブジェクトの名称

プロパティダイアログウィンドウでのチャートのサイズ変更やチャートのプロパティ変更

CHARTEVENT_CHART_CHANGE

N番号を使用したカスタムイベント

CHARTEVENT_CUSTOM+N

EventChartCustom()関数で定義された値

EventChartCustom()関数で定義された値

EventChartCustom()関数で定義された値

チャートイベントリスナーの例

//+——————————————————————+
//|                                          OnChartEvent_Sample.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+——————————————————————+
#property copyright “Copyright 2018, MetaQuotes Software Corp.”
#property link     “https://www.mql5.com”
#property version   “1.00”
#property description “Sample chart event listener and custom events generator”
//— サービスキーID
#define KEY_NUMPAD_5       12
#define KEY_LEFT           37
#define KEY_UP             38
#define KEY_RIGHT          39
#define KEY_DOWN           40
#define KEY_NUMLOCK_DOWN   98
#define KEY_NUMLOCK_LEFT  100
#define KEY_NUMLOCK_5     101
#define KEY_NUMLOCK_RIGHT 102
#define KEY_NUMLOCK_UP    104
//+——————————————————————+
//| エキスパート初期化関数                                                 |
//+——————————————————————+
int OnInit()
{
//— CHARTEVENT_CUSTOM定数値を表示する
Print(“CHARTEVENT_CUSTOM=”,CHARTEVENT_CUSTOM);
//—
Print(“Launched the EA “,MQLInfoString(MQL5_PROGRAM_NAME));
//— チャートオブジェクト作成イベントの受信フラグを設定する
ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_CREATE,true);
//— チャートオブジェクト削除イベントの受信フラグを設定する
ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_DELETE,true);
//— マウスホイールスクロールメッセージの有効化
ChartSetInteger(0,CHART_EVENT_MOUSE_WHEEL,1);
//— チャートプロパティの強制更新により、イベント処理の準備が整う
ChartRedraw();
//—
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| エキスパートティック関数                                                 |
//+——————————————————————+
void OnTick()
{
//— カスタムイベント生成のためのティックカウンタ
static int tick_counter=0;
//— 累積されたティックをこの値で除算する
int simple_number=113;
//—
tick_counter++;
//— ティックカウンタがsimple_numberの倍数である場合、カスタムイベントを送信する
if(tick_counter%simple_number==0)
{
//— カスタムイベントIDを0〜65535で形成する
ushort custom_event_id=ushort(tick_counter%65535);
//—  カスタムイベントを送信し、パラメータを記入する
EventChartCustom(ChartID(),custom_event_id,tick_counter,SymbolInfoDouble(Symbol(),SYMBOL_BID),__FUNCTION__);
//— 結果例を分析するためにログに追加する
Print(__FUNCTION__,“: Sent a custom event ID=”,custom_event_id);
}
//—    
}
//+——————————————————————+
//| ChartEvent 関数                                                   |
//+——————————————————————+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//— キーの押下
if(id==CHARTEVENT_KEYDOWN)
{
switch((int)lparam)
{
case KEY_NUMLOCK_LEFT: Print(“Pressed KEY_NUMLOCK_LEFT”);   break;
case KEY_LEFT:         Print(“Pressed KEY_LEFT”);           break;
case KEY_NUMLOCK_UP:   Print(“Pressed KEY_NUMLOCK_UP”);     break;
case KEY_UP:           Print(“Pressed KEY_UP”);             break;
case KEY_NUMLOCK_RIGHT: Print(“Pressed KEY_NUMLOCK_RIGHT”); break;
case KEY_RIGHT:         Print(“Pressed KEY_RIGHT”);         break;
case KEY_NUMLOCK_DOWN: Print(“Pressed KEY_NUMLOCK_DOWN”);   break;
case KEY_DOWN:         Print(“Pressed KEY_DOWN”);           break;
case KEY_NUMPAD_5:     Print(“Pressed KEY_NUMPAD_5”);       break;
case KEY_NUMLOCK_5:     Print(“Pressed KEY_NUMLOCK_5”);     break;
default:               Print(“Pressed unlisted key”);
}
}
//— チャートの左クリック
if(id==CHARTEVENT_CLICK)
Print(“Mouse click coordinates on a chart: x = “,lparam,”  y = “,dparam);
//— グラフィックオブジェクトのクリック
if(id==CHARTEVENT_OBJECT_CLICK)
Print(“Clicking a mouse button on an object named ‘”+sparam+“‘”);
//— オブジェクト削除
if(id==CHARTEVENT_OBJECT_DELETE)
Print(“Removed object named “,sparam);
//— オブジェクト作成
if(id==CHARTEVENT_OBJECT_CREATE)
Print(“Created object named “,sparam);
//— オブジェクト変更
if(id==CHARTEVENT_OBJECT_CHANGE)
Print(“Changed object named “,sparam);
//— オブジェクト移動またはアンカーポイント座標変更
if(id==CHARTEVENT_OBJECT_DRAG)
Print(“Changing anchor points of object named “,sparam);
//— Editグラフィックオブジェクトのテキスト編集
if(id==CHARTEVENT_OBJECT_ENDEDIT)
Print(“Changed text in Edit object “,sparam,”  id=”,id);
//— マウス移動イベント
if(id==CHARTEVENT_MOUSE_MOVE)
Comment(“POINT: “,(int)lparam,“,”,(int)dparam,“\n”,MouseState((uint)sparam));
if(id==CHARTEVENT_MOUSE_WHEEL)
{
//— このイベントのマウスボタンとホイールの状態を考察する
int flg_keys = (int)(lparam>>32);         // Ctrlキー、Shiftキー、マウスボタンの状態のフラグ
int x_cursor = (int)(short)lparam;         // マウスホイールイベントが発生したX座標
int y_cursor = (int)(short)(lparam>>16);   // マウスホイールイベントが発生したY座標
int delta    = (int)dparam;               // マウススクロールの合計値(+120または -120 が越されるとトリガされる)
//— フラグの処理
string str_keys=“”;
if((flg_keys&0x0001)!=0)
str_keys+=“LMOUSE “;
if((flg_keys&0x0002)!=0)
str_keys+=“RMOUSE “;
if((flg_keys&0x0004)!=0)
str_keys+=“SHIFT “;
if((flg_keys&0x0008)!=0)
str_keys+=“CTRL “;
if((flg_keys&0x0010)!=0)
str_keys+=“MMOUSE “;
if((flg_keys&0x0020)!=0)
str_keys+=“X1MOUSE “;
if((flg_keys&0x0040)!=0)
str_keys+=“X2MOUSE “;

if(str_keys!=“”)
str_keys=“, keys='”+StringSubstr(str_keys,0,StringLen(str_keys)-1)+“‘”;
PrintFormat(“%s: X=%d, Y=%d, delta=%d%s”,EnumToString(CHARTEVENT_MOUSE_WHEEL),x_cursor,y_cursor,delta,str_keys);
}
//— プロパティダイアログウィンドウでのチャートのサイズおよびプロパティ変更イベント
if(id==CHARTEVENT_CHART_CHANGE)
Print(“Changing the chart size or properties”);
//— カスタムイベント
if(id>CHARTEVENT_CUSTOM)
PrintFormat(“Custom event ID=%d, lparam=%d, dparam=%G, sparam=%s”,id,lparam,dparam,sparam);
}
//+——————————————————————+
//| マウスの状態                                                        |
//+——————————————————————+
string MouseState(uint state)
{
string res;
res+=“\nML: “   +(((state& 1)== 1)?“DN”:“UP”);   // 左ボタン
res+=“\nMR: “   +(((state& 2)== 2)?“DN”:“UP”);   // 右ボタン
res+=“\nMM: “   +(((state&16)==16)?“DN”:“UP”);   // 中央ボタン
res+=“\nMX: “   +(((state&32)==32)?“DN”:“UP”);   // 追加ボタン1
res+=“\nMY: “   +(((state&64)==64)?“DN”:“UP”);   // 追加ボタン 2
res+=“\nSHIFT: “+(((state& 4)== 4)?“DN”:“UP”);   // シフト キー
res+=“\nCTRL: “ +(((state& 8)== 8)?“DN”:“UP”);   // control キー
return(res);
}

参照

EventChartCustom、Types of chart events、Event handling functions、Program running、Client terminal events

OnTester

この関数は、Testerイベントが発生してテスト後に適切なアクションを取るために、EAで呼び出されます。

double  OnTester(void);

戻り値

テスト結果を評価するためのカスタム条件最適化の値  

注意事項

OnTester()関数は、EAのテスト時にのみ使用でき、主に入力パラメータの遺伝的最適化のためのカスタム最大基準として使用される値の計算のために意図されています。

遺伝的最適化では一世代内の結果は降順にソートされます。これは、最高値の結果が最適化基準の観点から最良とみなされることを意味します。このようなソーティングの最悪値は最後に配置され、その後破棄されます。したがって、それらは次世代の形成に参加しません。

したがって、OnTester()関数を使用すると、独自のテスト結果レポートが作成され保存されるだけでなく、最適化プロセスを制御してトレーディング戦略の最良のパラメータを見つけることができます。

以下はカスタム条件最適化を計算するです。アイディアは、バランスグラフの線形回帰を計算することです。これはOptimizing a strategy using balance graph and comparing results with “Balance + max Sharpe Ratio” criterion(バランスグラフを使用した戦略の最適化と、結果の「バランス+最大シャープレシオ」基準との比較)稿で説明されています。

//+——————————————————————+
//|                                              OnTester_Sample.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+——————————————————————+
#property copyright “Copyright 2018, MetaQuotes Software Corp.”
#property link     “https://www.mql5.com”
#property version   “1.00”
#property description “Sample EA with the OnTester() handler”
#property description “As a custom optimization criterion, “
#property description “the ratio of the balance graph linear regression”
#property description “divided by the deviation mean-square error is returned”
//– 取引操作クラスをインクルードする
#include <Trade\Trade.mqh>
//— EA入力パラメータ
input double Lots               = 0.1;     // ボリューム
input int   Slippage           = 10;     // 許容されるスリッページ
input int   MovingPeriod       = 80;     // 移動平均期間
input int   MovingShift        = 6;       // 移動平均シフト
//— グローバル変数
int    IndicatorHandle=0; // 指標ハンドル
bool   IsHedging=false;   // アカウントのフラグ
CTrade trade;             // 取引操作の実行
//—
#define EA_MAGIC 18052018
//+——————————————————————+
//| ポジションを開く条件を確認する                                            |
//+——————————————————————+
void CheckForOpen(void)
{
MqlRates rt[2];
//— 新しいバーの始めのみで取引する
if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
{
Print(“CopyRates of “,_Symbol,” failed, no history”);
return;
}
//— ティックボリューム
if(rt[1].tick_volume>1)
return;
//— 移動平均値を受け取る
double   ma[1];
if(CopyBuffer(IndicatorHandle,0,1,1,ma)!=1)
{
Print(“CopyBuffer from iMA failed, no data”);
return;
}
//— シグナルの存在を確認する
ENUM_ORDER_TYPE signal=WRONG_VALUE;
//— ローソク足は移動平均より高く開いたが、移動平均より低く閉じた
if(rt[0].open>ma[0] && rt[0].close<ma[0])
signal=ORDER_TYPE_BUY;   // 買いシグナル
else // ローソク足は移動平均より低く開いたが、移動平均より高く閉じた
{
if(rt[0].open<ma[0] && rt[0].close>ma[0])
signal=ORDER_TYPE_SELL;// 売りシグナル
}
//— 追加的確認
if(signal!=WRONG_VALUE)
{
if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100)
{
double price=SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ?SYMBOL_BID:SYMBOL_ASK);
trade.PositionOpen(_Symbol,signal,Lots,price,0,0);
}
}
//—
}
//+——————————————————————+
//| ポジションを閉じる条件を確認する                                          |
//+——————————————————————+
void CheckForClose(void)
{
MqlRates rt[2];
//— 新しいバーの始めのみで取引する
if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
{
Print(“CopyRates of “,_Symbol,” failed, no history”);
return;
}
if(rt[1].tick_volume>1)
return;
//— 移動平均値を受け取る
double   ma[1];
if(CopyBuffer(IndicatorHandle,0,1,1,ma)!=1)
{
Print(“CopyBuffer from iMA failed, no data”);
return;
}
//— ポジションはPositionSelect()を使用してすでに選択されている
bool signal=false;
long type=PositionGetInteger(POSITION_TYPE);
//— ローソク足は移動平均より高く開いたが、移動平均より低く閉じた – ショートポジションを決済する
if(type==(long)POSITION_TYPE_SELL && rt[0].open>ma[0] && rt[0].close<ma[0])
signal=true;
//— ローソク足は移動平均より低く開いたが、移動平均より高く閉じた – ロングポジションを決済する
if(type==(long)POSITION_TYPE_BUY && rt[0].open<ma[0] && rt[0].close>ma[0])
signal=true;
//— 追加的確認
if(signal)
{
if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100)
trade.PositionClose(_Symbol,Slippage);
}
//—
}
//+——————————————————————-+
//| 口座タイプ(ネッティングまたはヘッジ)を考慮してポジションを選択する                     |
//+——————————————————————-+
bool SelectPosition()
{
bool res=false;
//— ヘッジ口座のポジションを選択する
if(IsHedging)
{
uint total=PositionsTotal();
for(uint i=0; i<total; i++)
{
string position_symbol=PositionGetSymbol(i);
if(_Symbol==position_symbol && EA_MAGIC==PositionGetInteger(POSITION_MAGIC))
{
res=true;
break;
}
}
}
//— ネッティング口座のポジションを選択する
else
{
if(!PositionSelect(_Symbol))
return(false);
else
return(PositionGetInteger(POSITION_MAGIC)==EA_MAGIC); //—check Magic number
}
//— 実行結果
return(res);
}
//+——————————————————————+
//| エキスパート初期化関数                                                 |
//+——————————————————————+
int OnInit(void)
{
//— 取引タイプ(ネッティングまたはヘッジ)を設定する
IsHedging=((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING);
//— 正しいポジション制御のためにオブジェクトを初期化する
trade.SetExpertMagicNumber(EA_MAGIC);
trade.SetMarginMode();
trade.SetTypeFillingBySymbol(Symbol());
trade.SetDeviationInPoints(Slippage);
//— 移動平均指標を作成する
IndicatorHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE);
if(IndicatorHandle==INVALID_HANDLE)
{
printf(“Error creating iMA indicator”);
return(INIT_FAILED);
}
//— ok
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| エキスパートティック関数                                                 |
//+——————————————————————+
void OnTick(void)
{
//— ポジションが既に開かれている場合は、決済条件を確認する
if(SelectPosition())
CheckForClose();
// ポジションを開く条件を確認する
CheckForOpen();
//—
}
//+——————————————————————+
//| テスタ関数                                                          |
//+——————————————————————+
double OnTester()
{
//— カスタム条件最適化の値(高いほど良い)
double ret=0.0;
//— 取引結果を配列に入れる
double array[];
double trades_volume;
GetTradeResultsToArray(array,trades_volume);
int trades=ArraySize(array);
//— 10取引未満の場合、肯定的結果がないことをテストする
if(trades<10)
return (0);
//— 取引あたりの平均結果
double average_pl=0;
for(int i=0;i<ArraySize(array);i++)
average_pl+=array[i];
average_pl/=trades;
//— 単一テストモード用のメッセージを表示する
if(MQLInfoInteger(MQL_TESTER) && !MQLInfoInteger(MQL_OPTIMIZATION))
PrintFormat(“%s: Trades=%d, Average profit=%.2f”,__FUNCTION__,trades,average_pl);
//— 利益グラフの線形回帰を計算する
double a,b,std_error;
double chart[];
if(!CalculateLinearRegression(array,chart,a,b))
return (0);
//— 回帰直線からグラフの偏差の誤差を計算する
if(!CalculateStdError(chart,a,b,std_error))
return (0);
//— 傾向偏差の標準偏差を計算する
ret=a*trades/std_error;
//— カスタム条件最適化値を返す
return(ret);
}
//+——————————————————————+
//| 取引の利益/損失の配列を得る                                           |
//+——————————————————————+
bool GetTradeResultsToArray(double &pl_results[],double &volume)
{
//— 完全な取引履歴をリクエストする
if(!HistorySelect(0,TimeCurrent()))
return (false);
uint total_deals=HistoryDealsTotal();
volume=0;
//— 証拠金を持つ配列の初期サイズを、履歴の取引数で設定する
ArrayResize(pl_results,total_deals);
//— 取引結果を修正する取引のカウンター – 利益または損失
int counter=0;
ulong ticket_history_deal=0;
//— 全ての取引を見る
for(uint i=0;i<total_deals;i++)
{
//— 取引を選択する
if((ticket_history_deal=HistoryDealGetTicket(i))>0)
{
ENUM_DEAL_ENTRY deal_entry  =(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket_history_deal,DEAL_ENTRY);
long           deal_type   =HistoryDealGetInteger(ticket_history_deal,DEAL_TYPE);
double         deal_profit =HistoryDealGetDouble(ticket_history_deal,DEAL_PROFIT);
double         deal_volume =HistoryDealGetDouble(ticket_history_deal,DEAL_VOLUME);
//— 興味があるのは取引操作のみである
if((deal_type!=DEAL_TYPE_BUY) && (deal_type!=DEAL_TYPE_SELL))
continue;
//— 損益を固定する取引のみ
if(deal_entry!=DEAL_ENTRY_IN)
{
//— 取引結果を配列に書き込み、取引のカウンターを増やす
pl_results[counter]=deal_profit;
volume+=deal_volume;
counter++;
}
}
}
//— 配列の最終サイズを設定する
ArrayResize(pl_results,counter);
return (true);
}
//+——————————————————————+
//| 線形回帰を計算する y=a*x+b                                           |
//+——————————————————————+
bool CalculateLinearRegression(double  &change[],double &chartline[],
double  &a_coef,double  &b_coef)
{
//— データが十分か確認する
if(ArraySize(change)<3)
return (false);
//— 蓄積されたチャート配列を作成する
int N=ArraySize(change);
ArrayResize(chartline,N);
chartline[0]=change[0];
for(int i=1;i<N;i++)
chartline[i]=chartline[i-1]+change[i];
//— 線形回帰を計算する
double x=0,y=0,x2=0,xy=0;
for(int i=0;i<N;i++)
{
x=x+i;
y=y+chartline[i];
xy=xy+i*chartline[i];
x2=x2+i*i;
}
a_coef=(N*xy-x*y)/(N*x2-x*x);
b_coef=(y-a_coef*x)/N;
//—
return (true);
}
//+——————————————————————+
//|  指定されたaとbの平均二乗偏差誤差を計算する                               |
//+——————————————————————+
bool  CalculateStdError(double  &data[],double  a_coef,double  b_coef,double &std_err)
{
//— 誤差の平方和
double error=0;
int N=ArraySize(data);
if(N==0)
return (false);
for(int i=0;i<N;i++)
error=MathPow(a_coef*i+b_coef-data[i],2);
std_err=MathSqrt(error/(N-2));
//—
return (true);
}

参照

Testing trading strategies、TesterHideIndicators、Working with optimization results、TesterStatistics、OnTesterInit、OnTesterDeinit、OnTesterPass、MQL_TESTER、MQL_OPTIMIZATION、FileOpen、FileWrite、FileLoad、FileSave

OnTesterInit

この関数は、 TesterInitイベントが発生してストラテジーテスターでの最適化に先立って必要なアクションが実行されるときに、EAで呼び出されます。この関数の型は 2 つあります。

結果を返すバージョン

int  OnTesterInit(void);

戻り値

int型の値。ゼロは、最適化が開始される前にチャート上で起動されたEAの初期化に成功したことを意味します。

実行結果を返すOnTesterInit() を呼び出すと、プログラムを初期化できるだけでなく、最適化が異常に終了した場合にはエラーコードが返されるため、これを使用することをお勧めします。INIT_SUCCEEDED (0)以外の戻り値はエラーを意味し、最適化は行われません。

結果を返さないバージョンは古いコードとの相互性の為のみに残されています。使用は推奨されません。

void  OnTesterInit(void);

注意事項

TesterInitイベントは、ストラテジーテスターにおけるEAの最適化の前に生成されます。このイベントでは、OnTesterDeInit()またはOnTesterPass()イベントハンドラを持つEAが自動的に別の端末チャートにダウンロードされます。テスターで指定されたシンボルと期間があります。

このようなイベントはTesterInit、TesterDeinit、TesterPassイベントを受信しますが、Init、Deinit、 NewTickイベントは受信されません。したがって、最適化中に各パスの結果を処理するために必要なロジックはすべて、OnTesterInit ()、OnTesterDeinit ()、OnTesterPass ()ハンドラで実装されるべきです。

戦略最適化中の各シングルパスの結果は、FrameAdd ()関数を使用してOnTester ()ハンドラからフレームを介して渡すことができます。

OnTesterInit()関数は、最適化を開始する前にエキスパートアドバイザーを起動して、最適化結果をさらに処理するために使用されます。これは常にOnTesterDeinit()ハンドラと共に使用されます。

OnTesterInit()の実行時間は制限されています。超過した場合、EAは強制的に停止され、最適化自体は取り消されます。テスター操作ログにメッセージが表示されます。

Tester        OnTesterInit works too long. Tester cannot be initialized.

例はOnTickからとられています。 OnTesterInit()ハンドラは最適化パラメータを設定するために追加されました。:

//+——————————————————————+
//|                                          OnTesterInit_Sample.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+——————————————————————+
#property copyright “Copyright 2018, MetaQuotes Software Corp.”
#property link     “https://www.mql5.com”
#property version   “1.00”
#property description “Sample EA with the OnTesterInit() handler,”
#property description “in which values and limitations of “
#property description “inputs during optimization are set”

input double lots=0. 1;       // ロット単位のボリューム
input double kATR=3;         // ATRのシグナルローソク足の長さ
input int   ATRperiod=20;   // ATR指標期間
input int   holdbars=8;     // ポジションのバー数
input int   slippage=10;     // 許容されるスリッページ
input bool   revers=false;   // シグナルを反転するかどうか
input ulong EXPERT_MAGIC=0; // EAのマジックナンバー
//— ATR指標ハンドルを格納
int atr_handle;
//— ここで最後のATR値とローソク足のの実体を保存する
double last_atr,last_body;
datetime lastbar_timeopen;
double trade_lot;
//— 最適化開始時間を記憶する
datetime optimization_start;
//— 最適化が終了した後にチャートに期間を表示する
string report;
//+——————————————————————+
//| TesterInit 関数                                                   |
//+——————————————————————+
void OnTesterInit()
{
//— 最適化のための入力値を設定する
ParameterSetRange(“lots”,false,0.1,0,0,0);
ParameterSetRange(“kATR”,true,3.0,1.0,0.3,7.0);
ParameterSetRange(“ATRperiod”,true,10,15,1,30);
ParameterSetRange(“holdbars”,true,5,3,1,15);
ParameterSetRange(“slippage”,false,10,0,0,0);
ParameterSetRange(“revers”,true,false,false,1,true);
ParameterSetRange(“EXPERT_MAGIC”,false,123456,0,0,0);
Print(“Initial values and optimization parameter limitations are set”);
//— 最適化開始時間を記憶する
optimization_start=TimeLocal();
report=StringFormat(“%s: optimization launched at %s”,
__FUNCTION__,TimeToString(TimeLocal(),TIME_MINUTES|TIME_SECONDS));
//— メッセージをチャートと端末操作ログに表示する
Print(report);
Comment(report);
//—  
}
//+——————————————————————+
//| TesterDeinit 関数                                                 |
//+——————————————————————+
void OnTesterDeinit()
{
//— 最適化期間
string log_message=StringFormat(“%s: optimization took %d seconds”,
__FUNCTION__,TimeLocal()-optimization_start);
PrintFormat(log_message);
report=report+“\r\n”+log_message;
Comment(report);
}
//+——————————————————————+
//| エキスパート初期化関数                                                 |
//+——————————————————————+
int OnInit()
{
//— グローバル変数を初期化する
last_atr=0;
last_body=0;
//— 正しいボリュームを設定する
double min_lot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
trade_lot=lots>min_lot?lots:min_lot;
//— ATR指標ハンドルを作成する
atr_handle=iATR(_Symbol,_Period,ATRperiod);
if(atr_handle==INVALID_HANDLE)
{
PrintFormat(“%s: failed to create iATR, error code %d”,__FUNCTION__,GetLastError());
return(INIT_FAILED);
}
//— EA初期化が成功した
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| エキスパートティック関数                                                 |
//+——————————————————————+
void OnTick()
{
//— 取引シグナル
static int signal=0; // +1は買いシグナル、 -1は売りシグナル
//— ‘holdbars’バーより前に開かれた以前のポジションを確認して決済する
ClosePositionsByBars(holdbars,slippage,EXPERT_MAGIC);
//— 新しいバーを確認する
if(isNewBar())
{
//— シグナルの存在を確認する
signal=CheckSignal();
}
//— ネットポジションが開かれている場合は、信号をスキップして終了する
if(signal!=0 && PositionsTotal()>0 && (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_NETTING)
{
signal=0;
return; // NewTickイベントハンドラを終了し、新しいバーが現れる前に市場に入らない
}
//— ヘッジ口座の場合、各ポジションは個別に保持され、決済される
if(signal!=0)
{
//— 買いシグナル
if(signal>0)
{
PrintFormat(“%s: Buy signal!Revers=%s”,__FUNCTION__,string(revers));
if(Buy(trade_lot,slippage,EXPERT_MAGIC))
signal=0;
}
//— 売りシグナル
if(signal<0)
{
PrintFormat(“%s: Sell signal!Revers=%s”,__FUNCTION__,string(revers));
if(Sell(trade_lot,slippage,EXPERT_MAGIC))
signal=0;
}
}
//— OnTick関数の終わり
}
//+——————————————————————+
//| 新しい取引シグナルを確認する                                            |
//+——————————————————————+
int CheckSignal()
{
//— 0はシグナルが不在なことを意味する
int res=0;
//— 終わりから2番目の完全なバーにATR値を取得する(バーのインデックスは2)
double atr_value[1];
if(CopyBuffer(atr_handle,0,2,1,atr_value)!=-1)
{
last_atr=atr_value[0];
//— 最後に閉じたバーのデータをMqlRates型配列に取得する
MqlRates bar[1];
if(CopyRates(_Symbol,_Period,1,1,bar)!=-1)
{
//— 最後の完全なバーでバー本体のサイズを計算する
last_body=bar[0].close-bar[0].open;
//— 最後のバー(インデックス1)の本体が以前のATR値(インデックス2のバー上)を超える場合、取引シグナルが受信される
if(MathAbs(last_body)>kATR*last_atr)
res=last_body>0?1:-1; // 上昇ローソク足では正の値
}
else
PrintFormat(“%s: Failed to receive the last bar!Error”,__FUNCTION__,GetLastError());
}
else
PrintFormat(“%s: Failed to receive ATR indicator value!Error”,__FUNCTION__,GetLastError());
//— 反転取引モードが有効な場合
res=revers?-res:res; // 必要に応じてシグナルを反転させる(1の代わりに-1を返し、逆も同様)
//— 取引シグナル値を返す
return (res);
}
//+——————————————————————+
//|   新しいバーが現れると’true’                                           |
//+——————————————————————+
bool isNewBar(const bool print_log=true)
{
static datetime bartime=0; // 現在のバーの開いた時刻を格納する
//— ゼロバーの開いた時間を取得する
datetime currbar_time=iTime(_Symbol,_Period,0);
//— 新しいバーが到着すると開いた時刻が変わる
if(bartime!=currbar_time)
{
bartime=currbar_time;
lastbar_timeopen=bartime;
//— ログに新しいバーが開いている時間のデータを表示する
if(print_log && !(MQLInfoInteger(MQL_OPTIMIZATION)||MQLInfoInteger(MQL_TESTER)))
{
//— 新しいバーを開いた時間のメッセージを表示する
PrintFormat(“%s: new bar on %s %s opened at %s”,__FUNCTION__,_Symbol,
StringSubstr(EnumToString(_Period),7),
TimeToString(TimeCurrent(),TIME_SECONDS));
//— 最後のティックのデータを取得する
MqlTick last_tick;
if(!SymbolInfoTick(Symbol(),last_tick))
&nbsnbsp; Print(“SymbolInfoTick() failed, error = “,GetLastError());
//— 最後のティックタイムをミリ秒まで表示する
PrintFormat(“Last tick was at %s.%03d”,
TimeToString(last_tick.time,TIME_SECONDS),last_tick.time_msc%1000);
}
//— 新しいバーがある
return (true);
}
//— 新しいバーがない
return (false);
}
//+——————————————————————+
//| 成行価格で指定された量で買う                                            |
//+——————————————————————+
bool Buy(double volume,ulong deviation=10,ulong  magicnumber=0)
{
//— 成行価格で買う
return (MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber));
}
//+——————————————————————+
//| 成行価格で指定された量で売る                                           |
//+——————————————————————+
bool Sell(double volume,ulong deviation=10,ulong  magicnumber=0)
{
//— 成行価格で売る
return (MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber));
}
//+——————————————————————+
//| バー数によるポジション保留時間ごとにポジションを決済する                          |
//+——————————————————————+
void ClosePositionsByBars(int holdtimebars,ulong deviation=10,ulong  magicnumber=0)
{
int total=PositionsTotal(); // ポジション数
//— ポジションをすべて見る
for(int i=total-1; i>=0; i–)
{
//— ポジションパラメータ
ulong  position_ticket=PositionGetTicket(i);                                     // ポジションチケット
string position_symbol=PositionGetString(POSITION_SYMBOL);                       // シンボル
ulong  magic=PositionGetInteger(POSITION_MAGIC);                                 // ポジションマジックナンバー
datetime position_open=(datetime)PositionGetInteger(POSITION_TIME);               // ポジションの開かれた時刻
int bars=iBarShift(_Symbol,PERIOD_CURRENT,position_open)+1;                       // ポジションがどれだけ前(バー数)に開かれたか

//— マジックナンバーとシンボルが一致していてポジションがすでに長くある場合
if(bars>holdtimebars && magic==magicnumber && position_symbol==_Symbol)
{
int   digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);           // 小数点以下桁数
double volume=PositionGetDouble(POSITION_VOLUME);                             // ポジションボリューム
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // ポジションの種類
string str_type=StringSubstr(EnumToString(type),14);
StringToLower(str_type); // 正しいメッセージ書式設定のために小文字にする
PrintFormat(“Close position #%d %s %s %.2f”,
position_ticket,position_symbol,str_type,volume);
//— 注文タイプを設定し、取引リクエストを送信する
if(type==POSITION_TYPE_BUY)
MarketOrder(ORDER_TYPE_SELL,volume,deviation,magicnumber,position_ticket);
else
MarketOrder(ORDER_TYPE_BUY,volume,deviation,magicnumber,position_ticket);
}
}
}
//+——————————————————————+
//| 取引リクエストを準備して送信する                                          |
//+——————————————————————+
bool MarketOrder(ENUM_ORDER_TYPE type,double volume,ulong slip,ulong magicnumber,ulong pos_ticket=0)
{
//— 構造体の宣言と初期化
MqlTradeRequest request={0};
MqlTradeResult  result={0};
double price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
if(type==ORDER_TYPE_BUY)
price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
//— リクエストパラメータ
request.action   =TRADE_ACTION_DEAL;                     // 取引操作の種類
request.position =pos_ticket;                           // 決済する場合のポジションチケット
request.symbol   =Symbol();                             // シンボル
request.volume   =volume;                               // ボリューム
request.type     =type;                                 // 注文の種類
request.price    =price;                                 // 取引価格
request.deviation=slip;                                 // 価格からの許容偏差
request.magic    =magicnumber;                           // 注文のマジックナンバー
//— リクエストを送信する
if(!OrderSend(request,result))
{
//— 失敗したらデータを表示する
PrintFormat(“OrderSend %s %s %.2f at %.5f error %d”,
request.symbol,EnumToString(type),volume,request.price,GetLastError());
return (false);
}
//— 操作の成功を知らせる
PrintFormat(“retcode=%u  deal=%I64u  order=%I64u”,result.retcode,result.deal,result.order);
return (true);
}

参照

Testing trading strategies、Working with optimization results、OnTesterDeinit、OnTesterPass、ParameterGetRange、ParameterSetRange

OnTesterDeinit

この関数は、EA最適化の後にTesterDeinit イベントが発生したときに、EAで呼び出されます。

void  OnTesterDeinit(void);

戻り値

なし

注意事項

TesterDeinitイベントは、ストラテジーテスターにおけるEAの最適化の終了後に生成されます。

OnTesterDeInit()またはOnTesterPass() イベントハンドラを持つEAは、最適化開始時に別の端末チャートに自動的にダウンロードされます。テスターで指定されたシンボルと期間があります。関数はすべての最適化結果の最終処理用に設計されています。

FrameAdd()関数を使用してテストエージェントによって送信された最適化フレームはバンドルされ、配信に時間がかかることに注意してください。よって、すべてのフレームやTesterPassイベントが最適化が終わるまでに到着しOnTesterPass()で処理されるわけではありません。遅れているフレームをすべてOnTesterDeinit()で受け取る場合は、FrameNext()関数を使用してコードブロックを配置します。

参照

Testing trading strategies、Working with optimization results、TesterStatistics、OnTesterInit、OnTesterPass、ParameterGetRange、ParameterSetRange

OnTesterPass

この関数は、EA最適化中に新しいデータフレームを処理するためにTesterPassTesterPassイベントが発生するときに、EAで呼び出されます。

void  OnTesterPass(void);

戻り値

なし

注意事項

TesterPassイベントは、ストラテジーテスターでのエキスパートアドバイザーの最適化中にフレームを受け取ると自動的に生成されます。

OnTesterDeInit()またはOnTesterPass() イベントハンドラを持つEAは、最適化開始時に別の端末チャートに自動的にダウンロードされます。テスターで指定されたシンボルと期間があります。この関数は、最適化中にテストエージェントから受信したフレームを処理するためのものです。テスト結果を含むフレームは、FrameAdd()関数を使用してOnTester()ハンドラ−から送信する必要があります。

FrameAdd()関数を使用してテストエージェントによって送信された最適化フレームはバンドルされ、配信に時間がかかることに注意してください。よって、すべてのフレームやTesterPassイベントが最適化が終わるまでに到着しOnTesterPass()で処理されるわけではありません。遅れているフレームをすべてOnTesterDeinit()で受け取る場合は、FrameNext()関数を使用してコードブロックを配置します。

OnTesterDeinit()の最適化を完了すると、FrameFirst()/FrameFilterとFrameNext()関数を使用して再び、受け取ったフレームをすべて並び替えることができます。

参照

Testing trading strategies、Working with optimization results、OnTesterInit、OnTesterDeinit、FrameFirst、FrameFilter、FrameNext、FrameInputs

Originally posted 2019-07-29 23:21:08.

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">