記事"MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第21部): 取引クラス - 基本クロスプラットフォーム取引オブジェクト"についてのディスカッション

 

新しい記事 MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第21部): 取引クラス - 基本クロスプラットフォーム取引オブジェクト はパブリッシュされました:

この記事では、取引クラスを新しいライブラリセクションとして開発し始めます。さらに、MetaTrader 5およびMetaTrader 4プラットフォーム向けの統合基本取引オブジェクトの開発を検討します。サーバにリクエストを送信する場合、このような取引オブジェクトにより、検証済みの正しい取引リクエストパラメータがサーバに渡されます。

いつでもデータに簡単にアクセスできるというのはよいことですが、取引に適用できないとすれば、そのデータは役に立ちません。これは、既存の機能とともに取引機能が必要であることを意味します。
このセクションではすべてを段階的に行うので、セクションは比較的大きくなります。

  • MetaTrader 5とMetaTrader 4の違いに関係なく、これらのプラットフォームの両方から取引リクエストを送ることができるべきです。統一が必要です。
  • まず、意図的に誤ったリクエストでサーバが負荷されないように、取引リクエストを検証する必要があります。
  • 取引サーバのリターンコードを考慮して正しく処理します。サーバにリクエストを送信するときに、EAはサーバとの「リクエスト/レスポンス」対話を維持します。ここでのタスクは、そのような「通信チャネル」、すなわち取引サーバーの応答を処理するメソッドを作成することです。
  • 「できる限りコストを抑えて」ポジションを開く必要がある場合があるため、サーバの応答を処理するいくつかのオプションを作成する必要があります。これを行うには、注文が拒否された場合にサーバにリクエストを繰り返し送信するように手配する必要があります。取引リクエストのパラメータを調整するかリクエストを再送信するか、すべてのパラメータをそのままにして、これらのパラメータを持つリクエストが渡されるとすぐに送信されるような適切な瞬間を待機することができます。また、意図的に悪い価格で注文を再送信しないように、価格レベルを考慮する必要があります。
    場合によっては、リクエストの結果に関係なく取引リクエストを送信し、作業を継続する必要があります。
  • また、ライブラリベースのプログラムをMQL5マーケットに配置する際には、問題を回避するために、取引クラスの動作を調整する必要があります。このようなプログラムはすべてのチェックに合格するべきです。
以上が、取引クラスに関する現在の計画です。

作者: Artyom Trishkin

 

その半分以上を注意深く読んだ。さらに読み進めると、だんだん意識が遠のいていった。記事のボリュームは非常に大きい。

アナトリー・コジャルスキーは、論文の最後に必ず図書館の全体図を載せていた。あなたの論文にはそのような図式がないので、私は「象」の体を這う「蟻」のような気分である。私はライブラリーの簡潔なアイデアを構築しているが、あなたの記事を読むと、それを作り上げるのは難しい。詳細やコードの説明、他の記事への参照という形で「咀嚼」された情報はたくさんありますが、ライブラリの一体的で簡潔な説明やスキームはありません。

もちろん、実装のレベルは非常に高い。すべてが非常にプロフェッショナルであり、それが表れている。しかし、これほど多くの「ラッパー」の必要性には疑問がある。例えば、"CTradeObj::SetOrder"メソッドには次のようなラッパーがあります:

//--- 保留注文を設定 (1) BuyStop、(2) BuyLimit、(3) BuyStopLimit
   bool                 PlaceBuyStop(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceBuyLimit(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceBuyStopLimit(const double volume,
                                     const string symbol,
                                     const double price_stop,
                                     const double price_limit,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
//--- 保留注文を設定 (1) SellStop, (2) SellLimit, (3) SellStopLimit
   bool                 PlaceSellStop(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceSellLimit(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceSellStopLimit(const double volume,
                                     const string symbol,
                                     const double price_stop,
                                     const double price_limit,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
//--- 
                        

どれも大差はありませんが、かなりのスペースを取っています。このような "ディープ・ラッピング "では、素材やコードは "酵母 "のように増殖し、機能の使用は、指数関数的に増殖するエンティティの数の増加に比例して、より複雑になるでしょう。

いや、反対ではない。ポリモーフィズムとは、1つのメソッドが多くのラッパーを生み、それぞれが独自の特異性を持つことなのだろう。問題なのは、このアプローチによる解の構造があまりにも早く成長しすぎて、実用的でなくなってしまうことだ。そうでなければ、理解するのも使うのもますます難しくなってしまう。

 
Реter Konow:

その半分以上を注意深く読んだ。さらに読み進めると、だんだん意識が遠のいていった。記事のボリュームは非常に大きい。

アナトリー・コジャルスキーは、論文の最後に必ず図書館の全体図を載せていた。あなたの論文にはそのような図式がないので、私は「象」の体を這う「蟻」のような気分である。私はライブラリーの簡潔なアイデアを構築しているが、あなたの記事を読むと、それを作り上げるのは難しい。詳細、コードの説明、他の記事への参照という形で「咀嚼」された情報はたくさんありますが、ライブラリーの完全で簡潔な説明とスキームはありません。

もちろん、実装のレベルは非常に高い。すべてが非常にプロフェッショナルであり、それが表れている。しかし、これほど多くの「ラッパー」の必要性には疑問がある。 例えば、"CTradeObj::SetOrder"メソッドには以下のラッパーがあります:

どれも大差はありませんが、かなりのスペースを取って います。このような "ディープ・ラッピング "では、材料やコードは "酵母 "のように増殖し、機能の使用は、指数関数的に増殖するエンティティの数の増加に比例して、より複雑になります。

いや、反対ではない。ポリモーフィズムとは、1つのメソッドが多くのラッパーを生み、それぞれが独自の特異性を持つことなのだろう。問題なのは、このアプローチによる解の構造があまりにも早く成長しすぎて、実用的でなくなってしまうことだ。そうでなければ、理解するのも使うのもますます難しくなってしまう。

ピーター、評価をありがとう。CEngineから入手できるものだけを使うべきで、それはプログラムから入手できるものです。

残りはすべて、必要なパラメータが渡されるメソッドの実装です。これらのメソッドは、あなた自身のプログラムで実際に使用するために必要なものではなく、ライブラリ自体に必要なものです。したがって、エンドユーザーにとっては、メソッドの数は常にそれほど多くありません。

当然ながら、すべてが記述される。構造も、ユーザーが利用できるすべてのメソッドも。そして、OOP実装を隠し、ライブラリ・オブジェクトへの明示的なアクセスを必要としないユーザー関数が作成される。

主な機能は構造的にも表形式的にも記述することができ、記述が完全で修正を必要としないようにする必要があります。

この後の記事ごとに、メソッドの違いは劇的に増えていくだろう。この記事は、トレードクラスに関する作業のほんの始まりに過ぎません。そして、送信する注文の種類ごとに、どのようなパラメータが必要なのか、OrderSend() を見てください。これらのパラメータはすべてメソッドに渡されます。もちろん、インジケーターのように記述された構造体を通してパラメータを渡すことも可能でしょうが、それは不要でしょう。
また、必要な構造体をユーザーに記入させることもできるが、あらかじめ構造体を記入してからメソッドに渡すよりも、パラメーターを直接メソッドに渡す方が簡単で親切である。これは、エンドユーザーが使用する際の利便性のためだけに行われているのであって、ライブラリのコンポーネントを解析する際の利便性のためではない。
 
Artyom Trishkin:

ピーターさん、ご評価ありがとうございます。CEngineから入手可能なものだけを使用する必要があります。

あとは、必要なパラメータがすべて渡されるメソッドの実装です。これらのメソッドは、あなた自身のプログラムで実際に使用するために必要なものではなく、ライブラリ自体に必要なものです。したがって、エンドユーザーにとっては、メソッドの数は常にそれほど多くありません。

当然ながら、すべてが記述される。構造も、ユーザーが利用できるすべてのメソッドも。そして、OOP実装を隠し、ライブラリ・オブジェクトへの明示的なアクセスを必要としないユーザー関数が作成される。

主な機能は構造的にも表形式的にも記述することができ、記述が完全で修正を必要としないようにする必要があります。

この後の記事ごとに、メソッドの違いは劇的に増えていくだろう。この記事は、トレード・クラスに関する作業のほんの始まりに過ぎません。

根拠のないものにならないために、「ラッピング」を制限するために次のような対策を提案したい:

CTradeObj::SetOrder" メソッドを書き直し、1つの追加パラメーターを受け取るようにする。さらに、このメソッド自体がその方法を決定します。必要な構造体を初期化し、必要な値を設定し、必要なメソッドを呼び出します。したがって、すべてのラッパーを" CTradeObj::SetOrder" メソッドに送られる1つの追加パラメータに圧縮することになります。これは、PlaceBuyStop、PlaceSellStopLimit、またはPlaceBuyLimitをパラメータとして受け取り、必要な作業を行います。

もちろん、このオプションは実装がより複雑になりますが、ライブラリ機能の「圧縮」と使いやすさを保証します。

幸運を祈る。

 
Реter Konow:

根拠を欠くことのないよう、私は「ラッピング」を制限するために以下の対策を提案する:

CTradeObj::SetOrder" メソッドは、1つの追加パラメータ-設定する注文のタイプ-を受け取るように書き換えるべきである。さらに、このメソッド自体がその方法を決定します。必要な構造体を初期化し、必要な値を設定し、必要なメソッドを呼び出します。したがって、すべてのラッパーを" CTradeObj::SetOrder" メソッドに送られる1つの追加パラメータに圧縮することになります。これは、PlaceBuyStop、PlaceSellStopLimit、またはPlaceBuyLimitをパラメータとして受け取り、必要な作業を行います。

もちろん、このオプションは実装がより複雑になりますが、ライブラリ機能の「圧縮」と使いやすさを保証します。

幸運を祈る。

この方法はライブラリーのユーザーには必要ありません。ライブラリ自身が必要としているのだ。

ピータータイプだけを設定してポジションを開いてみてください。ターミナルで。そして、他に何が必要なのか見てみよう。ターミナルは、どのシンボルでポジションを建てるか、どのロットで建てるか、どのストップ・オーダー・レベルを設定するか、などといったことを決めてはくれません。

 
Artyom Trishkin:

...

そして、送信される注文の各タイプについて、OrderSend() を見てください。これらのパラメータはすべてメソッドに渡されます。もちろん、インジケーターのように記述された構造体を通してパラメータを渡すことも可能でしょうが、それは不要でしょう。

また、必要な構造体をユーザーに記入させることもできますが、あらかじめ構造体を記入してからメソッドに渡すよりも、パラメーターを直接メソッドに渡す方が簡単で親切 です。これはエンドユーザーの利便性のためであって、ライブラリのコンポーネントを解析する利便性のためではない。
私の見解では、最も友好的な選択肢は、OrderSend()のラッパーを1つだけ用意することである。このラッパーはユーザーからのパラメーターを受け取り、呼び出しのフォーマットを決定する。私ならこうします。しかし、それはあなた次第です。
 
Реter Konow:
私の見解では、最も友好的なオプションは、OrderSend()のラッパーである。このラッパーはユーザーからのパラメータを受け取り、呼び出しのフォーマットを決定する。私ならこうする。しかし、あなたはよくご存知でしょう。

メソッドはユーザーからパラメータを受け取ります。

 
Artyom Trishkin:

メソッドはユーザーからパラメータを受け取る。

はい、わかりました。これは注文処理の「多層」実装です。問題はラッパーの「厚さ」にある。どのメソッドがメカニズムを参照し、どのメソッドがライブラリのユーザー・インターフェースを参照するのか混乱してしまいました。申し訳ない。ラッパーがもっと少なければわかりやすいのですが、それはお好みで。
 
Реter Konow:
ああ、わかった。このような "多層的 "なオーダー処理の実装である。問題はラッパーの「厚さ」にある。どのメソッドがメカニズムを参照し、どのメソッドがライブラリーのユーザー・インターフェースを参照しているのか混乱してしまった。申し訳ない。ラッパーがもっと少なければわかりやすいのですが、それはお好みで。

ピーター、私は一つの作業方法だけでなく、多くの可能性を与えるようにしているんだ。

この記事では、トレード機能への低レベルのアクセスを整理した。トレードオブジェクトが行うのは、受け取ったパラメータをサーバーに注文を送信する機能に正しく配置することだけです。トレード注文を 送信するには、シンボルのコレクションにアクセスし、必要なシンボルのオブジェクトを取得し、このオブジェクトからトレードオブジェクトを取得する必要があります。そして、取引オブジェクトを操作する。必要なパラメータを渡すだけで十分です。しかし、これらのパラメータが正しいかどうかを独自にチェックしなければなりません。なぜなら、トレード・オブジェクトは、渡されたすべてのパラメータがすでに正しいとみなすからです。

これは不便です。しかし、そのようなアクセス方法もある。必要な人は自分ですべてをチェックし、取引注文を送信する。サーバーの応答処理はない。これが最初に行われたことである。

次の記事では、取引クラスについて説明します。このクラスは、同じパラメータを持つ同じ取引メソッドのセットを持ちますが、今度はすべてが正しいかどうかチェックされ、パラメータが正しくない場合(またはそのうちの1つ、あるいは取引の可能性がない場合)、プログラムに返されます。これは第二段階であり、すでに存在する第一段階と、ライブラリ自身がパラメータの正しさをチェックし、それらがすべて正しければ注文が送信され、少なくとも1つが正しくないか、取引の可能性がなければ、単に制御プログラムに返される第二段階の2つの方法がある。ここで、正しさのチェックを伴うより高度なアクセスが組織される。

しかし、それだけではない。エラーに対応する必要がある。次回は、さらに踏み込んで、取引注文のパラメータで受信したエラーを処理します(サーバに送信する前にも)。エラーの場合、ポジションのオープンを拒否し、パラメータを修正して再度リクエストを送信することができます。これはすでに、取引オブジェクトを使った作業の第三段階です。

必要な設定に従ってすべてが自動的に動作します。エキスパートアドバイザーが必要な注文を再度送信する適切なタイミングを待つか、または単にどのような状況で注文を送信する必要があるかを知っている場合です。そのような保留中のリクエストはすべて、リクエストを送信する適切なタイミングを待つために、彼の貯金箱にあります。

だから、ピーター、まだ何かを判断するのは時期尚早だ。

あなたは取引機能へのアクセスを一本化することを提案したが、私は多様な方法を提供したい。もちろん、すべての人を満足させることは不可能だが。

 

Artyom Trishkin:

...

私はあなたの説明を気に入ったが、そのために内部矛盾が生じた。

1.一方では、階層化された「ラッパー」構造を構築することで、ユーザーにライブラリエンジンの全レベルへのアクセスを提供し、圧縮されたアルゴリズムの代わりに拡大された関係があり、アルゴリズムの「フレームワーク」は知覚しやすいように拡大縮小されている。それは美しく、美的で、エレガントである。もちろん、それはデザインと使いやすさの問題である。より正確には、研究者にとっての使いやすさである。なぜなら、ユーザーは結果と効率をより重視するからだ。では、別の視点から解決策を見てみよう。

2- 効率性とは、簡潔であること、最小限のエンティティとラッパーのセットであること、データへのアクセスが可能な限り短いことを意味する。ラッパーからラッパーへパラメーターの "負荷 "を移さないように、"伸張 "させないように、すべてを近づける必要がある。効率性と、ラッパーの間でパラメーターの「分隊」を「さまよう」ような、配置された、階層化された、エレガントなスタイルは、異質で、ほとんど不調和なものだ。

//-----------------------------------

この矛盾を考慮して、私は妥協案を提案したい。解決策の簡潔性を高めることで、ラッパーの数の増加を部分的に制限する。原則的には、OrderSend()関数には 1つのラッパーで十分です。極端な場合、複数のラッパーが必要です。しかしこの場合、解決策は「研究者」にとって理解しづらくなり、「階層」へのアクセスも複雑になる。したがって、圧縮された効率的なブロックと、プログラマーに愛されているOOPジャングルの「つる」を組み合わせてみることだ。そうすれば、金字塔が見えてくるはずだ。

 
Artyom Trishkin:

...

そして、さらに高度なアプローチがあります - 必要な設定に従って、すべてが自動モードで動作します。エキスパートアドバイザーは、必要な注文を再度送信するタイミングを待つか、または単にどのような状況でリクエストを送信する必要があるかを知ることができます。このような保留中のリクエストはすべて貯金箱に保管され、リクエストを送信するタイミングを待ちます。

したがって、ピーター、何かを判断するのは時期尚早だ。

あなたは取引機能へのアクセスを一本化することを提案したが、私はさまざまな方法を提供したい。もちろん、すべての人を満足させることは不可能だが。

ライブラリーをレベル分けして、ユーザーがそのレベルに合わせて作業できるようにするのはとてもいいことだ。しかし、量が質を低下させることを忘れないでほしい。ユーザーがより多くの方法を得れば得るほど、混乱する可能性が高くなる。その点は留意してほしい。

それ以外は同意する。取引機能に対する レイヤーアプローチは良いことだ。