English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
preview
一からの取引エキスパートアドバイザーの開発(第26部):未来に向かって(I)

一からの取引エキスパートアドバイザーの開発(第26部):未来に向かって(I)

MetaTrader 5 | 11 11月 2022, 08:53
336 0
Daniel Jose
Daniel Jose

はじめに

一からの取引エキスパートアドバイザーの開発(第24部)」と同第25部ではコードを修正および改善してシステムの堅牢性を向上させる方法を見てきましたが、まだいくつかの詳細が残っています。これは、関連性が低いからではありません。実際には非常に重要です。

ここで、取引日にどのように作業して何をするかに関連するいくつかの質問があります。多くのトレーダーは、特定の価格で注文を出すだけで、その時点から移動させません。何が起こっても、これが完璧なエントリポイントであると想定し、注文を動かしません.ストップレベルをシフトしたり削除したりすることもありますが、エントリポイントは変更しません。

したがって、コードに残っている欠陥は、トレーダーの実際の動作には影響しません。発注システムに欠陥があることに気付くかもしれません (たとえば、この記事で修正しようとしているものなど)が、価格を追跡したり、とにかく取引に参加したいが、市場に参加したくない人は、システムで多くのエラーを目の当たりにするでしょう。他のトレーダーが利益を上げる一方、干渉して取引が安全でなくしてしまい(控えめに言っても)、市場の前で無力になるトレーダーもいるでしょう。


2.0.実装

この記事の旅を始めるにあたり、EAを「破産マシン」にしてしまうような欠陥を修正することから始めましょう。繰り返しますが、エントリポイントを常に変更し続けない限り、この問題の影響は受けません。ただし、念のため、コードを更新することを検討することをお勧めします。修正は添付のコードに既に実装されていますが、パフォーマンスがいくらか失われるため、EAに悪影響を与えるとお考えかもしれません。これは事実です。しかし、パフォーマンスをいくらか失うのと、悪いエントリでお金を失うリスクを冒すのとでは、どちらが良いのでしょうか。


2.0.1.エントリポイントエラー

このエラーは最初に修正するものですが、エラーはすべて何らかの方法で修正する必要があります。ただし、これはそれらすべての中で最も壊滅的なものです。これは、指値注文のエントリを配置し、たとえばBUYSTOPを配置し、エントリポイントを移動して、注文がBUYLIMITタイプになるようにした場合に発生します。ここには問題がないように見えますが、現在の開発段階のEAは正しい方法で変更をおこなうことができないため、この失敗は非常に壊滅的です。実際、多くのEAがこの変更をおこないたいと考えており、これが発生した場合、チャートに情報が表示されますが、サーバーには他の情報があります。システムは、ポジションが開かれたときにのみ正しく更新されます。それまでは、EAがチャートに表示するものとサーバーにあるものとの間のデータには一貫性がありません。

場合によっては、この不一致が発生するのみですが、別の場合には、問題は完全な災害になります。これを理解するには、この記事を注意深く読んでください。

このエラーを解消するために、適用前に別のパスをたどるという解決法がありますが、操作の原則は常に同じです。オーダーブックから注文を削除し、新しいポジションに移動し、注文タイプを変更してオーダーブックに戻します。これは実行すべきことですが、実行方法は特定の実装によって異なります。

したがって、最も基本的な解決策を実装しますが、理想的ではないため、いくつかの問題に対処する必要があります。

解決策は、強調表示された行を追加して、以下の関数を変更することです。

void SetPriceSelection(double price)
{
        char Pending;
                
        if (m_Selection.ticket == 0) return;
        Mouse.Show();
        if (m_Selection.ticket == def_IndicatorTicket0)
        {
                CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price,  price + m_Selection.tp - m_Selection.pr, price + m_Selection.sl - m_Selection.pr, m_Selection.bIsDayTrade);
                RemoveIndicator(def_IndicatorTicket0);
                return;
        }
        if ((Pending = GetInfosTradeServer(m_Selection.ticket)) == 0) return;
        m_TradeLine.SpotLight();
        switch (m_Selection.it)
        {
                case IT_TAKE:
                        if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, price, m_Selection.sl);
                        else ModifyPosition(m_Selection.ticket, price, m_Selection.sl);
                        break;
                case IT_STOP:
                        if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, m_Selection.tp, price);
                        else ModifyPosition(m_Selection.ticket, m_Selection.tp, price);
                        break;
                case IT_PENDING:
                        if (!ModifyOrderPendent(m_Selection.ticket, price, (m_Selection.tp == 0 ? 0 : price + m_Selection.tp - m_Selection.pr), (m_Selection.sl == 0 ? 0 : price + m_Selection.sl - m_Selection.pr)))
                        {
                                MoveSelection(macroGetLinePrice(def_IndicatorGhost, IT_PENDING));
                                m_TradeLine.SpotLight();
                        }
                        break;
        }
        RemoveIndicator(def_IndicatorGhost);
}

