OnTesterInit関数を使ったサンプルコードの解説その6-isNewBar関数部分-

MQL5リファレンス

OnTesterInit関数について解説した記事内↓にて、

OnTesterInit関数を利用したサンプルコードも掲載しているのですが、同じ記事内で解説するには、ちょっと長くて複雑だったもので、別記事にして数回に分けて解説しています。

前回はCheckSignal関数部分の記述について解説をおこないました↓

今回解説する記述は以下の箇所です。

//+------------------------------------------------------------------+
//|   新しいバーが生成されたか確認する関数                           |
//|   新しいバーが生成された場合にtrueを返し、そうでない場合はfalseを返す|
//+------------------------------------------------------------------+
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: %s %s に新しいバーが生成されました", __FUNCTION__, _Symbol, StringSubstr(EnumToString(_Period), 7));

            //--- 最後のティックデータを取得
            MqlTick last_tick;
            if (!SymbolInfoTick(Symbol(), last_tick))  // ティック情報の取得に失敗した場合
                Print("SymbolInfoTick() に失敗しました。エラーコード:", GetLastError());
            
            //--- 最後のティックの時刻をミリ秒まで表示
            PrintFormat("最終ティックの時刻: %s.%03d", TimeToString(last_tick.time, TIME_SECONDS), last_tick.time_msc % 1000);
        }
        return (true);  // 新しいバーが生成された場合はtrueを返す
    }
    return (false);  // 新しいバーが生成されていない場合はfalseを返す
}

スポンサーリンク
スポンサーリンク

isNewBar関数の記述解説その1

//+------------------------------------------------------------------+
//|   新しいバーが生成されたか確認する関数                           |
//|   新しいバーが生成された場合にtrueを返し、そうでない場合はfalseを返す|
//+------------------------------------------------------------------+
bool isNewBar(const bool print_log = true)
{
    static datetime bartime = 0;  // 現在のバーの開始時刻を保持する変数

    //--- 現在のバー(ゼロバー)の開始時刻を取得
    datetime currbar_time = iTime(_Symbol, _Period, 0);

isNewBar関数は、新しいバーが生成されたかどうかを確認し、生成された場合にtrueを、そうでない場合にfalseを返します。この判定により、エキスパートアドバイザーEA)がティックごとではなく、新しいバーが形成されたタイミングで特定の処理を行うことが可能になります。

引数の解説

  • print_log
    関数引数であるprint_logは、ログ出力を行うかどうかを制御します。この引数がtrueの場合、新しいバーが生成された際に詳細なログが出力されます。falseに設定すると、ログ出力はスキップされ、バーの生成確認のみが行われます。デフォルト値としてtrueが指定されているため、引数を指定しない場合でもログ出力が有効な状態になります。

変数の解説

  • bartime
    static指定子を持つdateTime型のbartimeは、関数呼び出しの間も値が保持される変数です。この変数には「前回取得したバーの開始時刻」が記録され、現在のバーと前回のバーの時刻を比較することで、新しいバーが生成されたかを判定します。初期値は0に設定されています。

処理の解説

関数内で、iTime関数を使って現在のバー(ゼロバー)の開始時刻を取得し、dateTime型のcurrbar_timeに格納しています。この時刻が前回のバー時刻と異なる場合、新しいバーが生成されたと判定します。

