効率的な Expert Advisor 操作のための仲介会社の自動選択
はじめに
Expert Advisor が1軒の仲介会社とうまく連携し、それが収益性のないものであったり、別の仲介会社とは損失を出しさえするという状況がごく頻繁にあるものです。その理由はさまざまです。異なる仲介会社は次の項目に関して異なる設定を持つものです。
- クオートクオートは2つの要素によりわずかに異なります。異なるデータフィードとクオートを平滑化するフィルターが異なることです。一部の Expert Advisors にとってはこれは関連している可能性があります。EA が1軒の仲介会社と頻繁に取引し、別の会社とはほとんど取引しない場合に状況は発生します。
- スリッページ。仲介会社が異るとスリッページは大きく異なります。これも、期待利益が低いため EA は悪い特性につながります。
- 再クオート。仲介会社の一部では、別の会社より頻発します。この場合、再クオート数が多いため、EA は効果的なエンターポイントを逃してしまいます。
統計
もちろん異なる仲介会社からの複数ターミナルを起動し、それらを1~2か月使用し、それから利益が一番大きい1つを選びます。ただ、そのような検証にはあまり情報がありません。取引ごとの平均スリッページ、一定ごとにオープンする際発生するクオート数、オープン時刻など、といった情報をもっと取得できるとよりよいのですが。ログを分析する必要がないように、プロジェクト統計が作成されました。それは以下のルールに基づいています。
- EA は市場を分析し、取引をおこない、取引に関する必要なデータをすべて入手し、それを共通モジュールに渡す。
- このモジュールには、現在の取引および終了済み取引についての情報がすべて収められている。また仲介会社の技術的特徴すべてに関する統計を集計する。
- 収集され集計されるすべてではなく、必要な情報のみ表示されるように大容量のデータ処理が最大限快適でなければならない。
統計分析(クオート数、取引実行時刻、スリッページ)と全取引を確認することで、どの仲介会社と取引するのが良いか判断することができます。全社についての統計が否定的なものである場合は、たとえば市場の時刻やトレード頻度など、一部 EA のパラメータを変更する必要があります。そして EA が利益を出し始めるまで変更します。一定の段階で、他では利益を出しているのに、EA がある仲介会社仲介会社からの利益をもたらさなくなれば、この会社のテストは終了します。
理論
EA からアプリケーションへファイルまたは dll を介してデータ提出を手配することができます。ファイルのバリアントは技術的実現の観点から簡単なものです。なぜなら本格的なシステムをプログラムする必要がないからです。ただし、ファイルと連携するのはあまり便利とは言えません。というのも異なる仲介会社に対してMetaTrader 4 ターミナルがどこにあるか、どの通貨でその会社がテストされるか、ファイルが消失したらどうすればよいのか、など事前にわからないためです。すべてを動的に行う必要があるなら、最大限のセキュリティを設定して dll でデータを渡すようにするのがより良いと言えます。
異なるターミナルが 1 件の dll で処理をするには、それはシステムディレクトリ windows\system32に入っている必要があります。1つのターミナルの複数 EA が1件同一の dll コピーをダウンロードすることが重要です。すべては1つのプロセスで処理し、それはターミナル(terminal.exe)であるからです。それは1つの同じアドレス空間を持つことを意味します。すなわち、同一の変数を処理するのです。複数 EA を持つ1つのターミナルには全 EA に対して自分の dll コピーと同じ変数、発表された内部 dll があり、別のターミナルは別の変数を持つコピーがあります。そのため、ターミナルは別ターミナルの変数にはアクセスしません。
われわれは、別のターミナルからのデータが収集できるシングルを作成したいと思います。データフィード1つの異なるプロセスの同期処理を行う方法は複数あります。これはファイルを介して実装できますが、数多くのターミナルや EA がある場合は、処理速度の問題と共にパスを指定する問題にまた出会うことになります。最善の解決策は分割可能なコアメモリです。それで作業するには十分な注意と使用されるオペレーションシステム(われわれの場合は Windows です)の機能に関する知識が必要ですが、可能性は無限です。共有メモリの特定ブロックへ連続してアクセスできるようにするには、プログラムセマフォの特別なメカニズムが使用されます。
理論の結論:dll の EA が共有メモリにデータを書き込むことで、アプリケーション-それを「モニター」と呼びます、では、メモリからデータを読み出し、表示し、必要な統計計算を行います。MetaTrader 4 が初めて DLL を呼ぶとき、オペレーションシステムはこの DLL のコピーを各ターミナル向けに作成します。なぜなら各ターミナルは個別のプロセスだからです。以下の画像は処理スキームです
練習
Expert Advisor
確かに現行トレードに関するデータは Expert Advisor によって作成されます。データを渡すには関数 dll のインターフェースを作成する必要があります。実装されたタスクに対しては関数が3つ必要です。
bool NewExpert(string isBrokerName, string isInstrument, int Digit);
新規に Expert Advisor を作成し、それをブローカー名と銘柄で特定します。統計的特徴を計算するには、証券価格のあるポイントの後に数字の数を渡します。
bool NewDeal(string isInstrument, int Action, int magik, double PriceOpen, int Slippage, int TimeForOpen, int Requotes);
新規トレードの登録は以下の方法で行われます。ブローカー名ですでにターミナルプロセスが特定されているなら、新規トレードに対しては、トレードが実行される銘柄で十分です。その他パラメータはトレードの特性です。
テーブル1 トレード開始
パラメータ |
値 |
処理 |
0 -買い、1 -売り |
magik |
マジックナンバー |
PriceOpen |
始値 |
スリッページ |
スリッページ |
TimeForOpen |
オープン期間 |
再クオート |
再クオート受領件数 |
bool CloseDeal(string isInstrument, int magik, double PriceClose, int Slippage, int TimeForClose, int Requotes);
トレード終了は銘柄と magic で特定されます。渡されたパラメータ
テーブル2 トレード終了
パラメータ |
値 |
PriceClose |
終値 |
スリッページ |
スリッページ |
TimeForClose |
クローズ期間 |
再クオート |
再クオート受領件数 |
このインターフェースでは、初期化、開始および終了関数は以下のようなものとなります。
初期化:
int init() { int Digit; if(IsDllsAllowed() == false) { Print("Calling from libraries (DLL) is impossible." + " EA cannot be executed."); return(0); } if(!IsTradeAllowed()) { Print("Trade is not permitted!"); return(0); } Digit = MarketInfo(Symbol(), MODE_DIGITS); if((Digit > 0) && (Bid > 0)) { if(!NewExpert(AccountServer(), Symbol(), Digit)) { Print("Creation of a new broker failed"); return (0); } Print("A broker is successfully created "); return(0); } Print("No symbol in MarketInfo!"); return(0); }
初期化中、ターミナルパラメータ(トレード許可と DLL 呼び出し確認)確認後、銘柄の数字と現行価格の情報を受け取ります。パラメータが両方ゼロより大きければ、その銘柄はターミナルに適切に存在し、それを処理することができます。ブローカーはそれぞれ関数 AccountServer() によって受け取る名前が異なります。この名前ごとにターミナルは共有メモリ内でお互いが異なっています。EA はトレードを行っている銘柄名で異なっています。異なる複数の EA が同一の通貨ペアにアタッチされた場合、それらが衝突につながる同一 DLL コピーをダウンロードするのはこのためです。
新規オーダーオープンの関数
int Deal(int act, double Lot) { int N = 0; int ticket; int err; double Price_open; double Real_price; datetime begin_deal; double Lots; int cmd; int magik; magik = GenericMagik() + 1; Lots = NormalizeDouble(Lot, 1); // checking margin for a position opening AccountFreeMarginCheck(Symbol(), cmd, Lots); err = GetLastError(); if(err > 0) { Print("No money for new position"); return(0); } begin_deal=TimeCurrent(); while(N < count) { if(act == 1) { Price_open = NormalizeDouble(Ask, Digits); cmd = OP_BUY; } if(act == 2) { Price_open = NormalizeDouble(Bid, Digits); cmd = OP_SELL; } ticket = OrderSend(Symbol(), cmd, Lots, Price_open, slippage, 0, 0, 0, magik); if(ticket > 0) { if(OrderSelect(ticket, SELECT_BY_TICKET) == true) { Real_price = OrderOpenPrice(); NewDeal(Symbol(), cmd,magik, Real_price , MathAbs(Real_price - Price_open), (TimeCurrent() - begin_deal), N); } return(ticket); } N++; Sleep(5000); RefreshRates(); } return(0); }
オーダーはパラメータを2つもつ関数 Deal によってオープンされます。2つのパラメータはアクション(1-買い、2-売り)とロットです。各オーダーは前回のオーダーとマジックが異なります。マジックは増加しています。ポジションはカウント試行でオープンしようとします。オープン期間、価格、スリッページとともに試行回数についての情報は、モニターにより読み取られる個所から共有メモリに渡されます。
オーダー終了関数
bool CloseOrder(int magik) { int ticket, i; double Price_close; int count = 0; datetime begin_time; double Real_close; begin_time = TimeCurrent(); for(i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) if(OrderSymbol() == Symbol()) if(OrderMagicNumber() == magik) { while(count < 10) { if(OrderType() == OP_BUY) Price_close = NormalizeDouble(Bid, Digits); if(OrderType() == OP_SELL) Price_close = NormalizeDouble(Ask, Digits); if(OrderClose(OrderTicket(), OrderLots(), Price_close, slippage)) { Real_close = OrderClosePrice(); CloseDeal(Symbol(), magik, Real_close, MathAbs(Real_close - Price_close), (TimeCurrent() - begin_time), count); return(true); } count++; Sleep(5000); RefreshRates(); } } } return(false); }
終了の関数 CloseOrder() は入力パラメータを1つしか持ちません。それが magic です。オーダーは複数回クローズしようとし、この試行回数が取引実行時刻、終値、スリッページと共にメモリに渡され、モニターによって読み取られます。
残りのコードは検証済み EA です。ご自分の EA で Statistic を使用するには、必要な dll 関数をインポートする必要があります。初期化およびポジションのオープン/クローズには関数 Deal および CloseOrder を使用します。お望みなら、これら関数を書き直すことができますが、取引上のデータは dll のインターフェースに従って渡されます。
以下は、DLL を使用したEA の実装例です(上記で列挙した関数コードは含まれていません)。
// Enable dll for operation with monitor #import "statistik.dll" bool NewExpert(string isBrokerName, string isInstrument, int Digit); // Create a broker bool NewDeal(string isInstrument, int Action, int magik, double PriceOpen, int Slippage, int TimeForOpen, int Requotes); bool CloseDeal(string isInstrument, int magik, double PriceClose, int Slippage, int TimeForClose, int Requotes); #import //---- extern int Num_Deals = 3; extern int TimeInMarket = 4; // maximally acceptable slippage int slippage = 10; // time for rest after a trade int TimeForSleep = 10; // period of request int time_for_action = 1; // number of attempts for opening a position int count = 5; // Function of a new bar bool isNewBar() { static datetime BarTime; bool res = false; if(BarTime != Time[0]) { BarTime = Time[0]; res = true; } return(res); } //+------------------------------------------------------------------+ //| Generation of magic | //+------------------------------------------------------------------+ int GenericMagic() { int deals; //---- for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) if(OrderSymbol() == Symbol()) if(OrderMagicNumber() != 0) deals++; } return (deals); } //+------------------------------------------------------------------+ //| forming signals to open/close a position | //+------------------------------------------------------------------+ int GetAction(int &action, double &lot, int &magic) { int cnt, total; if(OrdersTotal() <= Num_Deals) { if(Close[1] > Close[2]) { action = 1; lot = 1; return(0); } if(Close[2] < Close[1]) { action = 2; lot = 1; return(0); } } total = OrdersTotal(); for(cnt = total - 1; cnt >= 0; cnt--) { if(OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES)) if(OrderSymbol() == Symbol()) if((TimeCurrent() - OrderOpenTime()) > TimeInMarket*60) { action = 3; magic = OrderMagicNumber(); return(0); } } } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { int action = 0; double lot = 1; int magic = 0; while(!IsStopped()) { Sleep(time_for_action*1000); RefreshRates(); if(isNewBar()) { GetAction(action, lot, magic); if(((action == 1) || (action == 2))) { if(IsTradeAllowed()) Deal(action, lot); Sleep(TimeForSleep*1000); } if(action == 3) { if(IsTradeAllowed()) if(!CloseOrder(magik)) { Print("MANUAL CLOSING OF A POSITION IS NEEDED"); Sleep(TimeForSleep*1000); } } action = 0; lot = 0; magik = 0; } } Print("A serious error occurred, the EA stopped operating"); return(0); } //+------------------------------------------------------------------+
解析ブロックは基本で、ここでは前回バーがその前のバーより大きければ買い、逆であれば売りです。ポジションは時刻でクローズされます。ご自分の EA をテストするには、このブロックをアルゴリズムに従って書き直すだけです。実行箇所に変更はしません。
DLL
DLL は異なる環境、言語で実装される可能性があります。われわれの作業に必要な dll は Visual C++ で作成されています。トレードは以下のようなストラクチャです。
struct DealRec { int Index; int Magic; int Cur; int Broker; double PriceOpen; double PriceClose; int SlipOpen; int SlipClose; int Action; // 0 = BUY 1 = SELL int TimeForOpen; int TimeForClose; int ReqOpen; int ReqClose; int Profit; bool Checked; // indication that the position is closed };
2段階で達成されます。オープンとクローズです。すなわち、データの一部(始値、開始時のスリッページなど)はオープン時に渡され、別の部分(終値、終了時刻など)はクローズ時に渡されます。dll で関数を呼び出すプロトタイプ
__declspec(dllexport) bool __stdcall NewExpert (char *isBrokerName, char *isInstrument, int Digit); __declspec(dllexport) bool __stdcall NewDeal (char *isInstrument, int Action, int magic, double PriceOpen, int Slippage, int TimeForOpen, int Requotes); __declspec(dllexport) bool __stdcall CloseDeal (char *isInstrument, int magic, double PriceClose, int Slippage, int TimeForClose, int Requotes);
は渡す行でのみ MQL4 ではプロトタイプとは異なります。ソース dll をすべて見ると、別のプロジェクト作成に役立ちます。プロジェクトの再コンパイルには、プログラム Visual C++ でファイルstatistic.dsw を開きます。dll のコード全体はファイル statistic.cpp および statistic.h にあり、残りは補助的なものです。列挙されたファイルはすべて Statistic.zip にあります。
モニター
テーブルおよびグラフィカルインターフェースを伴うアプリケーションを迅速に書くための最適ツール-ボーランドからのソリューションです。それは Delphi と C++ビルダーです。
モニター機能:共有メモリを作成し、そこからデータを読み出し、テーブルに表示、スリッページの統計を保持します。作業をより便利にするオプションはほかにもいくつかあります。以下がモニターの機能です。
- オープン済みポジションのジャーナル維持
- クローズ済みポジションのジャーナル維持
- スリッページと再クオートの統計
- 調整可能テーブル
- html ファイルへのトレード保存
実装は添付 zip ファイル Statistic Monitor.zip にあります。プロジェクトの再コンパイルには、プログラム C++ビルダーを使用します。プロジェクトファイルの拡張子は *.bpr です。主要コードは в main.cpp にあります。
検証
検証には特別な EA が作成されました。それは時刻によるポジションのエンターとクローズというもっともシンプルな条件になっています(実装は前に表示しています)。dll と monitor.exe 付き EA は zip ファイル monitor+dll+expert.zip にあります。検証開始時には「開始する」をクリックし、共有メモリを作成します。DLL はフォルダsystem32 に入れる必要があります。その後、複数ターミナルを起動し、取引を行おうとしている通貨のチャートに EA をアタッチします。数多くのトレードをしたら、統計値が蓄積されます。データはモニター/ジャーナルに集められます。ときどき、データはファイルに転送され html ページの形式で格納されます。
アプリケーションの実操作も同様です。それによりトレーダーは、技術的特徴の観点で異なる仲介会社の処理を比較し、自動売買にもっとも適した会社を選択することができるのです。
おわりに
MQL4 で dll を有効化することで、異なるアプリケーション プログラム開発が可能となります。それはトレードに関する判断をするだけでなく統計を収集するのにも役立ちます。後者はトレードおよび仲介会社選択ににひじょうに便利です。作成されたアプリケーションは、作成者がこのむつかしい検索を行う手助けをします。ブローカーを分析するには、本稿で分析した例で説明されているように、statistic.dll を Expert Advisor にアタッチします。この作業に必要なファイルは、monitor+dll+expert.zip にあります。処理には、statistic.dll をフォルダ system32 にコピーし、Statistic.exe を任意のロケーションから起動し、Expert Advisors を持つターミナルを開きます。それは dll をダウンロードし、トレーディングを開始し、データを共有メモリに渡し始めます。Statistic.exe は補助ファイルを作成します。アプリケーションを空のフォルダから開始する方がよいのはそのためです。プログラムが売買ロボット開発者にとって興味深いものであれば、変更し修正することが可能です。
自動売買については、すべての仲介会社が同様の条件を提供しているわけではないことに注意が必要です。
- ブローカーは自動売買を禁じている可能性もあります。
- ブローカーは発注時 SL や TP を指定するのを禁じている可能性もありますhttps://www.mql5.com/ru/forum/103341。
- SL と TP に対する非対称レベル
- オーダーを相互にオープンするオプションがない場合があります。
- 1アカウントで同時にオープンされるポジション数の制限オーダー(オープンポジション + 未決注文)数が制限数を超えると、関数 OrderSend がエラーコードERR_TRADE_TOO_MANY_ORDERS を返します。
- その他の制限
取引しようとお考えの仲介会社の規則を注意して読むことを強くお薦めするのはこの理由からです。
プロジェクト Statistic は、MQL4 オプションに別言語やプログラム環境の機能を追加する場合、どのような複合体を作成することができるかを示しています。作成されたプログラムは Expert Advisor が異なる仲介会社と連携するのに有用なものです。というのも、それは都合のよい形式で仲介会社の技術的特色を分析するのに役立つためです。仲介会社がスリッページを設定しているなら、トレードは時刻で実行され、再クオートが頻発します。そうすると、何のためにそのような仲介会社が必要なのか、ということになります。選択肢はひじょうに多くあるのです!
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1476
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索