この解決策は問題を部分的に解決しますが、完全には解決しません。たとえば、BUYSTOP注文とSELLSTOP注文の場合、これらの単純な行を追加することで問題が解決されます。しかし、BUYLIMITSTOPLIMITの場合、クリックしてエントリポイントを変更すると、サーバーはすぐに注文を約定します。ここでさらに悪いのは、負けポジションに入ることです。注文が空の注文(利益または損失のレベル)として設定され、ストップロスポイントが価格制限外にある場合、サーバーは注文を即座に実行するだけではなく、直後に注文を決済します。私たちの取引口座にとっては完全な災害になります。そのため、取引システムの開発は非常に困難です。デモ口座でいくつかのテストを実行し、すべてが機能しているように見える場合は、実際の口座に移行します。その時点で、実際に何が起こっているのかを知らずに資金を失い始めます。

もう一度繰り返します。エラーは、エントリポイントが一度配置され、変更されない場合には影響しません。問題は、トレーダーがポイントを移動したときに発生します。

実際、STOP注文は正常に機能しています。ここで、LIMIT未決注文の問題を解決する必要があります。この問題は簡単に解決できるように思えるかもしれませんが、理解しておくべきことが1つあります。完全な解決策はないこと、そして、システム開発者にとって最適な解決策が、開発者にとって最適な解決策であるとは限らないということです。

ここでは、この問題に対する可能な解決策の1つを示します。解決策は、上記と同じ関数で実装されます。新しいコードは次のとおりです。

void SetPriceSelection(double price)
{
        char Pending;
        double last;
        long orderType;
                                
        if (m_Selection.ticket == 0) return;
        Mouse.Show();
        if (m_Selection.ticket == def_IndicatorTicket0)
        {
                CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price,  price + m_Selection.tp - m_Selection.pr, price + m_Selection.sl - m_Selection.pr, m_Selection.bIsDayTrade);
                RemoveIndicator(def_IndicatorTicket0);
                return;
        }
        if ((Pending = GetInfosTradeServer(m_Selection.ticket)) == 0) return;
        m_TradeLine.SpotLight();
        switch (m_Selection.it)
        {
                case IT_TAKE:
                        if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, price, m_Selection.sl);
                        else ModifyPosition(m_Selection.ticket, price, m_Selection.sl);
                        break;
                case IT_STOP:
                        if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, m_Selection.tp, price);
                        else ModifyPosition(m_Selection.ticket, m_Selection.tp, price);
                        break;
                case IT_PENDING:
                        orderType = OrderGetInteger(ORDER_TYPE);
                        if ((orderType == ORDER_TYPE_BUY_LIMIT) || (orderType == ORDER_TYPE_SELL_LIMIT))
                        {
                                last = SymbolInfoDouble(Terminal.GetSymbol(), (m_Selection.bIsBuy ? SYMBOL_ASK : SYMBOL_BID));
                                if (((m_Selection.bIsBuy) && (price > last)) || ((!m_Selection.bIsBuy) && (price < last)))
                                {
                                        RemoveOrderPendent(m_Selection.ticket);
                                        RemoveIndicator(m_Selection.ticket);
                                        CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, (m_Selection.tp == 0 ? 0 : price + m_Selection.tp - m_Selection.pr), (m_Selection.sl == 0 ? 0 : price + m_Selection.sl - m_Selection.pr), m_Selection.bIsDayTrade);
                                        break;
                                }
                        }
                        if (!ModifyOrderPendent(m_Selection.ticket, price, (m_Selection.tp == 0 ? 0 : price + m_Selection.tp - m_Selection.pr), (m_Selection.sl == 0 ? 0 : price + m_Selection.sl - m_Selection.pr)))
                        {
                                MoveSelection(macroGetLinePrice(def_IndicatorGhost, IT_PENDING));
                                m_TradeLine.SpotLight();
                        }
                        break;
        }
        RemoveIndicator(def_IndicatorGhost);
}