isNewBar関数の記述解説その2

 //--- 以前のバーと異なる時刻なら新しいバーが生成されたと判断
    if (bartime != currbar_time)
    {
        bartime = currbar_time;  // 現在のバー開始時刻を更新
        lastbar_timeopen = bartime;  // 最後のバー開始時刻を保存

この部分のコードでは、現在のバーが前回のバーと異なる時刻であれば「新しいバーが生成された」と判断します。bartimeとcurrbar_timeを比較することで、この判定を行っています。

処理の詳細

  • 新しいバーの生成判定
    if文で、前回のバーの開始時刻(bartime)と現在のバーの開始時刻(currbar_time)を比較しています。もし異なる時刻であれば、新しいバーが生成されたと判断され、if文の内部の処理が実行されます。
  • bartimeの更新
    新しいバーが生成された場合、bartimeを現在のバー開始時刻であるcurrbar_timeに更新します。この処理により、次回以降の関数呼び出し時には新しいバーの開始時刻が基準として使用され、正確にバー生成を検出できるようになります。
  • lastbar_timeopenの更新
    最新のバーの開始時刻をlastbar_timeopen変数に格納します。この変数は他の関数やプロセスでも新しいバーの時刻を利用できるようにするためのもので、新しいバーが生成されたタイミングで更新されます。

これらの処理により、EAは新しいバーが形成されたタイミングを認識し、そのタイミングで取引戦略のロジックを実行することが可能になります。

isNewBar関数の記述解説その3

//--- 新しいバーが生成されたことをログに表示(最適化またはテスト中でない場合)
        if (print_log && !(MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_TESTER)))
        {
            PrintFormat("%s: %s %s に新しいバーが生成されました",
                         __FUNCTION__, _Symbol, StringSubstr(EnumToString(_Period), 7));

このコードでは、新しいバーが生成されたときにその情報をログに出力しています。最適化またはテスト中でない場合のみ、ログが表示されます。この処理によって、EAの動作状況を確認しやすくなり、開発やデバッグに役立ちます。

条件文の詳細と日本語和訳

if (print_log && !(MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_TESTER)))

この条件文は、「print_logがtrueであり、かつ現在が最適化中またはテスト中でない場合」にのみログを出力するためのものです。日本語に和訳すると、以下のようになります。

「print_logがtrueであり、かつ最適化またはテスト中ではない場合」

使用されている関数の解説

  • MQLInfoInteger関数
    この関数は、MQL5プログラムの情報を整数として取得します。引数として渡した定数に応じて、最適化やテストなどの現在のプログラムの状態を確認できます。
    • MQL_OPTIMIZATION
      定数MQL_OPTIMIZATIONは、現在が最適化中であるかどうかを判定するためのもので、最適化中なら1、そうでない場合は0を返します。
    • MQL_TESTER
      定数MQL_TESTERは、現在がテスト中であるかどうかを判定するためのもので、テスト中なら1、そうでない場合は0を返します。

この条件文では、MQLInfoInteger(MQL_OPTIMIZATION)とMQLInfoInteger(MQL_TESTER)のどちらかが1の場合、EAが最適化またはテスト中であると判断されます。この場合、ログ出力を行わないようにしています。

ログ出力の詳細

PrintFormat("%s: %s %s に新しいバーが生成されました",
       __FUNCTION__, _Symbol, StringSubstr(EnumToString(_Period), 7));

フォーマット指定子と対応する値

このコードで使用されているフォーマット指定子と対応する値は以下の通りです。

  1. %s: 現在の関数名(__FUNCTION__
    __FUNCTION__は現在実行中の関数名(ここではisNewBar)を文字列として返します。この指定子を使って、エラー発生や特定の処理がどの関数で行われたかを確認できるようにしています。
  2. %s: シンボル名(_Symbol
    _Symbolは、現在取引中の通貨ペアや金融商品を示すシンボル名を返します。ここでの%指定子は、シンボル名をログに表示し、EAがどのシンボルで動作しているかを明示します。
  3. %s: 時間足(StringSubstr(EnumToString(_Period), 7)) _Periodは、現在の時間足を示す定数です。EnumToString関数関数を使用して数値を文字列に変換した後、StringSubstr関数で一部を抽出して表示しています。このコードでは、”PERIOD”の文字列を除くために7文字目以降を取り出し、M1、M5、H1などの時間足形式で表示しています。

このように、PrintFormat関数はログメッセージに各情報を表示するために使われており、新しいバーが生成されたタイミングを確認するために役立ちます。

isNewBar関数の記述解説その4

 //--- 最後のティックデータを取得
            MqlTick last_tick;
            if (!SymbolInfoTick(Symbol(), last_tick))  // ティック情報の取得に失敗した場合
                Print("SymbolInfoTick() に失敗しました。エラーコード:", GetLastError());
            
            //--- 最後のティックの時刻をミリ秒まで表示
            PrintFormat("最終ティックの時刻: %s.%03d", TimeToString(last_tick.time, TIME_SECONDS), last_tick.time_msc % 1000);
        }
        return (true);  // 新しいバーが生成された場合はtrueを返す
    }
    return (false);  // 新しいバーが生成されていない場合はfalseを返す
}

