トップ  >  自作してみる >  エキスパートアドバイザー(EA)作成の基本  >  es4.注文の変更(リミット・ストップの設定)
スポンサーリンク
検索

↑の検索エンジンが表示されない人は、
↓の古い検索エンジンを使用して下さい。
カスタム検索
MQL4リファレンスツリー
es4.注文の変更(リミット・ストップの設定)



注意事項:
このページにあるサンプルソースは、実際に売買を行う処理が含まれているので、絶対にライブ口座では実行しないで下さい。 念の為、デモ口座でしか処理しない対策処理を施しています。
これはあくまで勉強用のソースコードです。

リミット・ストップの手動設定

MQL4でのリミット・ストップの設定(または変更)の説明する前に、いつも通りMT4での操作から確認しましょう。
リミットやストップを設定する時は、設定したいポジションを選択して「注文変更または取消」をクリックします。

Order_Modify

注文画面が開かれたら、決済逆指値の価格か、決済指値の価格(または両方)の設定をして発注します。
Order_Modify

ちなみに決済逆指値や決済指値の価格に異常があれば発注ボタンは押せない状態になります。
Order_Modify

決済逆指値や決済指値で設定できる価格についてはH3.板情報と指値注文・逆指値注文について参照。

業者側の制限に引っかからなければ注文を受け付けてくれます。
Order_Modify

ポジションの決済逆指値・決済指値の値が変更されました。
Order_Modify

操作履歴のログにも、注文変更を発注して、サーバー側が受け付けた記録が残っています。
Order_Modify

MT4で手動でリミット・ストップを設定する時はこの手順を踏む必要があります。
何度も言っていますが1から10まで指示しなければならないのがプログラムなので、
手動でやっていた事は「プログラムではやらなくて良い」なんて事はありません。


OrderSelect()でチケットNo指定選択する

前回説明しましたが、保有ポジションに対して何かしたい場合は、まずOrderSelect()関数を使ってポジションを選択する必要があります。
前回ポジション選択するプログラムを作成したのでそれを流用しましょう。
前回es3.ポジションの選択で作成したTest_TradeOrderSelectPosition.mq4をコピペしてTest_TradeOrderModify.mq4に名前を変更して下さい。


MQL4でリミットの設定(または変更)をするにはOrderModify()関数を使用します。
注文変更用の内部関数を作成して、その関数内にソースコードを追記します。
OrderModify()を使う時にチケットNoを指定する必要があるので、最初にポジション選択の処理を追加します。


ソースコード:
//+------------------------------------------------------------------+
//| 注文変更
//+------------------------------------------------------------------+
bool Modify_Order( int in_ticket ){

    bool ret = false;                // 戻り値
    bool select_bool;                // ポジション選択結果

    // ポジションを選択
    select_bool = OrderSelect(
                    in_ticket ,      // チケットNo
                    SELECT_BY_TICKET // チケット指定で注文選択
                ); 

    // ポジション選択失敗時
    if ( select_bool == false ) {
        return ret;    // 処理終了
    }

    return ret;    // 戻り値を返す
}



前回登場したOrderSelect()関数がまた登場しましたが、
今回は第2引数をSELECT_BY_TICKETにしてチケット指定にしているので、ポジションのインデックスでは無く、
ダイレクトにチケットNo指定でポジションを選択します。

勘の良い人は気がついたかもしれませんが、
「どうしてインデックス指定でポジション選択をしているのに、今度はチケットNoで再びポジション選択をしているの?」と疑問に思いませんでした?

これは単純にこの注文変更用の関数を独立させて、他関数との結合度を無くす為です。

プログラミング経験が少ない人にはちょっと分かり難いかもしれませんが、
結合度の高い関数は他関数との依存度が高く、他関数と一緒に使わないと正常に動作しません。
現実社会で例えるなら常に先輩に質問して一人で仕事をこなす事が出来ず、先輩と一緒に作業をさせないとまともに仕事が出来ない依存度の高い社員です。
Order_Modify

結合度が低く独立した関数は、他関数と一緒に使わなくてもそれ単体で正常動作出来る関数です。
現実社会で例えるなら一人で仕事をこなせる他人への依存度の低い社員です。
Order_Modify

関数の結合度を無くす事で、この関数内で何か不具合があった時にこの独立した関数内だけをデバッグすれば良くなります。

OrderModify()でリミット設定する