これは、以下のようにおこなわれます。指値注文のエントリポイントを変更する場合、オーダーブック(板情報)の注文がストップリミットまたはバイリミットタイプであるかどうかを確認します。そうでない場合、実行フローはコード内の別のポイントに進みます。そうである場合、現在の資産価格を即座に取得し、買い注文の場合は、現在のASKを取得して、売り注文の場合はBIDを取得します。これはLAST値を使用する古い方法に代わるものです。LAST値は一部の市場では使用されていないため、参照値として使用できません。次に、オーダーブックの注文が無効になっているのか、それとも変更されているだけなのかを確認します。

注文がまだ有効な場合、システムは検証コードを無視し、注文が変更される部分に移動しますが、板情報の注文が無効な場合、次のコードが実行されます。

RemoveOrderPendent(m_Selection.ticket);
RemoveIndicator(m_Selection.ticket);
CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, (m_Selection.tp == 0 ? 0 : price + m_Selection.tp - m_Selection.pr), (m_Selection.sl == 0 ? 0 : price + m_Selection.sl - m_Selection.pr), m_Selection.bIsDayTrade);
break;

ただし、上記のコードは、SELL LIMIT注文とBUY LIMIT注文をそれぞれSELL STOPとBUY STOPに変更するだけです。これらの型を元の型に戻したい場合、または単にそのような変更を防止したい場合はどうすればよいでしょうか。

実行された注文のタイプをシステムに変更させたくない場合は、強調表示されたフラグメントを次のコードに置き換えるだけです。

if ((orderType == ORDER_TYPE_BUY_LIMIT) || (orderType == ORDER_TYPE_SELL_LIMIT))
{
        last = SymbolInfoDouble(Terminal.GetSymbol(), (m_Selection.bIsBuy ? SYMBOL_ASK : SYMBOL_BID));
        if (((m_Selection.bIsBuy) && (price > last)) || ((!m_Selection.bIsBuy) && (price < last)))
        {
                RemoveOrderPendent(m_Selection.ticket);
                RemoveIndicator(m_Selection.ticket);
                CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, (m_Selection.tp == 0 ? 0 : price + m_Selection.tp - m_Selection.pr), (m_Selection.sl == 0 ? 0 : price + m_Selection.sl - m_Selection.pr), m_Selection.bIsDayTrade);
                MoveSelection(macroGetLinePrice(def_IndicatorGhost, IT_PENDING));
                m_TradeLine.SpotLight();
                break;
        }
}

このコードは、注文タイプが変更されるのを防ぎます。未決注文が約定するポイントを変更することはできますが、LIMIT注文をSTOP注文に、またはその逆に変更することはできません。次に、価格を追跡し続け、特定の時点でエントリを強制したい場合は、以下に示すコードを使用します。これはEAで使用されるコードです。

#define def_AdjustValue(A) (A == 0 ? 0 : price + A - m_Selection.pr)
#define macroForceNewType       {                                                                                                                                               \
                RemoveOrderPendent(m_Selection.ticket);                                                                                                                         \
                RemoveIndicator(m_Selection.ticket);                                                                                                                            \
                CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, def_AdjustValue(m_Selection.tp), def_AdjustValue(m_Selection.sl), m_Selection.bIsDayTrade);      \
                break;                                                                                                                                                          \
                                }

                void SetPriceSelection(double price)
                        {
                                char Pending;
                                double last;
                                long orderType;
                                
                                if (m_Selection.ticket == 0) return;
                                Mouse.Show();
                                if (m_Selection.ticket == def_IndicatorTicket0)
                                {
                                        CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price,  price + m_Selection.tp - m_Selection.pr, price + m_Selection.sl - m_Selection.pr, m_Selection.bIsDayTrade);
                                        RemoveIndicator(def_IndicatorTicket0);
                                        return;
                                }
                                if (m_Selection.ticket == def_IndicatorFloat)
                                {
                                        CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, m_Selection.pr,  m_Selection.tp, m_Selection.sl, m_Selection.bIsDayTrade);
                                        RemoveIndicator(def_IndicatorFloat);
                                        return;
                                }
                                if ((Pending = GetInfosTradeServer(m_Selection.ticket)) == 0) return;
                                m_TradeLine.SpotLight();
                                switch (m_Selection.it)
                                {
                                        case IT_TAKE:
                                                if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, price, m_Selection.sl);
                                                else ModifyPosition(m_Selection.ticket, price, m_Selection.sl);
                                                break;
                                        case IT_STOP:
                                                if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, m_Selection.tp, price);
                                                else ModifyPosition(m_Selection.ticket, m_Selection.tp, price);
                                                break;
                                        case IT_PENDING:
                                                orderType = OrderGetInteger(ORDER_TYPE);
                                                if ((orderType == ORDER_TYPE_BUY_LIMIT) || (orderType == ORDER_TYPE_SELL_LIMIT))
                                                {
                                                        last = SymbolInfoDouble(Terminal.GetSymbol(), (m_Selection.bIsBuy ? SYMBOL_ASK : SYMBOL_BID));
                                                        if (((m_Selection.bIsBuy) && (price > last)) || ((!m_Selection.bIsBuy) && (price < last))) macroForceNewType;
                                                }
                                                if (!ModifyOrderPendent(m_Selection.ticket, price, def_AdjustValue(m_Selection.tp), def_AdjustValue(m_Selection.sl))) macroForceNewType;
                                }
                                RemoveIndicator(def_IndicatorGhost);
                        }