この部分では、新しいバーが生成された場合に、最後のティックデータを取得してその詳細をログに出力しています。また、新しいバーが生成されているかどうかに応じてtrueまたはfalseを返しています。

処理の詳細

  • MqlTick構造体の宣言
    MqlTick構造体型のlast_tickを宣言し、最後のティックデータ(最新の価格情報や時間など)を格納するための準備を行います。MqlTick構造体には、ティックデータの詳細情報が含まれており、取引に関するさまざまな判断に役立ちます。
  • SymbolInfoTick関数を使用してティックデータを取得
    SymbolInfoTick関数を用いて、現在のシンボルに関する最新のティック情報を取得し、last_tick構造体に格納します。この関数は、取得が成功すればtrueを、失敗すればfalseを返します。取得に失敗した場合には、Print関数でエラーメッセージを出力し、GetLastError関数でエラーコードを取得して表示します。このエラーコードにより、何が原因でティックデータの取得に失敗したのかを把握できます。
  • 最後のティック時刻をミリ秒までログ出力
    PrintFormat関数を使い、取得したティックの時刻をミリ秒単位で表示します。時刻を文字列として表示するために、TimeToString関数を使用しています。この関数にTIME_SECONDSフラグを渡すことで、時刻が「時:分:秒」の形式で表示されます。ティックの詳細な時間は、last_tick.time_mscを用いてミリ秒単位で取得し、「%03d」のフォーマット指定子を使って、3桁のミリ秒部分をゼロ埋めして表示しています。

処理の戻り値

  • 新しいバーが生成された場合
    新しいバーが生成されたと判断された場合、関数はtrueを返します。これは、他の関数や条件が「新しいバーが生成された」状態で実行されるべき処理をトリガーするために使用されます。
  • 新しいバーが生成されていない場合
    if文の条件に合致しなかった場合、新しいバーは生成されていないと判断され、falseが返されます。この戻り値を受け取り、EAの内部でバー生成時のみに行うべき処理と、ティックごとに実行する処理を分けることが可能になります。

サンプルコードの全体記述

OnTesterInit関数を利用したサンプルコードの全体記述は以下の通りです。



//--- EAの設定パラメータ
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の識別用のマジックナンバー

//--- 変数宣言
int atr_handle;                // ATR指標のハンドルを格納する変数
double last_atr, last_body;    // 最後に取得したATR値とローソク足の実体サイズを格納
datetime lastbar_timeopen;     // 最後のバーが開いた時間
double trade_lot;              // 実行する取引のロット数を格納
datetime optimization_start;   // 最適化開始時刻を記録
string report;                 // 結果を格納する文字列

//+------------------------------------------------------------------+
//| TesterInit関数                                                   |
//| 最適化開始前に呼び出され、EAパラメータの初期化を行う               |
//+------------------------------------------------------------------+
void OnTesterInit()
{
    //--- 最適化パラメータの範囲を設定
    ParameterSetRange("lots", false, 0.1, 0, 0, 0);             // 取引量の最小値、最大値、初期値の設定
    ParameterSetRange("kATR", true, 3.0, 1.0, 0.3, 7.0);        // ATR倍率の設定範囲
    ParameterSetRange("ATRperiod", true, 10, 15, 1, 30);        // ATR計算期間の設定範囲
    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);  // EA識別用マジックナンバーの設定

    //--- 初期化完了メッセージを出力
    Print("初期化と最適化パラメータが設定されました");

    //--- 最適化開始時刻を記録
    optimization_start = TimeLocal();

    //--- チャートおよびログに最適化開始のメッセージを表示
    report = StringFormat("%s: 最適化は %s に開始されました", __FUNCTION__, TimeToString(TimeLocal(), TIME_MINUTES|TIME_SECONDS));
    Print(report);  // ログ出力
    Comment(report); // チャート上に表示
}