先程追加した内部関数にOrderModify()関数の処理を追加してリミット設定しましょう。

ソースコード:
    bool   modify_bool;                  // 注文変更結果
    int    get_order_type;               // エントリー方向
    double set_limit_rate = 0 ;          // リミット価格
    double entry_rate;                   // エントリー価格
    double set_offset;                   // オフセット価格

    entry_rate     = OrderOpenPrice();   // エントリー価格取得
    get_order_type = OrderType();        // 注文タイプ取得

    set_offset     = Point() * 10 * 200; // オフセット設定(200pips)

    if ( get_order_type == OP_BUY ) {    // 買いの場合
        // リミット価格設定
        set_limit_rate = entry_rate + set_offset;
    }


    modify_bool = OrderModify(            // オーダー変更
                        in_ticket,        // チケットNo
                        0,                // エントリー価格(保留中の注文のみ)
                        0,                // ストップロス
                        set_limit_rate,   // リミット
                        0,                // 有効期限
                        clrYellow         // ストップリミットラインの色
                  );


簡単に説明すると、選択したポジションが買いエントリーなら、エントリー価格に200pips加算した価格をリミット価格として発注しています。

OrderModify()の第2引数と第5引数は保留中の(約定していない)エントリー指値・エントリー逆指値用ですので、
今回のような決済指値・決済逆指値の設定の時は0を設定して下さい(0を設定しなくても無効なので特に何もありませんが)。

また有効期限と色のデフォルト値が無いので、今回は省略する事が出来ません(デフォルト値追加して欲しい・・・)。
ちなみに最後の色はストップ・リミットライン自体の色では無く、注文受付した時のラインの色になります。
Order_Modify

上位関数に呼び出し処理を追加します。

ソースコード:
        bool ret = false;
        
        // ポジションを選択
        ret = OrderSelect( icount,        // 注文インデックス
                           SELECT_BY_POS  // 選択タイプ[インデックスで選択]
        );
        
        if ( ret == true ) { // ポジション選択成功した場合

            if ( OrderMagicNumber() != 20200518 ) {  // マジックナンバー不一致判定
                continue;                            // 次のループへ
            }

            if ( OrderSymbol() != Symbol() ) {       // 通貨ペア不一致判定
                continue;                            // 次のループへ
            }

            if ( OrderType() != OP_BUY ) {          // 注文タイプ不一致判定(成行買い以外は無視する)
                continue;                            // 次のループへ
            }

            Modify_Order( OrderTicket() );          // 注文変更

            printf( "[%d]インデックス=%d, チケットNo=%d, マジックナンバー=%d, ロット=%f"
                    , __LINE__
                    , icount
                    , OrderTicket()           // 選択した注文のチケット番号
                    , OrderMagicNumber()     // 選択した注文のマジックナンバー
                    , OrderLots()            // 選択した注文のロット数
            );
        }


関数を呼び出す時に引数にチケットNoを渡すのを忘れないで下さい。


さっそくスクリプトを動かしてみましょう
Order_Modify

対象のポジションのリミットが変更されました。
ちなみに逆にリミットを解除したい場合はリミット価格を0にして発注します。
Order_Modify


変更失敗時

OrderSend()の時と同様に何かしらのエラーが発生しますので、es2.OrderSend()関数のエラーの時と同様にエラーログ出力処理を追加します。
stdlib.mqhインクルードも忘れずに行って下さい。

#include <stdlib.mqh>          // ライブラリインクルード



ソースコード:
    if ( modify_bool == false) {    // 変更失敗

        int    get_error_code   = GetLastError();                   // エラーコード取得
        string error_detail_str = ErrorDescription(get_error_code); // エラー詳細取得

        // エラーログ出力
        printf( "[%d]オーダー変更エラー。 エラーコード=%d エラー内容=%s" 
            , __LINE__ ,  get_error_code , error_detail_str
         );        
    } else {
        // 変更成功
        ret = true;
    }

エラーログ出力を追加したら、もう一度スクリプトを動かしてみましょう


結果:
EURUSD,H1: [112]オーダー変更エラー。 エラーコード=1 エラー内容=no error, trade conditions not changed

3桁以内のトレードサーバーが返すエラーコードが出力されました。
内容は「エラーでは無いけど、変化がありません」。
理由は簡単で今現在設定されているリミット価格に対して同じリミット価格で変更するように要求した為、
エラーというか「意味の無い事をしていますよ」という警告がログ出力されました。