#undef def_AdjustValue
#undef macroForceNewType

重要な注意点:ForceNewTypeマクロがあるため、このコードを使用するときは注意してください。このマクロには、実行時にコードが「case」ブロックを終了するbreakが含まれています。このブロックを変更するときは細心の注意を払う必要があります。

エントリポイントの移動でシステムにエラーが発生することはなくなりましたが、他にも解決すべき問題があります。同じタイプの注文を変更するか維持することによって問題を修正する方法を示しました。ご自分に最も適したものを選択してください。これらの解決策にはそれぞれ長所と短所があることに注意してください。詳細には触れず、システムを修正して実装する方法のみを示します。

これらの変更の結果は、次の動画で確認できます。



2.0.2.将来への備え

上記の変更で問題は解決しましたが、他にもできることがあります。ここで、この変更の始まりを示します。EAの発注システムを見ると、まだまだ改善の余地がたくさんあります。必要な変更はほとんどありません。各トレーダーには市場での独自の行動方法があるため、最適なパスを選択できるように説明したいと思います。これから紹介するシステムを使うのが義務だと感じてはほしくありません。代わりに、誰でもカスタムEAを開発できるように基盤を作成したいと考えています。

では、次の事実に移りましょう。第18回から、特定の資産を取引する人にとって使いやすい発注システムの開発方法を示してきました。ただし、第 20回では、発注システムに視覚的な要素が追加されました。これは、すべてが発注システム自体によって示されるため、ある時点でチャート取引が取引に不要になるためです。そのため、チャート上ですべてを変更および設定できるようになります。この点に到達するには、どこかから始める必要があり、今それをおこないます。

チャートから注文を削除せずに、注文内で直接取引量を変更し、チャート取引でボリュームを変更してから、チャートに注文を再配置する方法はどうでしょうか。面白いとおもいませんか。今すぐにこの機能を実装していきます。いくつかのシナリオで大いに役立ちますが、他のプラットフォームでは見つからないため、システムの使用方法を学び、理解する必要があります。正直なところ、そのような機能を持つEAは見たことがありません。任意のEAでこの機能を実現するために何ができるか見てみましょう。

最初に、新しい指標インデックスを定義します。

#define def_IndicatorFloat      3

未決注文がこの値をチケットとして受け取ると、まったく異なる方法で処理できます。以前に存在していたものはすべて発注システムに残り、新しいindex.1を追加するだけです。

その後、新しいオブジェクトをシステムに追加します。

C_Object_BackGround     m_BackGround;
C_Object_TradeLine      m_TradeLine;
C_Object_BtnBitMap      m_BtnClose,
                        m_BtnCheck;
C_Object_Edit           m_EditInfo1,
                        m_EditInfo2;
C_Object_Label          m_BtnMove;

このオブジェクトは、注文が未決の間、常にいくつかのことを有効にします。

次に、C_Object_BitMapクラスに移動して編集します。いくつかの定義を追加します。