//+------------------------------------------------------------------+
//| TesterDeinit関数                                                 |
//| 最適化終了後に呼び出され、実行時間を出力する                       |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
    //--- 実行時間を計算してログ出力
    string log_message = StringFormat("%s: 最適化にかかった時間は %d 秒", __FUNCTION__, TimeLocal() - optimization_start);
    PrintFormat(log_message);  // 実行時間をログに出力

    //--- 結果をレポートに追加し、画面表示を更新
    report = report + "\r\n" + log_message;
    Comment(report);
}

//+------------------------------------------------------------------+
//| EA初期化関数                                                     |
//| EAの開始時に呼び出され、変数やATR指標の初期化を行う               |
//+------------------------------------------------------------------+
int OnInit()
{
    //--- 初期値設定
    last_atr = 0;  // ATR値の初期化
    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);  // ATRのハンドルを作成
    if (atr_handle == INVALID_HANDLE)  // ハンドル取得に失敗した場合
    {
        // ATRの作成に失敗した場合、エラーメッセージを出力
        PrintFormat("%s: iATRの作成に失敗しました。エラーコード: %d", __FUNCTION__, GetLastError());
        return (INIT_FAILED);  // 初期化失敗を返す
    }
    
    //--- EAの初期化が成功したことを示す戻り値
    return (INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| 新しいティックが到着したときに呼び出される                       |
//| 各バーごとに取引シグナルを確認し、必要ならばポジションを取る       |
//+------------------------------------------------------------------+
void OnTick()
{
    //--- 取引シグナルを保持する変数(0はシグナルなし、1は買い、-1は売り)
    static int signal = 0;  

    //--- 保持バー数に基づいて古いポジションを決済
    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;      // 新しいティックイベントを終了
    }

    //--- ヘッジモードの場合、シグナルに基づいてポジションを取る
    if (signal != 0)
    {
        //--- 買いシグナルの場合
        if (signal > 0)  
        {
            PrintFormat("%s: 買いシグナル!Revers = %s", __FUNCTION__, string(revers));
            if (Buy(trade_lot, slippage, EXPERT_MAGIC)) signal = 0;  // 買い注文が成功したらシグナルをリセット
        }
        //--- 売りシグナルの場合
        else if (signal < 0)  
        {
            PrintFormat("%s: 売りシグナル!Revers = %s", __FUNCTION__, string(revers));
            if (Sell(trade_lot, slippage, EXPERT_MAGIC)) signal = 0;  // 売り注文が成功したらシグナルをリセット
        }
    }
}

//+------------------------------------------------------------------+
//| 取引シグナルを生成する関数                                       |
//| ATRを使用してシグナルを確認し、シグナルがあれば1(買い)または-1(売り)を返す |
//+------------------------------------------------------------------+
int CheckSignal()
{
    int res = 0;  // 初期値(シグナルがない状態)

    //--- ATR指標の値を取得
    double atr_value[1];  // ATR値を格納する配列
    if (CopyBuffer(atr_handle, 0, 2, 1, atr_value) != -1)  // ATR指標から値を取得
    {
        last_atr = atr_value[0];  // 最新のATR値を変数に格納

        //--- 最新のバーのデータを取得
        MqlRates bar[1];  // ローソク足のデータを格納する変数
        if (CopyRates(_Symbol, _Period, 1, 1, bar) != -1)  // 最新のローソク足データを取得
        {
            last_body = bar[0].close - bar[0].open;  // 実体サイズを計算(終値-始値)

            //--- 実体サイズがATRの指定倍率を超えた場合、シグナルを設定
            if (MathAbs(last_body) > kATR * last_atr)  // 実体が一定以上の場合
                res = last_body > 0 ? 1 : -1;  // 上昇ローソクなら買いシグナル、下降なら売りシグナル
        }
        else  // ローソク足データの取得に失敗した場合
        {
            PrintFormat("%s: 最新のバー取得に失敗!エラー: %d", __FUNCTION__, GetLastError());
        }
    }
    else  // ATR指標値の取得に失敗した場合
    {
        PrintFormat("%s: ATR指標値取得に失敗!エラー: %d", __FUNCTION__, GetLastError());
    }

    //--- シグナル反転の設定がされている場合、シグナルを反転
    res = revers ? -res : res;  // シグナルを反転
    return (res);  // シグナル値を返す
}