これを回避する為に、価格に変化が無い場合は発注しないようにしましょう。

ソースコード:
    double limit_diff;                  // リミット価格差
    limit_diff = MathAbs( set_limit_rate - OrderTakeProfit() );

    if ( limit_diff < Point() ) {       // 0.1pips未満の変化の場合
        return ret;                         // 処理終了
    }

OrderModify()関数の直前にこの処理を追加します。
設定済みのリミット価格と、設定するリミット価格の差の絶対値が0.1pips未満の場合は処理を終了します。
これで警告回避出来ます。

売り注文に対するリミット設定

買い注文に対するリミット設定の方法は分かったと思いますので、売り注文のリミット設定は自作してみて下さい。
と言っても問い合わせが来ると思うのでソースコードだけ記載しておきます。


ソースコード:
    if ( get_order_type == OP_BUY ) {            // 買いの場合
        // リミット価格設定
        set_limit_rate = entry_rate + set_offset;
    } else if ( get_order_type == OP_SELL ) {    // 売りの場合
        // リミット価格設定
        set_limit_rate = entry_rate - set_offset;
    } else {
        // エントリー指値注文の場合
        return ret;                                  // 処理終了
    }


動作確認する前に上位関数でOP_BUYでフィルタリングしているので、そこを削除して下さい。

ソースコード:
            // if ( OrderType() != OP_BUY ) {          // 注文タイプ不一致判定(成行買い以外は無視する)
            //    continue;                            // 次のループへ
            //}

            Modify_Order( OrderTicket() );          // 注文変更


Order_Modify

売り注文に対してもリミット設定されました。

ストップを設定する

リミット設定でしなければならない事が分かった所で、最後にストップの設定をします。
リミットとストップは同時に変更注文を出せるので、単純にストップ価格設定の処理を追加します。


ソースコード:
    double set_stop_rate = 0 ;          // ストップ価格

    if ( get_order_type == OP_BUY ) {            // 買いの場合
        set_limit_rate = entry_rate + set_offset; // リミット価格設定
        set_stop_rate  = entry_rate - set_offset; // ストップ価格設定

    } else if ( get_order_type == OP_SELL ) {    // 売りの場合
        set_limit_rate = entry_rate - set_offset; // リミット価格設定
        set_stop_rate  = entry_rate + set_offset; // ストップ価格設定

    } else {                                      // エントリー指値注文の場合
        return ret;                                  // 処理終了
    }

    double limit_diff;                  // リミット価格差
    double stop_diff;                  // ストップ価格差
    limit_diff = MathAbs( set_limit_rate - OrderTakeProfit() );
    stop_diff = MathAbs( set_stop_rate   - OrderStopLoss() );

    if ( limit_diff < Point() && stop_diff < Point() ) {       // 0.1pips未満の変化の場合
        return ret;                         // 処理終了
    }

    modify_bool = OrderModify(            // オーダー変更
                        in_ticket,        // チケットNo
                        0,                // エントリー価格(保留中の注文のみ)
                        set_stop_rate,    // ストップロス
                        set_limit_rate,   // リミット
                        0,                // 有効期限
                        clrYellow         // ストップリミットラインの色
                  );

注意しなければならないのは、前に説明した通りリミットやストップを取り消したい場合は0を設定する必要があるので、
変更しないからと言って0を設定するとリミット・ストップ注文が取り消されます。

その為リミットが設定済みの状態で、ストップ設定の発注を行う場合は、リミットは現在設定済みの価格と同じ設定をする必要があります。
同価格設定の警告はリミットとストップの両方の設定価格が同一だった場合に発生するので、
リミットとストップの設定価格差の両方をチェックする必要があります。
なのでリミット価格差とストップ価格差の両方をチェックして、両方とも同一価格なら処理終了させています。

ソースコード変更したら動作チェックしましょう。
Order_Modify

ストップロスも変更されました。


完成したサンプルソースコード


ソースコード:
//+------------------------------------------------------------------+
//|                                        Test_TradeOrderModify.mq4 |
//|                                                             yuki |
//|                                      https://yukifx.web.fc2.com/ |
//+------------------------------------------------------------------+
#property copyright "yuki"
#property link      "https://yukifx.web.fc2.com/"
#property version   "1.00"
#property strict // strictは絶対に削除しない事

