市場シミュレーション(第4回):C_Ordersクラスの作成(I)
はじめに
前回の「市場シミュレーション(第82回):パフォーマンスの問題」では、当面の間ではありますが、パフォーマンスを低下させていたいくつかの問題を回避するために、クラスに調整を加えました。これらの問題は現時点では解決されていますが、今私たちは本当に、かなり複雑な課題に直面しています。この最初のパートではそこまでではありません。なぜなら、ここで扱うテーマについては、これまでの記事ですでに触れてきたからです。ただし、今回は少し異なるアプローチで進めます。その結果、この問題の扱い方もやや異なったものになります。
多くの方が、リプレイやシミュレーターがついに注文を実行する様子を見るのを心待ちにしていることは承知しています。しかし、その前に、注文システムが完全に動作していることを確認する必要があります。これは、デモ口座であれリアル口座であれ、実際の取引サーバーと通信するために不可欠です。いずれの場合でも、Chart Tradeインジケーター、マウスインジケーター、そしてエキスパートアドバイザー(EA)といったアプリケーションが完全に調和して動作し、実際の取引サーバーとの円滑な通信を確保しなければなりません。
上記のアプリケーションに加えて、他のコンポーネントも作成する必要があります。ただし、これらについては今は脇に置いておいて構いません。というのも、それらの開発は、概念設計と実装の両面において、現段階で扱われるいくつかの要因に依存しているからです。
この記事では、取引サーバーとどのように通信するかの説明を始めます。すでにこの方法をよく理解している方も多いかもしれません。その場合は、少し辛抱していただければと思います。私たちは急ぐのではなく、意図的に慎重に進めていきます。実際に何が起きているのかを完全に理解することが非常に重要だからです。一般的な多くのプログラミング手法とは異なり、このシステムはモジュール単位で構築され、それぞれが非常に特定の役割を担います。ひとつのモジュールが失敗すれば、システム全体が失敗します。他の方法で機能を保証するバックアップシステムは存在しないからです。
概念の理解
この連載を追ってきた方であれば、「リプレイシステムの開発(第78回):新しいChart Trade (V)」の記事において、インタラクションがどのようにおこなわれるかを示し始めた際、EAは実際には注文がどこから来ているのかを知らない、という点に気付いたかもしれません。しかし同じEAは、受信したメッセージをどのように解釈するかは理解しています。当時使用していた手法では両建て注文システムを実現することはできませんでしたが、その後の記事でこの問題には対処しました。「市場シミュレーション(第2回):両建て注文(II)」では、EAと通信するためのメッセージングシステムがどのような構造になるのかを示しました。
この仕組み全体は、さらに大きな概念の一部です。そのため、このメッセージングメカニズムを理解することは、この記事でこれから探求し始める内容を理解するうえで極めて重要です。これまでの記事で説明してきた内容を過小評価したり、見落としたりしないでください。そして何よりも、実際に動作しているのを見るまでは、完全に理解したと早合点しないでください。
これまでに提示してきたEAのコードを理解できていれば、ここでプログラムされる内容を理解するのはそれほど難しくないはずです。ただし、繰り返しになりますが、コードを眺めただけで理解したつもりにならないでください。システム全体がどのように機能しているのかを完全に理解するためには、各細部がどのように動作しているのかを理解する必要があります。
成行注文の開始
説明すべき概念が数多くあるため、以下のコードでは最初からクラス全体を示すことはしません。同様に、この記事の中に大量のコードを一気に掲載することもしません。このセクションでは、慎重な理解が求められます。なぜなら、ここで扱うコードは実際にお金を扱うものだからです。読者の皆さん自身のお金です。各部分がどのように機能しているのかを理解することで、提示されるコードに対して安心感と信頼感を持てるようになります。理解できていないからという理由だけでコードを変更してほしくはありません。変更は、現在存在しない機能を追加する必要がある場合にのみおこない、単に特定のコーディングスタイルに慣れているからという理由ではおこなわないでください。このコードは、後に注文シミュレーションを実装する際にも使用されるため、注意深く学んでください。
説明をできるだけ簡単にするために、まずはサーバーに注文を送信する役割を担う初期クラスを確認することから始めましょう。これは、現在扱っている実際のサーバーであっても、後で見ることになるシミュレーションサーバーであっても同じです。いずれの場合でも、コードは以下に示す形で始まります。最初のコードスニペットは次のとおりです。
001. //+------------------------------------------------------------------+ 002. #property copyright "Daniel Jose" 003. //+------------------------------------------------------------------+ 004. #include "..\Defines.mqh" 005. //+------------------------------------------------------------------+ 006. class C_Orders 007. { 008. protected: 009. //+------------------------------------------------------------------+ 010. inline const ulong GetMagicNumber(void) const {return m_MagicNumber;} 011. //+------------------------------------------------------------------+ 012. private : 013. //+------------------------------------------------------------------+ 014. MqlTradeRequest m_TradeRequest; 015. ulong m_MagicNumber; 016. bool m_bTrash; 017. //+------------------------------------------------------------------+ 018. struct stChartTrade 019. { 020. struct stEvent 021. { 022. EnumEvents ev; 023. string szSymbol, 024. szContract; 025. bool IsDayTrade; 026. ushort Leverange; 027. double PointsTake, 028. PointsStop; 029. }Data; 030. //--- 031. bool Decode(const EnumEvents ev, const string sparam) 032. { 033. string Res[]; 034. 035. if (StringSplit(sparam, '?', Res) != 7) return false; 036. stEvent loc = {(EnumEvents) StringToInteger(Res[0]), Res[1], Res[2], (bool)(Res[3] == "D"), (ushort) StringToInteger(Res[4]), StringToDouble(Res[5]), StringToDouble(Res[6])}; 037. if ((ev == loc.ev) && (loc.szSymbol == _Symbol)) Data = loc; 038. 039. return true; 040. } 041. //--- 042. }m_ChartTrade; 043. //+------------------------------------------------------------------+ 044. ulong SendToPhysicalServer(void) 045. { 046. MqlTradeCheckResult TradeCheck; 047. MqlTradeResult TradeResult; 048. 049. ZeroMemory(TradeCheck); 050. ZeroMemory(TradeResult); 051. if (!OrderCheck(m_TradeRequest, TradeCheck)) 052. { 053. PrintFormat("Order System - Check Error: %d", GetLastError()); 054. return 0; 055. } 056. m_bTrash = OrderSend(m_TradeRequest, TradeResult); 057. if (TradeResult.retcode != TRADE_RETCODE_DONE) 058. { 059. PrintFormat("Order System - Send Error: %d", TradeResult.retcode); 060. return 0; 061. }; 062. 063. return TradeResult.order; 064. } 065. //+------------------------------------------------------------------+ 066. ulong ToMarket(const ENUM_ORDER_TYPE type) 067. { 068. double price = SymbolInfoDouble(m_ChartTrade.Data.szContract, (type == ORDER_TYPE_BUY ? SYMBOL_ASK : SYMBOL_BID)); 069. double vol = SymbolInfoDouble(m_ChartTrade.Data.szContract, SYMBOL_VOLUME_STEP); 070. uchar nDigit = (uchar)SymbolInfoInteger(m_ChartTrade.Data.szContract, SYMBOL_DIGITS); 071. 072. ZeroMemory(m_TradeRequest); 073. m_TradeRequest.magic = m_MagicNumber; 074. m_TradeRequest.symbol = m_ChartTrade.Data.szContract; 075. m_TradeRequest.price = NormalizeDouble(price, nDigit); 076. m_TradeRequest.action = TRADE_ACTION_DEAL; 077. m_TradeRequest.sl = NormalizeDouble(m_ChartTrade.Data.PointsStop == 0 ? 0 : price + (m_ChartTrade.Data.PointsStop * (type == ORDER_TYPE_BUY ? -1 : 1)), nDigit); 078. m_TradeRequest.tp = NormalizeDouble(m_ChartTrade.Data.PointsTake == 0 ? 0 : price + (m_ChartTrade.Data.PointsTake * (type == ORDER_TYPE_BUY ? 1 : -1)), nDigit); 079. m_TradeRequest.volume = NormalizeDouble(vol + (vol * (m_ChartTrade.Data.Leverange - 1)), nDigit); 080. m_TradeRequest.type = type; 081. m_TradeRequest.type_time = (m_ChartTrade.Data.IsDayTrade ? ORDER_TIME_DAY : ORDER_TIME_GTC); 082. m_TradeRequest.stoplimit = 0; 083. m_TradeRequest.expiration = 0; 084. m_TradeRequest.type_filling = ORDER_FILLING_RETURN; 085. m_TradeRequest.deviation = 1000; 086. m_TradeRequest.comment = "Order Generated by Experts Advisor."; 087. 088. MqlTradeRequest TradeRequest[1]; 089. 090. TradeRequest[0] = m_TradeRequest; 091. ArrayPrint(TradeRequest); 092. 093. return (((type == ORDER_TYPE_BUY) || (type == ORDER_TYPE_SELL)) ? SendToPhysicalServer() : 0); 094. }; 095. //+------------------------------------------------------------------+ 096. public : 097. //+------------------------------------------------------------------+ 098. C_Orders(const ulong magic) 099. :m_MagicNumber(magic) 100. { 101. } 102. //+------------------------------------------------------------------+ 103. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 104. { 105. switch (id) 106. { 107. case CHARTEVENT_CUSTOM + evChartTradeBuy : 108. case CHARTEVENT_CUSTOM + evChartTradeSell : 109. case CHARTEVENT_CUSTOM + evChartTradeCloseAll: 110. if (m_ChartTrade.Decode((EnumEvents)(id - CHARTEVENT_CUSTOM), sparam)) switch (m_ChartTrade.Data.ev) 111. { 112. case evChartTradeBuy: 113. ToMarket(ORDER_TYPE_BUY); 114. break; 115. case evChartTradeSell: 116. ToMarket(ORDER_TYPE_SELL); 117. break; 118. case evChartTradeCloseAll: 119. break; 120. } 121. break; 122. } 123. } 124. //+------------------------------------------------------------------+ 125. }; 126. //+------------------------------------------------------------------+
C_Replay.mqhファイルのソースコード
では、このコードが実際に何をしているのかを理解していきましょう。一見すると複雑に見えるかもしれませんが、実際には非常にシンプルで、ひとつの機能だけを実行します。それは、ユーザーとChart Tradeインジケーターとのインタラクションに応じて、成行の買い注文または売り注文を送信することです。しかし、どのようにしてそれを実現しているのでしょうか。Chart Tradeインジケーターを何らかの形で変更するのだろうと考えた方もいるかもしれません。もしそう思ったのであれば、それはこのシステムの仕組みをまだ十分に理解していないということになります。インジケーターは取引サーバーに注文を送信することはできません。インジケーターの役割は、チャート上に情報を表示することです。Chart Tradeインジケーターの場合、その役割は、ユーザーがシステムの他の部分とやり取りできるようにすることにあります。
実際にこのヘッダファイルを使用するEAを紹介する前に、ここで一度立ち止まり、すでに説明してきた内容を振り返ってみましょう。そうすることで、このヘッダファイルをより理解しやすくなります。
「リプレイシステムの開発(第78回):新しいChart Trade (V)」は、EAが受け取るべきメッセージについて説明しました。その際、OnChartEventプロシージャを使用して、これらのメッセージを捕捉していたことに気付いたかもしれません。このプロシージャの中で、あるクラスを呼び出していました。そのクラスは、受信したメッセージを解釈し、分析のためにターミナルへ出力していました。この部分は比較的簡単でした。なぜなら、そのデータを使って取引サーバーと通信する必要がなかったからです。
EAのソースコードを見ると、OnChartEventプロシージャ内でDispatchMessageを呼び出している箇所があることが分かります。この呼び出しによって、実際にこのヘッダファイルが実行されます。具体的には103行目です。しかし、そこに到達する前に、まずは最初から見ていきましょう。
98行目にあるクラスのコンストラクタです。このコンストラクタは非常にシンプルです。呼び出されると、1つの引数を受け取ります。この値は、クラスをマジックナンバーで識別するために使用されます。ここで重要な点があります。それは、EA自体を識別しているのではなく、クラスを識別しているという点です。なぜこのような区別をするのでしょうか。同じ種類の処理をおこなう、よく似たクラスを別々に使いたい場合があるからです。現時点では必要性を感じにくいかもしれませんが、読み進めていくうちに明確になっていきます。この特定のクラスでは、いくつかの要素を使用していませんが、それについては後ほど説明します。
たとえば、注文が存在せず、ポジションのみが残っている状態になった場合、それらを特定の方法で処理したいと考えることがあるかもしれません。そのために複数のEAを使用するのは、エラーの原因になりやすい方法です。さらに、1つのチャートには1つのEAしか動作させることができません。(同じ銘柄に複数のEAを使用できないと言っているわけではありません。同一チャート上に複数配置できないという意味です。)
同じ銘柄のチャートを複数開き、それぞれに異なるEAを動かすという方法は、管理が非常に難しくなります。理解できる人もいるでしょうが、私自身は非常に混乱しやすいと感じます。一方で、わずかに異なるクラスを同一のEA内に配置し、それらが調和して動作するようにする方法であれば、十分に管理可能です。そのため、コンストラクタがクラスを生成する際に、マジックナンバーが割り当てられます。この番号は、後に注文やポジションで使用されることになります。これについては後ほど確認します。
マジックナンバーは99行目で初期化され、それを保持する変数は15行目で宣言されています。また、12行目にはprivate句があり、12行目から96行目までのすべてがクラス内にカプセル化されています。これには、14行目から16行目の間で宣言されている変数も含まれます。
続ける前に、10行目に注目してください。ここには、このクラスに定義されたマジックナンバーを返す関数があります。この行は、8行目のprotected句と12行目のprivate句の間に位置しているため、継承システムの外部からは使用できません。つまり、C_Ordersを継承していないクラスの外部からこの関数にアクセスしようとすると、コンパイルエラーになります。
この関数は、将来的な用途のために用意されているもので、目的はマジックナンバーを返すことだけです。現時点では、これ以上深く掘り下げる必要はありません。今の段階では、10行目のこの関数は継承システムの外からはアクセスできず、このクラスのマジックナンバーを返すだけのものである、という理解で十分です。
以降のコードを理解しやすくするために、内容をトピックごとに分けて説明していきます。ただし、それぞれのトピックは、同じコードを参照することになります。
構造体内のプロシージャ?
「リプレイシステムの開発(第78回):新しいChart Trade (V)」では、翻訳システムを実装するためにクラスを使用しました。しかし、ここでは構造体を使用しています。これは可能なのでしょうか。答えは「はい」です。なぜなら、クラスは本質的に、より多機能な構造体だからです。今回必要としているものは、よりシンプルにモデル化できるため、構造体を選択しました。これは18行目から42行目の間を見ると分かります。
注意してください。18行目で構造体が宣言されています。もしこれがクラスであった場合、18行目から42行目までのすべてはprivateになります。その場合、アクセスを調整するためにpublic句が必要になります。それ自体は問題ではありません。しかし、なぜクラスの中にさらにクラスを宣言する必要があるのでしょうか。通常、それはコードをより混乱させるだけです。
私たちが必要としているデータはメッセージから来るものであり、これは一連の変数の集合と考えることができます。それなら、メッセージをひとつの大きな変数セットとして考えてみてはどうでしょうか。そうすれば理解が簡単になりますよね。
メッセージの構造は20行目から29行目の間にあります。データ構造全体は18行目から42行目までですが、メッセージそのものは20行目から29行目の部分として扱われます。以前の記事で説明したように、メッセージは文字列です。もし構造体の長さだけを基準にして文字列を解析しようとすると、簡単に誤解釈が発生します。そのため、メッセージをデコードするための追加コードが必要になります。
31行目から40行目には、このメイン構造体の中にある関数が定義されており、その処理を担当します。ただし、これはメッセージ構造そのものの一部ではありません。ロジックを分離することで、エラーのリスクを低減しています。なぜでしょうか。それは、要素がそれぞれ独立して存在しているからです。メッセージ構造、関数、プロシージャをすべてひとまとめにすることも可能です。しかし、そのようにすると、実装時に問題を引き起こす可能性が高くなります。
ここは非常に混乱しやすい部分なので、特に注意してください。これを理解できれば、多くのプログラマーが、使用可能であっても構造体を避ける理由が分かるようになります。そして、構造体を使おうとする一部のプログラマーは、特にレガシーなC言語でコードを書いた場合、プログラムを時限爆弾のようなものにしてしまうことがあります。
36行目には特に注意してください。この行には、すべてが混ざり合ってしまう現実的な危険が潜んでいます。この行では、必要なすべての値をデータ構造に格納しています。もしこれが関数やプロシージャであった場合、35行目の実行時に何が起こるでしょうか。さらに悪いことに、36行目で上書きされたメモリ上にある関数やプロシージャを呼び出したらどうなるでしょうか。データの上書きは深刻な結果を招く可能性があり、これがレガシーCでクラスの使用が強調される重要な理由のひとつです。しかし、その仕組みを理解すれば、なぜクラスが作られたのかも理解できます。
何が起こり得るかの詳細には踏み込みません。ただし、本当に悪意のあるプログラマーは、あなたが想像もできないようなことをおこなえる、という点だけは忘れないでください。では、コードの話に戻りましょう。31行目の関数は、以前と同じ役割を果たしています。ただし、110行目でこの関数がどのように呼び出されているかを見てください。関数名を直接呼び出しているのではなく、追加の参照が必要になっていることに気付くはずです。これは、構造体を表すデータを保持している変数への参照です。混乱して見えるかもしれませんが、実際はそうではありません。構造体を使っていることはいったん忘れて、クラスのメソッドを呼び出していると考えてみてください。ロジックは同じです。
DECODEがC_Ordersの一部ではない理由を疑問に思う方もいるかもしれません。もしそうであれば、110行目の呼び出しは不要になります。しかし、DECODEはデータを含むメッセージをデコードするために独立して存在しています。そのため、C_Ordersクラス内に宣言する意味はありません。常に、利便性ではなく、論理的な観点から要素を分離するようにしてください。もしDECODE関数をC_Ordersクラス内に宣言してしまうと、将来、別のデータ構造を対象とした同名のプロシージャを使いたくなった場合、衝突を避けるためにまったく異なる名前を考えなければなりません。さらに悪いことに、時間が経ってコードが変化していくにつれて、何が何なのか分かりにくくなっていきます。このように、責務を論理的に分離することで、将来的な名前衝突を防ぎ、潜在的なエラーを減らすことができます。
サーバーとの通信
この部分は、特にプログラミングを始めたばかりの方にとって混乱しやすいところです。もしこのセクションが分かりにくいと感じたのであれば、それは、実際に何をしなければならないのかをまだ完全には理解できていないということを意味します。チャートを眺めて判断するトレーダーとは異なり、プログラマーは処理を「正しく書類を記入する作業」として捉えなければなりません。もし書類に不備があれば、サーバーは几帳面な雇用主のように、それを受け付けずに却下します。
サーバーはミスを理解してくれる存在ではありません。不適切なリクエストは単純に拒否されます。ただし、拒否した理由については通知してくれます。通信手順が正しく構成されていれば、サーバーとのやり取りは円滑におこなわれます。
44行目から64行目には、サーバーとの通信を処理する関数があります。非常にシンプルに見えますが、必要な手順はすべて含まれています。ここでは、処理の論理的な順序に注意してください。以前と同じやり方をそのまま使うことはできません。次の順序を必ず守る必要があります。まず、レスポンス用のメモリをクリアします。これは49行目から50行目でおこなわれます。次に、リクエストの検証をおこないます。つまり、送信前にデータをチェックします。この確認は51行目でおこなわれます。もしエラーがあれば、対応するエラーコードが返され、それを修正して再試行することができます。すべてが正しければ、56行目でリクエストがサーバーに送信されます。
サーバーからの戻り値は、コンパイラ警告を避けるために、一時的な変数に格納されます。なぜなら、私たちが関心を持っているのは関数そのものの戻り値ではないからです。本当に重要なのは、レスポンス構造体の内容です。57行目では、その結果がTRADE_RETCODE_DONEと異なるかどうかを確認しています。異なっていれば、エラーが発生したということになります。その場合、対応するエラーコードがターミナルに表示されます。これは59行目でおこなわれます。
エラーが発生した場合、44行目の関数はゼロを返します。問題がなければ、サーバーから返されたチケット番号を返します。このチケットは、注文やポジションを識別するためのものです。これについては、後ほど実際に注文やポジションを操作する段階で説明します。現時点では、私たちは成行注文リクエストを送信しているだけです。
このようなリクエストは、66行目にある別の関数でおこなわれます。この関数は、買いか売りかを示す1つの引数を受け取ります。Chart Tradeインジケーターから成行アクションを指示するメッセージが届いたとき、113行目と116行目でこの関数が呼び出されます。しかし、サーバーはどのようにして、ストップロス、テイクプロフィット、レバレッジ、あるいは取引銘柄の情報を知るのでしょうか。また、両建て注文を使用しているかどうかは、どこで判断されるのでしょうか。さて、そこで次のステップが必要になってきます。
リクエストフォームの記入
44行目のサーバー通信関数を見た場合、51行目と56行目で、その関数内では宣言されていない構造体を使用していることに気付くでしょう。この構造体は、C_Ordersの14行目で宣言されています。これは、クラス全体でアクセス可能なprivateな構造体です。つまり、クラス内部のどこからでもこの変数にアクセスできますが、クラスの外部のコードからはアクセスできません。
したがって、44行目の関数で使用されるこの変数は、正しく値が設定されている必要があります。この設定は66行目から94行目でおこなわれています。構造体を正しく埋めることで、サーバーは希望通りのリクエスト、つまり成行の買い注文または売り注文を実行します。保留中の注文についてや、ストップロスとテイクプロフィットの変更は後ほど説明します。
構造体を埋めるには、いくつかのデータが必要です。一部はChart Tradeから、残りはMetaTrader 5から取得します。いずれにしても、ある論理的な順序に従う必要があります。まず、現在の価格を取得します(68行目)。この行の各要素は非常に重要なので、細部まで注意してください。
また、取引量(ボリューム)を知る必要があります。この段階で多くの人が戸惑います。なぜなら、サーバーが求めるボリュームは別の数値の倍数だからです。チャート上に表示されているボリュームは取引量そのものではなく、レバレッジレベルです。この2つの概念は異なりますが関連しています。レバレッジは最小取引量を乗算します。そのため、混同しないように注意してください。さらに、サーバーは銘柄の小数点桁数も必要とします。この情報は70行目で取得できます。
ここで最も重要なステップに入ります。構造体の値を設定するのです。まず、構造体をクリアします(72行目)。次に、73行目から86行目では、サーバーが具体的にどのような処理を行うかを示す各フィールドに適切な値が設定されます。このリクエストの設定は、株式、OTC市場、FXすべてに対応しています。各フィールドには固有の意味があり、誤解すると金銭的損失につながる可能性があります。保留注文については、後の記事で詳しく説明します。
最後に、設定が完了した構造体はターミナルに出力され、確認できます(88行目~91行目)。方法はいくつかありますが、簡単のためにMQL5標準ライブラリのArrayPrintを使用しています。その後、関数はリクエストのレスポンスを返します(93行目)。
最後に
この記事では、コードの一部分、具体的には成行注文の送信についてのみ取り扱いましたが、このヘッダファイルとChart Tradeインジケーターを組み合わせることで、すでに成行の買い注文と売り注文を実行できます。MqlTradeRequest構造体に関しては、まだ疑問が残るかもしれませんが、保留注文の解説でこれらも明らかになります。次回の記事では、EAのソースコードのさらなる解析を続けます。
| ファイル | 説明 |
|---|---|
| Experts\Expert Advisor.mq5 | Chart TradeとEAの連携を示す(Mouse Study が必要) |
| Indicators\Chart Trade.mq5 | 送信する注文を構成するためのウィンドウを作成する(操作にはMouse Studyが必要) |
| Indicators\Market Replay.mq5 | リプレイ/シミュレーターサービスと対話するためのコントロールを作成する(操作にはMouse Studyが必要) |
| Indicators\Mouse Study.mq5 | グラフィカルコントロールとユーザー間のインタラクションを実現する(リプレイ/シミュレーターおよび実取引の両方で必須) |
| Services\Market Replay.mq5 | マーケットリプレイおよびシミュレーションサービスを生成し、維持する(システム全体のメインファイル) |
MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/12589
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
取引におけるニューラルネットワーク:暗号通貨市場向けメモリ拡張コンテキスト認識学習(MacroHFT)
取引におけるニューラルネットワーク:概念強化を備えたマルチエージェントシステム(最終回)
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
MQL5で自己最適化エキスパートアドバイザーを構築する(第16回):教師あり学習を用いた線形システム同定
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索