//+------------------------------------------------------------------+
//|   新しいバーが生成されたか確認する関数                           |
//|   新しいバーが生成された場合にtrueを返し、そうでない場合はfalseを返す|
//+------------------------------------------------------------------+
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: %s %s に新しいバーが生成されました", __FUNCTION__, _Symbol, StringSubstr(EnumToString(_Period), 7));

            //--- 最後のティックデータを取得
            MqlTick last_tick;
            if (!SymbolInfoTick(Symbol(), last_tick))  // ティック情報の取得に失敗した場合
                Print("SymbolInfoTick() に失敗しました。エラーコード:", GetLastError());
            
            //--- 最後のティックの時刻をミリ秒まで表示
            PrintFormat("最終ティックの時刻: %s.%03d", TimeToString(last_tick.time, TIME_SECONDS), last_tick.time_msc % 1000);
        }
        return (true);  // 新しいバーが生成された場合はtrueを返す
    }
    return (false);  // 新しいバーが生成されていない場合はfalseを返す
}

//+------------------------------------------------------------------+
//| 成行価格で指定の量を買う関数                                      |
//| 指定されたボリュームで成行買い注文を実行し、成功でtrueを返す       |
//+------------------------------------------------------------------+
bool Buy(double volume, ulong deviation = 10, ulong magicnumber = 0)
{
    //--- 買い注文を行う
    return (MarketOrder(ORDER_TYPE_BUY, volume, deviation, magicnumber));
}

//+------------------------------------------------------------------+
//| 成行価格で指定の量を売る関数                                      |
//| 指定されたボリュームで成行売り注文を実行し、成功でtrueを返す       |
//+------------------------------------------------------------------+
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("ポジション #%I64u %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);
        }
    }
}

//+------------------------------------------------------------------+
//| 成行注文を準備して送信する関数                                    |
//| 指定された注文内容で成行注文を送信し、成功でtrueを返す             |
//+------------------------------------------------------------------+
bool MarketOrder(ENUM_ORDER_TYPE type, double volume, ulong slip, ulong magicnumber, ulong pos_ticket = 0)
{
    MqlTradeRequest request = {};  // 取引リクエスト構造体の初期化
    MqlTradeResult result = {};    // 取引結果構造体の初期化
    double price = SymbolInfoDouble(Symbol(), SYMBOL_BID);  // 成行注文の価格を取得

    //--- 注文タイプが買いの場合は買い価格(ASK)を設定
    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;               // マジックナンバーを設定

    //--- 注文を送信し、成功すればtrueを返す
    if (!OrderSend(request, result))
    {
        // 注文送信に失敗した場合、エラーメッセージを出力
        PrintFormat("OrderSend %s %s %.2f at %.5f エラーコード: %d", request.symbol, EnumToString(type), volume, request.price, GetLastError());
        return (false);  // 注文が失敗した場合にfalseを返す
    }

    //--- 注文が成功した場合の結果を表示
    PrintFormat("リクエストコード = %u、取引 = %I64u、注文番号 = %I64u", result.retcode, result.deal, result.order);
    return (true);  // 成功時にtrueを返す
}
タイトルとURLをコピーしました