一からの取引エキスパートアドバイザーの開発(第12部):Times and Trade (I)
はじめに
テープリーディングは、取引の様々な段階で一部のトレーダーに使用されている取引方法です。この方法は非常に効率的で、正しく使用すれば、純粋なローソク足観察である有名なプライスアクションを使用する場合よりも、安全かつ安定した方法で利益を上げることができます。しかし、現在発表されているテープリーディングの使用方法では、作業が非常に複雑で面倒であり、常に注意力を集中させることが必要です。時間の経過とともに、どうしても観察に間違いが生じるようになります。
テープリーディングで問題になるのは、分析しなければならない情報量の多さです。テープリーディングの典型的な使用例を見てみましょう。
本当の問題は、分析中には価格とその推移を見なければならないが、ミニコントラクトでこれらの値をチェックするのはあまり現実的ではないということです。したがって、通常、市場を動かすのはフルコントラクトであるため、ミニコントラクトのフローの内容は見ずにフルコントラクトを観察することが望ましいと考えます。これは実際にそうで、システムは下図のようになっています。多少は解釈しやすく、フォローしやすくなっています。
ただし、この場合でも、その適用は非常に面倒な作業であり、細心の注意を払う必要があります。ストップポジションが作動すると状況はさらに厳しくなり、この場合、画面上の情報のスクロールが非常に速くなるはずなので動きを見逃してしまうことがあります。
計画
しかし、MetaTrader 5プラットフォームは、ミニコントラクトに対しても代替システムを備えており、モニタリングをより効率的かつ容易にすることができます。ミニコントラクトで作業するときの様子を見てみましょう。
ご覧のように、解釈はもっとシンプルになりますが、先に述べた理由から、フルコントラクトを用いる方が適切であるため、以下のようになります。
取引に関するデータはBIDとASKの動きのノイズに邪魔されています。ここでは、取引を丸で表現しています。赤は売り取引、青は買い取引、緑は直接注文を表しています。観測そのものに必要のない情報が入ってしまうことに加え、実際に取引するチャートとシステムが離れているため2つの画面を監視しなければならないという問題があります。一方、これは利点でもあるのですが、場合によっては事態を大きく複雑化させることにもなります。そこで、ここでは、見やすく、かつ、この指標を取引チャート上で直接見ることができるシステムを提案します。
実装
まず、C_Terminalクラスを変更して、フルコントラクトの資産にアクセスできるようにします。これは、次のコードを追加することでおこないます。
void CurrentSymbol(void) { MqlDateTime mdt1; string sz0, sz1, sz2; datetime dt = TimeLocal(); sz0 = StringSubstr(m_Infos.szSymbol = _Symbol, 0, 3); m_Infos.szFullSymbol = _Symbol; m_Infos.TypeSymbol = ((sz0 == "WDO") || (sz0 == "DOL") ? WDO : ((sz0 == "WIN") || (sz0 == "IND") ? WIN : OTHER)); if ((sz0 != "WDO") && (sz0 != "DOL") && (sz0 != "WIN") && (sz0 != "IND")) return; sz2 = (sz0 == "WDO" ? "DOL" : (sz0 == "WIN" ? "IND" : sz0)); sz1 = (sz2 == "DOL" ? "FGHJKMNQUVXZ" : "GJMQVZ"); TimeToStruct(TimeLocal(), mdt1); for (int i0 = 0, i1 = mdt1.year - 2000;;) { m_Infos.szSymbol = StringFormat("%s%s%d", sz0, StringSubstr(sz1, i0, 1), i1); m_Infos.szFullSymbol = StringFormat("%s%s%d", sz2, StringSubstr(sz1, i0, 1), i1); if (i0 < StringLen(sz1)) i0++; else { i0 = 0; i1++; } if (macroGetDate(dt) < macroGetDate(SymbolInfoInteger(m_Infos.szSymbol, SYMBOL_EXPIRATION_TIME))) break; } } // ... Class code ... inline string GetFullSymbol(void) const { return m_Infos.szFullSymbol; }
ハイライト表示された行を追加することで、目的の資産にアクセスしてTime & Tradeプログラムで使用することができるようになります。次に、Time & Tradeをサポートするオブジェクトクラスの作成に進みます。このクラスには、非常に興味深い関数が含まれることになります。まず、指標を格納するサブウィンドウを作成する必要があります。簡単にできるのですが、実用上の理由から、前回使用したサブウィンドウシステムは使用しないことにします。もしかしたら将来的に概念が変わるかもしれませんが、今のところTime & Tradeは指標システムとは別のウィンドウで動作することになり、準備作業が多くなっています。
まずは、指標に別の名前をつけるために、新しいサポートファイルを作成することから始めましょう。ファイルの上にファイルを作るのではなく、もっとエレガントな方法を取ります。より多くの可能性を持つために、サポートファイルを修正します。新しいサポートファイルは以下の通りです。
#property copyright "Daniel Jose 07-02-2022 (A)" #property version "1.00" #property description "This file only serves as supporting indicator for SubWin" #property indicator_chart_window #property indicator_plots 0 //+------------------------------------------------------------------+ input string user01 = "SubSupport"; //Short Name //+------------------------------------------------------------------+ int OnInit() { IndicatorSetString(INDICATOR_SHORTNAME, user01); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { return rates_total; } //+------------------------------------------------------------------+
ソースファイルに加える変更をハイライト表示しました。次に、EAのコードに変更を加える必要があります。新しいクラスを作成します。
#property copyright "Daniel Jose" //+------------------------------------------------------------------+ #include "C_Terminal.mqh" //+------------------------------------------------------------------+ class C_FnSubWin { private : string m_szIndicator; int m_SubWin; //+------------------------------------------------------------------+ void Create(const string szIndicator) { int i0; m_szIndicator = szIndicator; if ((i0 = ChartWindowFind(Terminal.Get_ID(), szIndicator)) == -1) ChartIndicatorAdd(Terminal.Get_ID(), i0 = (int)ChartGetInteger(Terminal.Get_ID(), CHART_WINDOWS_TOTAL), iCustom(NULL, 0, "::" + def_Resource, szIndicator)); m_SubWin = i0; } //+------------------------------------------------------------------+ public : //+------------------------------------------------------------------+ C_FnSubWin() { m_szIndicator = NULL; m_SubWin = -1; } //+------------------------------------------------------------------+ ~C_FnSubWin() { Close(); } //+------------------------------------------------------------------+ void Close(void) { if (m_SubWin >= 0) ChartIndicatorDelete(Terminal.Get_ID(), m_SubWin, m_szIndicator); m_SubWin = -1; } //+------------------------------------------------------------------+ inline int GetIdSubWinEA(const string szIndicator = NULL) { if ((szIndicator != NULL) && (m_SubWin < 0)) Create(szIndicator); return m_SubWin; } //+------------------------------------------------------------------+ inline bool ExistSubWin(void) const { return m_SubWin >= 0; } //+------------------------------------------------------------------+ }; //+------------------------------------------------------------------+
このクラスはC_SubWindowに代わるもので、チャート上でのサブウィンドウの作成をサポートするようになりました。このクラスの動作を理解するために、以下の新しい C_SubWindowクラスを簡単に見てみましょう。
#include "C_ChartFloating.mqh" #include <NanoEA-SIMD\Auxiliar\C_FnSubWin.mqh> //+------------------------------------------------------------------+ class C_SubWindow : public C_ChartFloating { //+------------------------------------------------------------------+ private : C_FnSubWin m_fnSubWin; //+------------------------------------------------------------------+ public : //+------------------------------------------------------------------+ ~C_SubWindow() { Close(); } //+------------------------------------------------------------------+ void Close(void) { m_fnSubWin.Close(); CloseAlls(); } //+------------------------------------------------------------------+ inline int GetIdSubWinEA(void) { return m_fnSubWin.GetIdSubWinEA("SubWinSupport"); } //+------------------------------------------------------------------+ inline bool ExistSubWin(void) const { return m_fnSubWin.ExistSubWin(); } //+------------------------------------------------------------------+ }; //+------------------------------------------------------------------+
このクラスには、テンプレートをサポートするために使用される指標の定義が含まれていることに注意してください。上のコードでハイライト表示されています。さて、ここからが扱いにくいところです。SubWinSupportの代わりに別の名前を使用すると、C_FnSubWinクラスは別の指標を検索します。この仕掛けを利用して、指標ファイルを作成しないようにします。C_FnSubWinクラスに、目的の指標の短縮名を伝えるだけです。このように、EAのサブウィンドウを作成するためだけに使用する不要なサブウィンドウや指標ファイルの数に制限されることはありません。
この後、C_TimeAndTradeクラスの作成に移ります。
C_TimesAndTradeクラス
C_TimesAndTradeオブジェクトクラスは、それぞれが特定の役割を担っているいくつかの小さな部分から構成されています。以下に示すコードは、EAがこのクラスに対して最初に呼び出すものです。
void Init(const int iScale = 2) { if (!ExistSubWin()) { CreateCustomSymbol(); CreateChart(); } ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_CHART_SCALE, (iScale > 5 ? 5 : (iScale < 0 ? 0 : iScale))); }
このコードは、サポートサブウインドウが存在するかどうかを確認して、まだ存在しない場合は作成します。さて、次にある、このクラスの初期サポートのコードを見てください。
inline void CreateCustomSymbol(void) { m_szCustomSymbol = "_" + Terminal.GetFullSymbol(); SymbolSelect(Terminal.GetFullSymbol(), true); SymbolSelect(m_szCustomSymbol, false); CustomSymbolDelete(m_szCustomSymbol); CustomSymbolCreate(m_szCustomSymbol, StringFormat("Custom\\Robot\\%s", m_szCustomSymbol), Terminal.GetFullSymbol()); CustomRatesDelete(m_szCustomSymbol, 0, LONG_MAX); CustomTicksDelete(m_szCustomSymbol, 0, LONG_MAX); SymbolSelect(m_szCustomSymbol, true); };
このコードでは、カスタム銘柄を作成し、その銘柄内のすべてのデータをリセットします。これから作成するウィンドウに銘柄の内容を表示できるようにするために、まずこの銘柄を気配値表示に追加しておきます。これは次の行でおこなわれます。
SymbolSelect(m_szCustomSymbol, true);
カスタム銘柄は、以下の場所に作成されます。 CustomRobot <銘柄名>を指定します。その初期データは、元の銘柄から提供されます。これは次のコードで実装されています。
CustomSymbolCreate(m_szCustomSymbol, StringFormat("Custom\\Robot\\%s", m_szCustomSymbol), Terminal.GetFullSymbol());
基本的にはそれだけです。EAにクラスを追加して、次のように実行します。
// ... Expert Advisor code #include <NanoEA-SIMD\Tape Reading\C_TimesAndTrade.mqh> // ... Expert Advisor code input group "Times & Trade" input int user041 = 2; //Escala //+------------------------------------------------------------------+ C_TemplateChart Chart; C_WallPaper WallPaper; C_VolumeAtPrice VolumeAtPrice; C_TimesAndTrade TimesAndTrade; //+------------------------------------------------------------------+ int OnInit() { // ... Expert Advisor code TimesAndTrade.Init(user041); OnTrade(); EventSetTimer(1); return INIT_SUCCEEDED; }
結果は次の通りです。
これはまさに期待通りのものでした。次に、_DOLH22チャートに実行した取引の値を追加してみましょう。このチャートは、実行されたすべての取引を反映し、Times & Tradeのグラフィカルな表現を提供します。日本のローソク足のパターンが使いやすいので、その形で提示します。その前に、いくつかのこと、特に銘柄の接続と同期を行う必要があります。これは、次の関数でおこなわれます。
inline void Connect(void) { switch (m_ConnectionStatus) { case 0: if (!TerminalInfoInteger(TERMINAL_CONNECTED)) return; else m_ConnectionStatus = 1; case 1: if (!SymbolIsSynchronized(Terminal.GetFullSymbol())) return; else m_ConnectionStatus = 2; case 2: m_LastTime = TimeLocal(); m_MemTickTime = macroMinusMinutes(60, m_LastTime) * 1000; m_ConnectionStatus = 3; default: break; } }
関数は、ターミナルが接続されているかどうかを確認して銘柄を同期します。その後、値の取り込みを開始し、画面に表示します。ただし、そのためには、初期化コードを少し変更する必要があります。この変更は、次のコードでハイライト表示されています。
void Init(const int iScale = 2) { if (!ExistSubWin()) { CreateCustomSymbol(); CreateChart(); m_ConnectionStatus = 0; } ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_CHART_SCALE, (iScale > 5 ? 5 : (iScale < 0 ? 0 : iScale))); }
その後、キャプチャ関数を見ることができます。
inline void Update(void) { MqlTick Tick[]; MqlRates Rates[def_SizeBuff]; int i0, p1, p2 = 0; int iflag; if (m_ConnectionStatus < 3) return; if ((i0 = CopyTicks(Terminal.GetFullSymbol(), Tick, COPY_TICKS_ALL, m_MemTickTime, def_SizeBuff)) > 0) { for (p1 = 0, p2 = 0; (p1 < i0) && (Tick[p1].time_msc == m_MemTickTime); p1++); for (int c0 = p1, c1 = 0; c0 < i0; c0++) { if (Tick[c0].volume == 0) continue; iflag = 0; iflag += ((Tick[c0].flags & TICK_FLAG_BUY) == TICK_FLAG_BUY ? 1 : 0); iflag -= ((Tick[c0].flags & TICK_FLAG_SELL) == TICK_FLAG_SELL ? 1 : 0); if (iflag == 0) continue; Rates[c1].high = Tick[c0].ask; Rates[c1].low = Tick[c0].bid; Rates[c1].open = Tick[c0].last; Rates[c1].close = Tick[c0].last + ((Tick[c0].volume > 200 ? 200 : Tick[c0].volume) * (Terminal.GetTypeSymbol() == C_Terminal::WDO ? 0.02 : 1.0) * iflag); Rates[c1].time = m_LastTime; p2++; c1++; m_LastTime += 60; } CustomRatesUpdate(m_szCustomSymbol, Rates, p2); m_MemTickTime = Tick[i0 - 1].time_msc; } }
上記の関数により、すべての取引ティックを完全に取り込み、それが売りティックなのか買いティックなのかを確認することができます。これらのティックがBIDまたはASKの変更に関連している場合(出来高のない場合)、情報は保存されません。ティックにも同様の懸念があります。ティックは価格の動きには影響を与えない直接注文ですが、直接注文を満たすためだけに価格をある値に強制し、その直後に価格を自由に動かせる市場関係者がいるため、しばしば動きに関係することがあります。これらのBIDやASKの修正に関わるティックは、システム全体から見れば二の次なので、次回以降、別のバージョンで使用することにします。トランザクションの種類を確認した後の一連の行は非常に重要なので、理解しておいてください。以下のコードでは、分析システムを通過して保存する必要がある各ティックごとに1つのローソク足を構築します。
Rates[c1].high = Tick[c0].ask;
Rates[c1].low = Tick[c0].bid;
Rates[c1].open = Tick[c0].last;
Rates[c1].close = Tick[c0].last + ((Tick[c0].volume > 200 ? 200 : Tick[c0].volume) * (Terminal.GetTypeSymbol() == C_Terminal::WDO ? 0.02 : 1.0) * iflag);
Rates[c1].time = m_LastTime;
ローソク足の高値と安値は取引時のスプレッドを示します。 つまりBIDとASKの間に存在した値は作成されたローソク足の髭となり 、ローソク足の始値は実際に取引が成立した時の価格となります。次に、ハイライト表示されたコード行をよくご覧ください。取引ティックに出来高がある場合、この行はその出来高に小さな調整を加えて、スケールがオーバーフローしないようにします。資産に応じて、ご自身の分析に基づき、ご自身の判断で数値を調整されることをお勧めします。
さて、最後の詳細は時間です。それ未満の値をプロットすることはできないため、各ローソク足は1分間に対応します。そして、それぞれが1分ごとに対応するポジションに留まることになります。これは現実の時間ではなく、仮想の時間です。取引時間とグラフィック時間を混同しないでください。操作はミリ秒単位でおこなわれますが、グラフィック情報はグラフィックスケールで1分ごとにプロットされます。他の値でも良いのですが、このように最小にすることでプログラミングが非常に簡単になります。このシステムの結果は以下の通りです。
読み取りがかなり可能で解釈がシンプルになったことがわかります。キャプチャ時のオーダーテープは非常に遅かったのですが、イメージは十分伝わると思います。
このシステムの最終的な情報は、下図で見ることができます。
システムには4種類の構成がありますが、これらは何のために必要なのでしょうか。これについては、次回説明します。これは、Times & Tradeの構成が 4 つある理由を理解するのに役立ちます。とにかく、集中的に使うには十分と思われる稼働中のシステムはすでに存在します。ただし、何が起こっていて、何が4つのローソク足パターンを発生させているのかを理解すれば、このシステムから多くのものを得ることができます。もしかしたら、これがあなたのメイン指標になるかもしれません......。
結論
EAで使用するために、テープリーディングを分析するTimes & Tradeシステムを作成しました。MetaTrader 5が備えている代替システムと同等の分析速度が提供されます。これは、大量の数値と値を読み取って理解しようとするかわりにチャートシステムを作成することで達成されました。次回は、システムに不足している情報を実装していきます。EAコードにいくつかの新しい要素を追加する必要があります。
MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/10410
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索