
一からの取引エキスパートアドバイザーの開発(第14部):価格別出来高の追加((II)
はじめに
私たちのEAには既に、以前の記事で追加した、取引を支援するためのリソースがいくつかあります。ただし、このEAには視覚化とサイズ変更に関するいくつかの問題があります。取引を妨げるようなものではありませんが、強制的に更新するまで画面が混乱することがあります。さらに、私たちにとって貴重な情報を提供してくれるものがいくつか欠けています。これらは特定のものですが、情報が必要になる場合があります。
これらの新しい改善の実装を始めましょう。この興味深い記事では、情報を提示するためのいくつかの新しいアイデアと方法を提供します。同時に、プロジェクトの小さな欠陥の修正にも役立ちます。
価格別出来高の新機能の計画と実装
1.計画
取引には興味深いことがあります。特定の価格帯で市場が蓄積し、買い側または売り側のいずれかでストップがトリガーされると、価格が急速に動くことがよくあります。この動きはTimes & Tradeで見ることができます。これについては、以前の「Times & Trade (I)」および「Times & Trade (II)」稿で検討しました。これらの記事では、実行された注文の注文フローを読み取って分析するための代替のグラフィカルシステムを作成する方法について説明しました。よく見ると、ある時点で価格が蓄積領域に戻る傾向があり、その時点で離れないことに気付くでしょう。ただし、価格別出来高指標を見ると、この特定の地域でいつ価格が変わっていなかったのかを判断するのは困難です。この指標は「価格別出来高の追加(I)」稿で実装されました。それを使用すると、分析の開始点を変更するだけで比較的最近の動きを分析できます。これは、下図に示されているオブジェクトの値を調整することによっておこなわれます。
ただし、これは実際には非現実的です。メインの時間枠に縛られているためです。つまり、60分の時間枠のチャートがある場合、この時間枠を下回る価格の動きを調整することはできません。分析点を調整できるようにするには、より短い時間枠に切り替える必要があります。しかし、先物契約を取引する場合、ほとんどのトレーダーは実際には 5分、10分、30分などのより短い時間枠を使用するため、分析開始点の調整に問題はありません。ただし、前に説明したように、ストップがトリガーされたために価格の累積が終了することがあり、そのようなリターンは通常5分以内に発生します。このような場合、上または下に長い髭のあるローソク足がチャートに表示されます。プライスアクションは、何が起こったのかがマーケットサウンディングであったことを示しています。このタイプの動きは、下の矢印で示されたローソク足で見ることができます。
典型的な買い手のテストの動き、またはショートストップ トリガー
典型的な売り手のテストの動き、または買い手側のストップトリガー
この種の動きは頻繁に発生し、各価格帯で生成されたボリュームを分析することは、市場がテスト中であるかトレンドが本当に反転しているかを理解できるため、非常に重要です。ただし、以前に提案されたボリューム指標を使用して、これを適切に、またはむしろ迅速におこなうことは不可能です。
指標オブジェクトクラスに小さな変更を加えて、何が起こっているのかをより明確にすることはできます。これは、指定された期間におこなわれた取引のトレースとして表示されます。
2.実装
最初におこなうことは、60分、45分、30分、19分、7分、1分のうちどの追跡時間を設定するかを分析することです。これに関係なく、追跡システムが本当に役立つように、十分な倍数の値を使用することをお勧めします。実用的な理由から、30分間の追跡を使用して実装するため、次のコード行で定義します。
#define def_MaxTrailMinutes 30
しかし、なぜ正確に30分なのでしょうか。実際には1分ごとに追跡システムが実行されますが、最大追跡時間は30分になります。つまり、常に30分の追跡がおこなわれます。たとえば、追跡が31分に切り替わると、取引の最初の1分は表示されなくなります。それはどのように実装されているのでしょうか。これは、以下に示すキャプチャ システムを使用します。
inline void SetMatrix(MqlTick &tick) { int pos; if ((tick.last == 0) || ((tick.flags & (TICK_FLAG_BUY | TICK_FLAG_SELL)) == (TICK_FLAG_BUY | TICK_FLAG_SELL))) return; pos = (int) ((tick.last - m_Infos.FirstPrice) / Terminal.GetPointPerTick()) * 2; pos = (pos >= 0 ? pos : (pos * -1) - 1); if ((tick.flags & TICK_FLAG_BUY) == TICK_FLAG_BUY) m_InfoAllVaP[pos].nVolBuy += tick.volume; else if ((tick.flags & TICK_FLAG_SELL) == TICK_FLAG_SELL) m_InfoAllVaP[pos].nVolSell += tick.volume; m_InfoAllVaP[pos].nVolDif = (long)(m_InfoAllVaP[pos].nVolBuy - m_InfoAllVaP[pos].nVolSell); m_InfoAllVaP[pos].nVolTotal = m_InfoAllVaP[pos].nVolBuy + m_InfoAllVaP[pos].nVolSell; m_Infos.MaxVolume = (m_Infos.MaxVolume > m_InfoAllVaP[pos].nVolTotal ? m_Infos.MaxVolume : m_InfoAllVaP[pos].nVolTotal); m_Infos.CountInfos = (m_Infos.CountInfos == 0 ? 1 : (m_Infos.CountInfos > pos ? m_Infos.CountInfos : pos)); m_Infos.Momentum = macroGetMin(tick.time); m_Infos.Momentum = (m_Infos.Momentum > (def_MaxTrailMinutes - 1) ? m_Infos.Momentum - def_MaxTrailMinutes : m_Infos.Momentum); if (m_Infos.memMomentum != m_Infos.Momentum) { for (int c0 = 0; c0 <= m_Infos.CountInfos; c0++) m_TrailG30[m_Infos.Momentum].nVolume[c0] = 0; m_Infos.memMomentum = m_Infos.Momentum; } m_TrailG30[m_Infos.Momentum].nVolume[pos] += tick.volume; }
ハイライト表示されている行は、オブジェクトクラスのソースコードに追加された行で、ボリュームトレースキャプチャを実装しています。以下の行で、追跡が期待どおりに実行されることを保証します。
m_Infos.Momentum = macroGetMin(tick.time);
m_Infos.Momentum = (m_Infos.Momentum > (def_MaxTrailMinutes - 1) ? m_Infos.Momentum - def_MaxTrailMinutes : m_Infos.Momentum);
トレースキャプチャ システムの準備が整ったので、新たな決断を下す必要があります。トレースは1分ごとにキャプチャされます。これは、1分以内に各価格帯で出来高を確認できるように表示できます。このようにチャートを作成している限り、以下に示したようなことをするのを検討してください。
より明るい色合いはより新しいボリュームを表します。これは良い考えかもしれません...
一見良いように見えますが、ボリュームが小さいときや動きが速いときは、これまでに見つかった最大ボリュームに合わせてプロットされるため、ひとまず表現できるボリュームでも実際には見えない場合があります。したがって、これを解決するために少し異なる方法でプロットすると、次のようになります。
各色は、ボリュームトレースの特定の期間を表します。
これは、ボリューム内の非常に狭い帯域を分析するのに役立ち、最初のケースで見られる時折の問題を修正します。しかし、別の時点で全体のボリュームに比べてボリュームが表現できない場合、調整の問題が発生する可能性があります。さらに、非常に活発な取引中に分析が混乱しないように、各期間の色を慎重に選択する必要があります。
したがって、ここでは、さまざまな期間の動きを分析するために調整できる、より単純なモデルを使用します。ただし、上記の問題に注意してください。これはあなた次第です。次に、トレースは次のように表示されます。
ここには純粋なトレースが見られます。起こった場合に何が起こっているのかを理解するために、Times & TradeとPrice Actionの両方を分析する必要があります。
とにかく、ボリューム表示を変更するために変更する必要がある唯一の関数は以下です。
void Redraw(void) { uint x, y, y1, p; double reason = (double) (m_Infos.MaxVolume > m_WidthMax ? (m_WidthMax / (m_Infos.MaxVolume * 1.0)) : 1.0); double desl = Terminal.GetPointPerTick() / 2.0; ulong uValue; Erase(); p = m_WidthMax - 8; for (int c0 = 0; c0 <= m_Infos.CountInfos; c0++) { if (m_InfoAllVaP[c0].nVolTotal == 0) continue; ChartTimePriceToXY(Terminal.Get_ID(), 0, 0, m_Infos.FirstPrice + (Terminal.GetPointPerTick() * (((c0 & 1) == 1 ? -(c0 + 1) : c0) / 2)) + desl, x, y); y1 = y + Terminal.GetHeightBar(); FillRectangle(p + 2, y, p + 8, y1, macroColorRGBA(m_InfoAllVaP[c0].nVolDif > 0 ? m_Infos.ColorBuy : m_Infos.ColorSell, m_Infos.Transparency)); FillRectangle((int)(p - (m_InfoAllVaP[c0].nVolTotal * reason)), y, p, y1, macroColorRGBA(m_Infos.ColorBars, m_Infos.Transparency)); uValue = 0; for (int c1 = 0; c1 < def_MaxTrailMinutes; c1++) uValue += m_TrailG30[c1].nVolume[c0]; FillRectangle((int) (p - (uValue * reason)), y, p, y1, macroColorRGBA(clrRoyalBlue, m_Infos.Transparency)); } C_Canvas::Update(); };
より正確には、変更する必要があるのは、ハイライト表示されたコードのみです。目的の結果が得られるまでいじってみてください。派以来後表示された部分を除いて、クラス内には変更する必要のあるものはありません。プログラムをコンパイルしてチャート上で実行すると、次のように表示されます。
レンダリングの問題を解決する
コードには特定の問題はありませんでしたが、チャートのサイズを変更するときに小さな欠陥があります。最大化されたチャートを他のサイズに変更してからまた最大化すると、一部のオブジェクトが失われ、期待どおりに動作せず、間違った場所に配置されます。修正することは多くはありません。問題は以下のコードにあります。以前の記事で使用しました。
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { Chart.DispatchMessage(id, lparam, dparam, sparam); VolumeAtPrice.DispatchMessage(id, sparam); switch (id) { case CHARTEVENT_CHART_CHANGE: Terminal.Resize(); WallPaper.Resize(); TimesAndTrade.Resize(); break; } ChartRedraw(); }
非常に簡単な修正がありますが、「何も見えない。コードは正しい」と思われるかもしれません。私も、一見したところ何も問題は見られず、コードには引き続き実行時エラーが発生していました。しかし、いくつかの機能を追加していたときに、まさに上で説明した問題に気付きました。この問題を解決するには、コードを次のように変更する必要があります。
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { switch (id) { case CHARTEVENT_CHART_CHANGE: Terminal.Resize(); WallPaper.Resize(); TimesAndTrade.Resize(); break; } Chart.DispatchMessage(id, lparam, dparam, sparam); VolumeAtPrice.DispatchMessage(id, sparam); ChartRedraw(); }
ばかげているように聞こえるかもしれませんが、その理由を理解するには、関数コード全体とハイライト表示された部分をご覧ください。システムが修正されたので、次の手順に進むことができます。
余分なリソースを追加する
これから追加する関数は非常にシンプルで、多くの人はそれを実装する理由をあまり理解していないかもしれませんが、実装すると、ポジショニング、移動、または単に出来高指標を監視するなど、注文を処理するときに非常に役立ちます。
最初におこなうことは、価格ライン調整コードが含まれるクラスを変更することです。このコードはC_OrderViewクラスから出てC_Terminalクラスに入りますが、クラス自体の変数を操作し始めるため、このコードにも小さな変更が加えられています。新しいコードは以下のようになります。
double AdjustPrice(const double arg) { double v0, v1; if(m_Infos.TypeSymbol == OTHER) return arg; v0 = (m_Infos.TypeSymbol == WDO ? round(arg * 10.0) : round(arg)); v1 = fmod(round(v0), 5.0); v0 -= ((v1 != 0) || (v1 != 5) ? v1 : 0); return (m_Infos.TypeSymbol == WDO ? v0 / 10.0 : v0); };
そうすることで、新しいEAクラス「C_Mouse」を作成できます。このクラスオブジェクトは、マウスイベントを担当してその基礎となるので、この開発段階でどのようになるかを見てみましょう。ただし、まず、下図に示されているエキスパートアドバイザー(EA)の現在のクラス構造を見てみましょう。
次のシステムを実装するには、新しい構造を導入する必要があります...
上記の構造を踏まえ、変数の宣言から始めてC_Mouseオブジェクトクラスのコードを分解してみましょう。
class C_Mouse { private : struct st00 { color cor01, cor02, cor03; string szNameObjH, szNameObjV, szNameObjT, szNameObjI, szNameObjB; }m_Infos; struct st01 { int X, Y; datetime dt; double price; uint ButtonsStatus; }Position;
開発のこの段階で必要なものはほとんどないので、注目に値する次のポイントに移りましょう。
~C_Mouse() { // ... Internal code ... ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_MOUSE_MOVE, false); ChartSetInteger(Terminal.Get_ID(), CHART_CROSSHAIR_TOOL, true); }
このコードは、クロスヘアCHART_CROSSHAIR_TOOLを復元し、チャートによるマウスイベントの使用を無効にします。つまり、プラットフォーム自体によって処理されるため、MT5はそのようなイベントをチャートに送信することを気にする必要がなくなります。
また、マウスを制御するときに使用される2つの非常に一般的な関数もあります。
inline void Show(void) { ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjH, OBJPROP_COLOR, m_Infos.cor01); } //+------------------------------------------------------------------+ inline void Hide(void) { ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjH, OBJPROP_COLOR, clrNONE); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjV, OBJPROP_COLOR, clrNONE); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjT, OBJPROP_COLOR, clrNONE); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjI, OBJPROP_COLOR, clrNONE); ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjB, 0, 0, 0); }
興味深いことに、マウスは実際には消えず、作成したオブジェクトだけが画面から消えます。マウスを「オン」にすると、価格ラインだけが実際に表示されます。これは奇妙に思えるかもしれませんが、EAのいくつかの特定のポイントで使用されます。そのようなポイントの1つは、以下のコードでハイライト表示されている部分のC_OrderViewクラスオブジェクトです。
inline void MoveTo(uint Key) { static double local = 0; int w = 0; datetime dt; bool bEClick, bKeyBuy, bKeySell; double take = 0, stop = 0, price; bEClick = (Key & 0x01) == 0x01; //Left click bKeyBuy = (Key & 0x04) == 0x04; //SHIFT pressed bKeySell = (Key & 0x08) == 0x08; //CTRL pressed Mouse.GetPositionDP(dt, price); if (bKeyBuy != bKeySell) Mouse.Hide(); else Mouse.Show(); ObjectMove(Terminal.Get_ID(), m_Infos.szHLinePrice, 0, 0, price = (bKeyBuy != bKeySell ? price : 0)); ObjectMove(Terminal.Get_ID(), m_Infos.szHLineTake, 0, 0, take = price + (m_Infos.TakeProfit * (bKeyBuy ? 1 : -1))); ObjectMove(Terminal.Get_ID(), m_Infos.szHLineStop, 0, 0, stop = price + (m_Infos.StopLoss * (bKeyBuy ? -1 : 1))); if((bEClick) && (bKeyBuy != bKeySell) && (local == 0)) CreateOrderPendent(bKeyBuy, m_Infos.Volume, local = price, take, stop, m_Infos.IsDayTrade); else local = 0; ObjectSetInteger(Terminal.Get_ID(), m_Infos.szHLinePrice, OBJPROP_COLOR, (bKeyBuy != bKeySell ? m_Infos.cPrice : clrNONE)); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szHLineTake, OBJPROP_COLOR, (take > 0 ? m_Infos.cTake : clrNONE)); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szHLineStop, OBJPROP_COLOR, (stop > 0 ? m_Infos.cStop : clrNONE)); };
ハイライト表示された部分の上の行に注意してください。
Mouse.GetPositionDP(dt, price);
この行では、マウス位置の値をキャプチャします。以下は、これらの値を報告するコードです。
inline void GetPositionDP(datetime &dt, double &price) { dt = Position.dt; price = Position.price; }
ただし、これですべてではありません。場合によっては、画面位置に対するチャートのデカルト座標が必要になります。関連する値を取得できる別の関数があります。以下に示します。
inline void GetPositionXY(int &X, int &Y) { X = Position.X; Y = Position.Y; }
C_OrderViewクラスに戻ると、注目に値する興味深い点があります。
void DispatchMessage(int id, long lparam, double dparam, string sparam) { ulong ticket; double price, pp, pt, ps; eHLineTrade hl; switch (id) { case CHARTEVENT_MOUSE_MOVE: MoveTo(Mouse.GetButtonStatus()); break; // ... The rest of the code ... }
MoveTo関数は、この関数の少し前に示されています。これはC_OrderViewクラスの一部でもありますが、もっと重要なのはMouse.GetButtonsStatus関数です。この関数は、マウスイベントに関連付けられたボタンとキーの状態を返します。
この関数Mouse.GetButtonStatusを以下に示します。
inline uint GetButtonStatus(void) const { return Position.ButtonsStatus; }
これは、最後のマウスイベント以降に記録された値を含む変数を返す1行です。この値を記録するコードに進みます。ただ、最初に、マウスの初期化コードを見てみましょう。これは、マウスを初期化したいこと、そしてこれからはEAがさまざまなマウス関連のものを処理することをEAに伝える必要があるためです。これを担当するコードを以下に示します。
// ... Other things .... input group "Mouse" input color user50 = clrBlack; //Price line input color user51 = clrDarkGreen; //Positive move input color user52 = clrMaroon; //Negative move //+------------------------------------------------------------------+ // ... General information ... //+------------------------------------------------------------------+ int OnInit() { static string memSzUser01 = ""; Terminal.Init(); WallPaper.Init(user10, user12, user11); Mouse.Init(user50, user51, user52); // ... The rest of the code ...
したがって、システムが使用する3つの色を定義する必要があります。これらの色は、チャート上でデータが明確に表示されるように選択する必要があります。もう少し理解するために、Mouse.Init のコードをご覧ください。以下で見ることができます。
void Init(color c1, color c2, color c3) { m_Infos.cor01 = c1; m_Infos.cor02 = c2; m_Infos.cor03 = c3; if (m_Infos.szNameObjH != NULL) return; ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_MOUSE_MOVE, true); ChartSetInteger(Terminal.Get_ID(), CHART_CROSSHAIR_TOOL, false); m_Infos.szNameObjH = "H" + (string)MathRand(); m_Infos.szNameObjV = "V" + (string)MathRand(); m_Infos.szNameObjT = "T" + (string)MathRand(); m_Infos.szNameObjB = "B" + (string)MathRand(); m_Infos.szNameObjI = "I" + (string)MathRand(); //--- ObjectCreate(Terminal.Get_ID(), m_Infos.szNameObjH, OBJ_HLINE, 0, 0, 0); ObjectCreate(Terminal.Get_ID(), m_Infos.szNameObjV, OBJ_VLINE, 0, 0, 0); ObjectCreate(Terminal.Get_ID(), m_Infos.szNameObjT, OBJ_TREND, 0, 0, 0); ObjectCreate(Terminal.Get_ID(), m_Infos.szNameObjB, OBJ_BITMAP, 0, 0, 0); ObjectCreate(Terminal.Get_ID(), m_Infos.szNameObjI, OBJ_TEXT, 0, 0, 0); //--- ObjectSetString(Terminal.Get_ID(), m_Infos.szNameObjH, OBJPROP_TOOLTIP, "\n"); ObjectSetString(Terminal.Get_ID(), m_Infos.szNameObjV, OBJPROP_TOOLTIP, "\n"); ObjectSetString(Terminal.Get_ID(), m_Infos.szNameObjT, OBJPROP_TOOLTIP, "\n"); ObjectSetString(Terminal.Get_ID(), m_Infos.szNameObjB, OBJPROP_TOOLTIP, "\n"); ObjectSetString(Terminal.Get_ID(), m_Infos.szNameObjI, OBJPROP_TOOLTIP, "\n"); //--- ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjT, OBJPROP_WIDTH, 2); //--- ObjectSetString(Terminal.Get_ID(), m_Infos.szNameObjB, OBJPROP_BMPFILE, "::" + def_Fillet); //--- ObjectSetString(Terminal.Get_ID(), m_Infos.szNameObjI, OBJPROP_FONT, "Lucida Console"); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjI, OBJPROP_FONTSIZE, 10); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjI, OBJPROP_BACK, false); Hide(); Show(); }
このコードに特別なことは何もありません。クラスで使用するオブジェクトをいくつか作成しているだけです。ただし、ハイライト表示された部分はやや紛らわしい可能性があります。クラス内で探しても宣言されている場所が見つからないからです。これは、他のリソースの宣言とともにEAファイルのコードで実際に宣言されているためです。後でこれらすべてをファイルにまとめますが、今のところはこのままにします。EAコードを見ると、次の行が見つかります。
#define def_Resource "Resources\\SubSupport.ex5" #define def_Fillet "Resources\\Fillet.bmp" //+------------------------------------------------------------------+ #resource def_Resource #resource def_Fillet
この行は、マウスの初期化コードでハイライト表示されたリソースを示しています。
さて、次のフラグメントによって呼び出されるこのクラス内でピークに達します。
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { Mouse.DispatchMessage(id, lparam, dparam, sparam); switch (id) { case CHARTEVENT_CHART_CHANGE: Terminal.Resize(); WallPaper.Resize(); TimesAndTrade.Resize(); break; } Chart.DispatchMessage(id, lparam, dparam, sparam); VolumeAtPrice.DispatchMessage(id, sparam); ChartRedraw(); }
次に、EAコードのハイライト表示された行が次のコードを呼び出します。
void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) { int w = 0; uint key; static int b1 = 0; static double memPrice = 0; switch (id) { case CHARTEVENT_MOUSE_MOVE: Position.X = (int)lparam; Position.Y = (int)dparam; ChartXYToTimePrice(Terminal.Get_ID(), Position.X, Position.Y, w, Position.dt, Position.price); ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjH, 0, 0, Position.price = Terminal.AdjustPrice(Position.price)); ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjV, 0, Position.dt, 0); key = (uint) sparam; if ((key & 0x10) == 0x10) { ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjV, OBJPROP_COLOR, m_Infos.cor01); b1 = 1; } if (((key & 0x01) == 0x01) && (b1 == 1)) { ChartSetInteger(Terminal.Get_ID(), CHART_MOUSE_SCROLL, false); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjT, OBJPROP_COLOR, m_Infos.cor01); ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjT, 0, Position.dt, memPrice = Position.price); b1 = 2; } if (((key & 0x01) == 0x01) && (b1 == 2)) { ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjT, 1, Position.dt, Position.price); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjT, OBJPROP_COLOR, (memPrice > Position.price ? m_Infos.cor03 : m_Infos.cor02)); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjI, OBJPROP_COLOR, (memPrice > Position.price ? m_Infos.cor03 : m_Infos.cor02)); ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjB, 0, Position.dt, Position.price); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjB, OBJPROP_ANCHOR, (memPrice > Position.price ? ANCHOR_RIGHT_UPPER : ANCHOR_RIGHT_LOWER)); ObjectSetString(Terminal.Get_ID(), m_Infos.szNameObjI, OBJPROP_TEXT, StringFormat("%.2f ", Position.price - memPrice)); ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjI, 0, Position.dt, Position.price); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjI, OBJPROP_ANCHOR, (memPrice > Position.price ? ANCHOR_RIGHT_UPPER : ANCHOR_RIGHT_LOWER)); } if (((key & 0x01) != 0x01) && (b1 == 2)) { b1 = 0; ChartSetInteger(Terminal.Get_ID(), CHART_MOUSE_SCROLL, true); Hide(); Show(); } Position.ButtonsStatus = (b1 == 0 ? key : 0); break; } }
上記のコードは埋め込み実装コードではありません。現在の開発段階までは、EAの主要なタスクのみをサポートおよび解決します。これを理解するには、マウスの初期化コードの1つの点に注意してください。次の行があります。
ChartSetInteger(Terminal.Get_ID(), CHART_CROSSHAIR_TOOL, false);
この行により、マウスの中ボタンをクリックしたときに十字線が表示されなくなります。しかし、なぜ十字線が作成されないようにするのでしょうか。これを理解するために、次のGIF を見てみましょう。
これはWDOチャートで、0.5から0.5に移動しますが、分析をおこなおうとすると、精度があまり高くないことがわかります。分析をおこなうにはある程度の精度が重要な場合もありますが、MetaTrader 5のクロスヘアツールは、特定のケースでは十分ではありません。この場合、新しいシステムに頼る必要があるため、EAの実行中にMetaTrader 5に十字線の作成を強制的に停止させます。代わりに、独自の十字線を作成して分析を実行します。これにより、より関連性の高いデータと値を追加し、最も適切と思われる方法でそれらを提示することができます。これは、EAを実行してデータモデリングシステムを使用した結果を示す下図で見ることができます。
ご覧のとおり、指定された値は正確な移動値に対応しています。さらに、視覚的な表示があります。表示は、値が正の場合は緑色になり、負の場合は赤色になります。トレースが作成され、開始点と終了点も表示されます。しかし、すでに述べたように、システムはまだ完全ではありません。必要に応じて改善を加えることができます。C_Mouseクラスの新しいバージョンが公開されるまで、このバージョンを改善して、必要なデータを増やすことができます。しかし、これをおこなうには、すべてがどのように機能するかを理解する必要があるため、C_Mouseクラスのメッセージコードを詳しく見てみましょう。
C_Mouse クラスの DispathMessage コードを理解する
コードは、マウス位置変数の値を取得して調整することから始めます。これは、以下のコードでおこなわれます。
Position.X = (int)lparam; Position.Y = (int)dparam; ChartXYToTimePrice(Terminal.Get_ID(), Position.X, Position.Y, w, Position.dt, Position.price);
ポジション値がMetaTrader 5プラットフォームによって報告されますが、値は実際にはオペレーティングシステムから取得され、画面座標(XとY)を持ちます。それらをチャート座標に変換する必要があるため、MQL5で利用可能なChartXYToTimePrice関数を使用します。
これが完了したら、価格とタイムラインを移動します。
ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjH, 0, 0, Position.price = Terminal.AdjustPrice(Position.price)); ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjV, 0, Position.dt, 0);
ただし、タイムラインは最初は目に見えないためチャートに表示されません。その後、マウスの状態をキャプチャします。
key = (uint) sparam;
ここまでは順調です。次に、中央のボタンが押された状態かどうかを確認します。押された状態である場合、タイムラインがチャートに表示されます。これは以下のコードで実装されています。
if ((key & 0x10) == 0x10) { ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjV, OBJPROP_COLOR, m_Infos.cor01); b1 = 1; }
この目的のために、static 変数を使用してこのイベントを保存するため、今後は他のイベントがEAによって受け入れられ、処理されることはなくなり、チャートで実行したい調査を処理するようになります。しかし実際には、調査はマウスの左ボタンを押したときにのみ開始されます。つまり、MetaTrader 5プラットフォームのすべてのユーザーが調査のために既に知っている同じ作業モードを使用します。これが最も適切な方法です。ユーザーが研究ラインの新しい方法を学ばなければならない場合、システムをあきらめる可能性があるからです。次に、EA はこの左クリックを待機します。これは次のコードによっておこなわれます。
if (((key & 0x01) == 0x01) && (b1 == 1)) { ChartSetInteger(Terminal.Get_ID(), CHART_MOUSE_SCROLL, false); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjT, OBJPROP_COLOR, m_Infos.cor01); ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjT, 0, Position.dt, memPrice = Position.price); b1 = 2; }
クリックが発生すると、チャート移動システムがロックされます。次に、分析ポイントを示すトレンドラインを提示します。システムは次の手順に切り替わります。これは、b1の新しい値から確認できます。これは実際に、より多くの情報を追加したり、最も関連性が高いと思われるものを配置したりできる部分です.ここではシステムのデモンストレーションをおこなっているだけですが、自由に好きなものを配置してください。これは、以下に示すようにおこなう必要があります。
if (((key & 0x01) == 0x01) && (b1 == 2)) { ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjT, 1, Position.dt, Position.price); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjT, OBJPROP_COLOR, (memPrice > Position.price ? m_Infos.cor03 : m_Infos.cor02)); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjI, OBJPROP_COLOR, (memPrice > Position.price ? m_Infos.cor03 : m_Infos.cor02)); ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjB, 0, Position.dt, Position.price); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjB, OBJPROP_ANCHOR, (memPrice > Position.price ? ANCHOR_RIGHT_UPPER : ANCHOR_RIGHT_LOWER)); ObjectSetString(Terminal.Get_ID(), m_Infos.szNameObjI, OBJPROP_TEXT, StringFormat("%.2f ", Position.price - memPrice)); ObjectMove(Terminal.Get_ID(), m_Infos.szNameObjI, 0, Position.dt, Position.price); ObjectSetInteger(Terminal.Get_ID(), m_Infos.szNameObjI, OBJPROP_ANCHOR, (memPrice > Position.price ? ANCHOR_RIGHT_UPPER : ANCHOR_RIGHT_LOWER)); }
ハイライト表示された線にご注目ください。チャート画面に表示される値が表示され、計算される場所です。そこにさらに有用な情報を追加できます。この部分の操作により、左ボタンが押されている間、データが計算されて表示されます。これは MetaTrader 5のデフォルトと同じ動作ですが、値は希望とニーズに従って調整およびモデル化できます。
ここで、以下に示すもう1つのテストをおこなう必要があります。
if (((key & 0x01) != 0x01) && (b1 == 2)) { b1 = 0; ChartSetInteger(Terminal.Get_ID(), CHART_MOUSE_SCROLL, true); Hide(); Show(); }
マウスの左ボタンを離すと、チャートが解放されてドラッグできるようになります。分析の作成に使用されたすべての要素が非表示になり、価格線のみが再び表示されます。最後に、以下に示す最後のコード部分があります。
Position.ButtonsStatus = (b1 == 0 ? key : 0);
調査が呼び出されない場合、マウスボタンのステータスが保存され、EAの他の場所で使用できますが、調査が呼び出された場合、ステータスデータとしてNULL値が使用されるため、注文を作成することやポジションを変更することはできません。
下のビデオでは、このトレースが実際にどのように機能し、画面のボリュームをどのように調整するかを確認できます。この指標は非常に役立ちます。正しく使用する方法を学べば素晴らしいでしょう。Times & Tradeと共にダブルノイズ分析ツールが形成されます。これは、市場で最も高度な取引方法の1つです。
MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/10419





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索