#define def_BtnClose            "Images\\NanoEA-SIMD\\Btn_Close.bmp"
#define def_BtnCheckEnabled     "Images\\NanoEA-SIMD\\CheckBoxEnabled.bmp"
#define def_BtnCheckDisabled    "Images\\NanoEA-SIMD\\CheckBoxDisabled.bmp"
//+------------------------------------------------------------------+
#resource "\\" + def_BtnClose
#resource "\\" + def_BtnCheckEnabled
#resource "\\" + def_BtnCheckDisabled

このクラスで何が起こっているかを知る必要があるので、次の関数を追加します。

bool GetStateButton(string szObjectName) const
{
        return (bool) ObjectGetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_STATE);
}
//+------------------------------------------------------------------+
inline void SetStateButton(string szObjectName, bool bState)
{
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_STATE, bState);
}

GetStateButtonは、ボタンの状態を返します。MetaTrader 5は状態を変更するため、追加のステップを実装する必要はなく、ボタンの値がTrueかFalseかを調べるだけです。しかし、状態が私たちが望むものを反映していない場合があります。次に、SetStateButtonを使用して、取引サーバーとEAから見た実際の状態を反映するように状態を設定します。

もう1つの簡単な変更は、C_Object_Editクラスにあります。

inline void SetOnlyRead(string szObjectName, bool OnlyRead)
{
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_READONLY, OnlyRead);
}

これは、値を編集できるかどうかを示します。チャート取引を使用せずに、チャート上で直接注文量を変更できるようにしたいと考えています。作成された未決注文は常に読み取り専用モードになりますが、これを変更するシステムを作成します。

それでは、C_IndicatorTradeViewに戻り、さらにいくつかの変更を実装しましょう。システムの新しい関数を作成します。以下のようになります。

#define macroSwapAtFloat(A, B) ObjectSetString(Terminal.Get_ID(), macroMountName(ticket, A, B), OBJPROP_NAME, macroMountName(def_IndicatorFloat, A, B));
                bool PendingAtFloat(ulong ticket)
                        {
                                eIndicatorTrade it;
                                
                                if (macroGetLinePrice(def_IndicatorFloat, IT_PENDING) > 0) return false;
                                macroSwapAtFloat(IT_PENDING, EV_CHECK);
                                for (char c0 = 0; c0 < 3; c0++)
                                {
                                        switch(c0)
                                        {
                                                case 0: it = IT_PENDING;        break;
                                                case 1: it = IT_STOP;           break;
                                                case 2: it = IT_TAKE;           break;
                                                default:
                                                        return false;
                                        }
                                        macroSwapAtFloat(it, EV_CLOSE);
                                        macroSwapAtFloat(it, EV_MOVE);
                                        macroSwapAtFloat(it, EV_EDIT);
                                        macroSwapAtFloat(it, EV_GROUND);
                                        macroSwapAtFloat(it, EV_LINE);
                                        m_EditInfo1.SetOnlyRead(macroMountName(def_IndicatorFloat, IT_PENDING, EV_EDIT), false);
                                }
                                return true;
                        }
#undef macroSwapAtFloat

この関数が呼び出されると、すべての指標オブジェクトの名前が変更されます。つまり、注文チケットを指す値は別の値に置き換えられます。この場合、このトピックの冒頭で検討した指標です。もう1つ質問があります。指標オブジェクトのリストを維持するために構造を使用するのではなく、別の方法でおこないます。このようにして、MetaTrader 5にこのリストを処理させます。しかし、そのため、変動注文は1つのみに制限されるため、無制限の変動注文を作成することはできません。これは、次の行を使用して確認できます。

if (macroGetLinePrice(def_IndicatorFloat, IT_PENDING) > 0) return false;

ここでのチェックは簡単です:インジケーターラインがどこかにある場合、マクロは0以外の値を返すので、予約済みチケットを使用するインジケーターが既に存在することがわかります。これは、リクエストが拒否された指標のデータをEAが復元するために後で重要になります。MetaTrader 5はBitmapオブジェクトの状態を自動的に変更するため、呼び出し元に失敗について通知する必要があります。

次に必要な変更は、指標を作成する関数です。