#include <stdlib.mqh>          // ライブラリインクルード

//+------------------------------------------------------------------+
//| スクリプトプログラムスタート
//+------------------------------------------------------------------+
void OnStart()
{
    int position_total = OrdersTotal();     // 保有しているポジション数取得
    
    printf( "[%d]ポジション数:%d" , __LINE__ , position_total );

    // 全ポジション分ループ
    for ( int icount = 0 ; icount < position_total ; icount++ ) {
        
        bool ret = false;
        
        // ポジションを選択
        ret = OrderSelect( icount,        // 注文インデックス
                           SELECT_BY_POS  // 選択タイプ[インデックスで選択]
        );
        
        if ( ret == true ) { // ポジション選択成功した場合

            if ( OrderMagicNumber() != 20200518 ) {  // マジックナンバー不一致判定
                continue;                            // 次のループへ
            }

            if ( OrderSymbol() != Symbol() ) {       // 通貨ペア不一致判定
                continue;                            // 次のループへ
            }

            Modify_Order( OrderTicket() );          // 注文変更

            printf( "[%d]インデックス=%d, チケットNo=%d, マジックナンバー=%d, ロット=%f"
                    , __LINE__
                    , icount
                    , OrderTicket()           // 選択した注文のチケット番号
                    , OrderMagicNumber()     // 選択した注文のマジックナンバー
                    , OrderLots()            // 選択した注文のロット数
            );
        }
    }
}

//+------------------------------------------------------------------+
//| 注文変更
//+------------------------------------------------------------------+
bool Modify_Order( int in_ticket ){

    bool ret = false;                // 戻り値
    bool select_bool;                // ポジション選択結果

    // ポジションを選択
    select_bool = OrderSelect(
                    in_ticket ,      // チケットNo
                    SELECT_BY_TICKET // チケット指定で注文選択
                ); 

    // ポジション選択失敗時
    if ( select_bool == false ) {
        return ret;    // 処理終了
    }

    bool   modify_bool;                  // 注文変更結果
    int    get_order_type;               // エントリー方向
    double set_limit_rate = 0 ;          // リミット価格
    double set_stop_rate = 0 ;          // ストップ価格
    double entry_rate;                   // エントリー価格
    double set_offset;                   // オフセット価格

    entry_rate     = OrderOpenPrice();   // エントリー価格取得
    get_order_type = OrderType();        // 注文タイプ取得

    set_offset     = Point() * 10 * 200; // オフセット設定(200pips)

    if ( get_order_type == OP_BUY ) {            // 買いの場合
        set_limit_rate = entry_rate + set_offset; // リミット価格設定
        set_stop_rate  = entry_rate - set_offset; // ストップ価格設定

    } else if ( get_order_type == OP_SELL ) {    // 売りの場合
        set_limit_rate = entry_rate - set_offset; // リミット価格設定
        set_stop_rate  = entry_rate + set_offset; // ストップ価格設定

    } else {                                      // エントリー指値注文の場合
        return ret;                              // 処理終了
    }

    double limit_diff;                  // リミット価格差
    double stop_diff;                  // ストップ価格差
    limit_diff = MathAbs( set_limit_rate - OrderTakeProfit() );
    stop_diff = MathAbs( set_stop_rate   - OrderStopLoss() );

    if ( limit_diff < Point() && stop_diff < Point() ) {       // 0.1pips未満の変化の場合
        return ret;                      // 処理終了
    }

    modify_bool = OrderModify(            // オーダー変更
                        in_ticket,        // チケットNo
                        0,                // エントリー価格(保留中の注文のみ)
                        set_stop_rate,    // ストップロス
                        set_limit_rate,   // リミット
                        0,                // 有効期限
                        clrYellow         // ストップリミットラインの色
                  );

    if ( modify_bool == false) {    // 変更失敗

        int    get_error_code   = GetLastError();                   // エラーコード取得
        string error_detail_str = ErrorDescription(get_error_code); // エラー詳細取得

        // エラーログ出力
        printf( "[%d]オーダー変更エラー。 エラーコード=%d エラー内容=%s" 
            , __LINE__ ,  get_error_code , error_detail_str
         );        
    } else {
        // 変更成功
        ret = true;
    }

    return ret;    // 戻り値を返す
}





スポンサーリンク


Copyright ©2015 MT4でEA自作しちゃお~ All Rights Reserved.


Top

inserted by FC2 system