#define macroCreateIndicator(A, B, C, D)        {                                                                               \
                m_TradeLine.Create(ticket, sz0 = macroMountName(ticket, A, EV_LINE), C);                                        \
                m_BackGround.Create(ticket, sz0 = macroMountName(ticket, A, EV_GROUND), B);                                     \
                m_BackGround.Size(sz0, (A == IT_RESULT ? 84 : (A == IT_PENDING ? 108 : 92)), (A == IT_RESULT ? 34 : 22));       \
                m_EditInfo1.Create(ticket, sz0 = macroMountName(ticket, A, EV_EDIT), D, 0.0);                                   \
                m_EditInfo1.Size(sz0, 60, 14);                                                                                  \
                if (A != IT_RESULT)     {                                                                                       \
                        m_BtnMove.Create(ticket, sz0 = macroMountName(ticket, A, EV_MOVE), "Wingdings", "u", 17, C);            \
                        m_BtnMove.Size(sz0, 21, 23);                                                                            \
                                        }else                   {                                                               \
                        m_EditInfo2.Create(ticket, sz0 = macroMountName(ticket, A, EV_PROFIT), clrNONE, 0.0);                   \
                        m_EditInfo2.Size(sz0, 60, 14);  }                                                                       \
                                                }
                void CreateIndicator(ulong ticket, eIndicatorTrade it)
                        {
                                string sz0;
                                
                                switch (it)
                                {
                                        case IT_TAKE    : macroCreateIndicator(it, clrForestGreen, clrDarkGreen, clrNONE); break;
                                        case IT_STOP    : macroCreateIndicator(it, clrFireBrick, clrMaroon, clrNONE); break;
                                        case IT_PENDING:
                                                macroCreateIndicator(it, clrCornflowerBlue, clrDarkGoldenrod, def_ColorVolumeEdit);
                                                m_BtnCheck.Create(ticket, sz0 = macroMountName(ticket, it, EV_CHECK), def_BtnCheckEnabled, def_BtnCheckDisabled);
                                                m_BtnCheck.SetStateButton(sz0, true);
                                                break;
                                        case IT_RESULT  : macroCreateIndicator(it, clrDarkBlue, clrDarkBlue, def_ColorVolumeResult); break;
                                }
                                m_BtnClose.Create(ticket, macroMountName(ticket, it, EV_CLOSE), def_BtnClose);
                        }
#undef macroCreateIndicator

新しいシステムをサポートするために、強調表示されたすべての部分が追加されました。基本的に、常にtrueに設定されるチェックボックスをここに作成します。これは、注文がすぐにオーダーブックに配置されることを意味します。私はこの取引方法を変更したくありませんでしたが、チェックボックスの値を「true」から「false」に変更するという単純な事実だけで注文を直接おこなうことができなくなるわけではありません。この変更には、他のさらに深い変更を加える必要があり、問題は、ある時点で注文をおこなうようになり、チェックボックスをオンにするのを忘れる可能性があることです.実際にはすべて物忘れが原因なのに、エントリポイントが見落とされてEAに欠陥があると思われることになるかもしれません。これを回避するには、未決注文はデフォルトで直接オーダーブックに送られるため、ステータスを明示的に変更する必要があります。

次の非常に重要な関数を以下に示します。

#define def_AdjustValue(A) (A == 0 ? 0 : price + A - m_Selection.pr)
#define macroForceNewType       {                                                                                                                                               \
                RemoveOrderPendent(m_Selection.ticket);                                                                                                                         \
                RemoveIndicator(m_Selection.ticket);                                                                                                                            \
                CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, def_AdjustValue(m_Selection.tp), def_AdjustValue(m_Selection.sl), m_Selection.bIsDayTrade);      \
                break;                                                                                                                                                          \
                                }

                void SetPriceSelection(double price)
                        {
                                char Pending;
                                double last;
                                long orderType;
                                
                                if (m_Selection.ticket == 0) return;
                                Mouse.Show();
                                if (m_Selection.ticket == def_IndicatorTicket0)
                                {
                                        CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, def_AdjustValue(m_Selection.tp), def_AdjustValue(m_Selection.sl), m_Selection.bIsDayTrade);
                                        RemoveIndicator(def_IndicatorTicket0);
                                        return;
                                }
                                if (m_Selection.ticket == def_IndicatorFloat)
                                {
                                        switch(m_Selection.it)
                                        {
                                                case IT_STOP   : m_Selection.sl = price; break;
                                                case IT_TAKE   : m_Selection.tp = price; break;
                                                case IT_PENDING:
                                                        m_Selection.sl = def_AdjustValue(m_Selection.sl);
                                                        m_Selection.tp = def_AdjustValue(m_Selection.tp);
                                                        m_Selection.pr = price;
                                                        break;
                                        }
                                        m_Selection.ticket = 0;
                                        m_TradeLine.SpotLight();
                                        return;
                                }
                                if ((Pending = GetInfosTradeServer(m_Selection.ticket)) == 0) return;
                                m_TradeLine.SpotLight();
                                switch (m_Selection.it)
                                {
                                        case IT_TAKE:
                                                if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, price, m_Selection.sl);
                                                else ModifyPosition(m_Selection.ticket, price, m_Selection.sl);
                                                break;
                                        case IT_STOP:
                                                if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, m_Selection.tp, price);
                                                else ModifyPosition(m_Selection.ticket, m_Selection.tp, price);
                                                break;
                                        case IT_PENDING:
                                                orderType = OrderGetInteger(ORDER_TYPE);
                                                if ((orderType == ORDER_TYPE_BUY_LIMIT) || (orderType == ORDER_TYPE_SELL_LIMIT))
                                                {
                                                        last = SymbolInfoDouble(Terminal.GetSymbol(), (m_Selection.bIsBuy ? SYMBOL_ASK : SYMBOL_BID));
                                                        if (((m_Selection.bIsBuy) && (price > last)) || ((!m_Selection.bIsBuy) && (price < last))) macroForceNewType;
                                                }
                                                if (!ModifyOrderPendent(m_Selection.ticket, price, def_AdjustValue(m_Selection.tp), def_AdjustValue(m_Selection.sl))) macroForceNewType;
                                }
                                RemoveIndicator(def_IndicatorGhost);
                        }
#undef def_AdjustValue
#undef macroForceNewType

強調表示されたコード部分は興味深いことを行います。セレクターで使用される値のみを更新しますが、これらの値は実際にはインジケーター自体に保存されます。また、より一般的な方法でシステムを移動する場合もあるため、ポジション計算を実行する関数が正しい値を指定できるように、これらの値をセレクターで指定する必要があります。

この関数には意味をなさないかもしれないことがあります。未決注文のデータの作成と変更を担当しますが、それを見ると、未決注文がオーダーブックに戻されるポイントはわかりません。チャート上で直接注文の値ボリュームを移動、変更、調整できますが、チャートにどのように戻るかを確認することはできません。

それは事実です。指値注文を変更および作成するためのシステム全体は、上記の関数に実装されています。奇妙なことに、この関数は注文をオーダーブックに戻すのではなく、以下に示すように実際にリクエストをおこなうためです。簡潔化のために、板情報で注文を出すリクエストを担当する部分のみを示します。

void DispatchMessage(int id, long lparam, double dparam, string sparam)
{

// ... Internal code...

        case CHARTEVENT_OBJECT_CLICK:
                if (GetIndicatorInfos(sparam, ticket, it, ev)) switch (ev)
                {
                        case EV_CLOSE:
                                if (ticket == def_IndicatorFloat) RemoveIndicator(def_IndicatorFloat, it);
                                else if ((cRet = GetInfosTradeServer(ticket)) != 0) switch (it)
                                {
                        case IT_PENDING:
                        case IT_RESULT:
                                if (cRet < 0) RemoveOrderPendent(ticket); else ClosePosition(ticket);
                                break;
                        case IT_TAKE:
                        case IT_STOP:
                                m_Selection.ticket = ticket;
                                m_Selection.it = it;
                                SetPriceSelection(0);
                        break;
                }
                break;
        case EV_MOVE:
                if (ticket == def_IndicatorFloat)
                {
                        m_Selection.ticket = ticket;
                        m_Selection.it = it;
                }else   CreateGhostIndicator(ticket, it);
                break;
        case EV_CHECK:
                if (ticket != def_IndicatorFloat)
                {
                        if (PendingAtFloat(ticket)) RemoveOrderPendent(ticket);
                        else m_BtnCheck.SetStateButton(macroMountName(ticket, IT_PENDING, EV_CHECK), true);
                } else
                {
                        m_Selection.ticket = def_IndicatorTicket0;
                        m_Selection.it = IT_PENDING;
                        m_Selection.pr = macroGetLinePrice(def_IndicatorFloat, IT_PENDING);
                        m_Selection.sl = macroGetLinePrice(def_IndicatorFloat, IT_STOP);
                        m_Selection.tp = macroGetLinePrice(def_IndicatorFloat, IT_TAKE);
                        m_Selection.bIsBuy = (m_Selection.pr < m_Selection.tp) || (m_Selection.sl < m_Selection.pr);
                        m_Selection.bIsDayTrade = true;
                        m_Selection.vol = m_EditInfo1.GetTextValue(macroMountName(def_IndicatorFloat, IT_PENDING, EV_EDIT)) * Terminal.GetVolumeMinimal();
                        SetPriceSelection(m_Selection.pr);
                        RemoveIndicator(def_IndicatorFloat);
                }

// ... Rest of the code...

システム自体がどのように構築されるかを確認してください。システムが大きくなるにつれて、プログラミングの量が減っていきます。

強調表示されたコードは、トピックの冒頭で作成した指標と関係があります。すべて順調に進んでいるように見えますが、変動注文がオーダーブックに戻ると、デイトレード注文であるという欠点があり、その日の終わりに決済されるため、後で変更することがいくつかあります。.後で変更しますが、そのことを知っておくべきです。チェックボックスをクリックしたときに、未決注文が実際にどのようにオーダーブックに出入りするのかをまだわからないかもしれません。下の図を参照してください。

すべての呼び出しが同じ場所からされていることを確認します。板情報から注文を削除しましたが、チャートには引き続き表示されます。すべての操作は、前の記事で示したように実行されます。しかし、注文が板情報に戻る特定の時間を見つけようとすると、コードで少し迷子になる可能性があります。図を見ると、SetPriceSelection関数を呼び出す唯一の場所であるため、DispatchMessage関数から呼び出しが行われていることがわかりますが、SetPriceSelection関数を見ると、フローティングシステムで使用されているインデックスで注文を作成するという参照はありません。ただし、1つのことに注意してください。インデックス0による注文の作成があり、これはまさに使用するものです。注文チケットを変更し、それがインデックス0チケットになることを通知します。このようにして、注文が作成されます。これがどのように機能するかを理解するには、以下のコードを参照してください。

m_Selection.ticket = def_IndicatorTicket0;
m_Selection.it = IT_PENDING;
m_Selection.pr = macroGetLinePrice(def_IndicatorFloat, IT_PENDING);
m_Selection.sl = macroGetLinePrice(def_IndicatorFloat, IT_STOP);
m_Selection.tp = macroGetLinePrice(def_IndicatorFloat, IT_TAKE);
m_Selection.bIsBuy = (m_Selection.pr < m_Selection.tp) || (m_Selection.sl < m_Selection.pr);
m_Selection.bIsDayTrade = true;
m_Selection.vol = m_EditInfo1.GetTextValue(macroMountName(def_IndicatorFloat, IT_PENDING, EV_EDIT)) * Terminal.GetVolumeMinimal();
SetPriceSelection(m_Selection.pr);
RemoveIndicator(def_IndicatorFloat);

強調表示された行を除いて、コードは完璧です。現在、これを修正する方法はありません。クラス自体にいくつかの変更を加える必要があるため、これは次の記事でおこないます。

以下の動画は、変更の結果を示しています。ボリュームがどのように変更され、指定された時点で新しい注文がどのように送信されるかに注意してください。EAがより使いやすくなりました。



MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/10620

添付されたファイル |
オブジェクトを使用して複雑な指標を簡単に オブジェクトを使用して複雑な指標を簡単に
この記事では、複数のプロットやバッファを扱ったり複数のソースからのデータを組み合わせたりするときに発生する問題を回避しながら、複雑な指標を作成する方法を紹介します。
DoEasy-コントロール(第13部):WinFormsオブジェクトのマウスによる操作の最適化、TabControl WinFormsオブジェクトの開発開始 DoEasy-コントロール(第13部):WinFormsオブジェクトのマウスによる操作の最適化、TabControl WinFormsオブジェクトの開発開始
今回は、マウスカーソルを離した後のWinFormsオブジェクトの外観の処理を修正および最適化して、TabControl WinFormsオブジェクトの開発を開始します。
勢力指数による取引システムの設計方法を学ぶ 勢力指数による取引システムの設計方法を学ぶ
最も人気のあるテクニカル指標によって取引システムを設計する方法についての連載の新しい記事へようこそ。今回は、新しく、勢力指数(Force Index)テクニカル指標と、この指標を使った取引システムの作り方についてご紹介します。
CCI指標:3つの変換ステップ CCI指標:3つの変換ステップ
今回は、この指標のロジックそのものに影響を与えるCCIの追加変更について説明します。さらに、これをメインチャートウィンドウで確認できるようになります。