English
preview
MQL5入門(第25回):チャートオブジェクトで取引するEAの構築(II)

MQL5入門(第25回):チャートオブジェクトで取引するEAの構築(II)

MetaTrader 5トレーディングシステム |
10 1
Israel Pelumi Abioye
Israel Pelumi Abioye

はじめに

連載「MQL5入門」の第25回へようこそ。前回の記事では、チャートオブジェクトを活用した手動のチャート分析と自動売買の実行を組み合わせることで、裁量取引と自動取引の間にあるギャップを埋める手法を紹介しました。具体的には、矩形ツールを用いて描画したサポートゾーンおよびレジスタンスゾーンを題材に解説しました。

本記事はそのコンセプトを発展させた内容で、今回はトレンドラインを使用します。トレンドラインは、テクニカル分析において最も広く利用されている手法の一つであり、市場の方向性を把握するだけでなく、ブレイクアウトや反転が発生する可能性のあるポイントを見極めるのに有効です。本記事では、チャート上に描画されたトレンドラインオブジェクトをEAが自動的に認識し、価格がラインを上抜けまたは下抜けした際に、市場の状況に応じて取引を自動的に実行するEAを構築していきます。

 

EAの動作概要

ユーザーはチャート上に2本のトレンドラインを手動で描画し、EAがそれを利用します。下降トレンドラインは、高値から低値へ描き、上昇トレンドラインは、低値から高値へ描きます。 EAはラインの名前を使ってチャート上の対象オブジェクトを特定します。つまり、ユーザーはトレンドラインの正確な名前を入力設定に指定する必要があります。複数のトレンドラインが存在する場合でも、この方法でEAはどのオブジェクトを監視すべきかを明確に把握できます。

さらに、ユーザーはEAが監視する時間足、使用するロットサイズ、および取引スタイルを指定できます。EAの選択可能な取引モードには、価格の動きに応じて反転条件とブレイクアウト&リテスト条件の両方を処理する[REVERSAL AND BREAK-OUT]モード、価格がトレンドラインに触れて反転シグナルを示した場合に取引を開始する[REVERSAL]モード、そして価格がトレンドラインを突破してから取引を開始する[BREAK-OUT]モードが含まれます。

図1:EAの動作概要

取引管理において、EAは最新の確定足を基準に、SLおよびTPレベルを自動で設定します。

  • 買い取引の場合:SLは直近の確定足の安値に設定
  • 売り取引の場合:SLは直近の確定足の高値に設定
  • TP:エントリー価格とSLの距離の1:4に設定

図2:反転

図3:ブレイクアウトとリテスト



トレンドラインの識別

次のステップでは、EAがチャート上のトレンドラインをどのように認識するかを説明します。EAの動作原理を理解した上で、ここで重要になるのは、ユーザーが描画したトレンドラインのうち、上昇トレンドを示すものと下降トレンドを示すものを区別するシンプルな方法です。

この目的のために、トレンドラインの名前を利用します。ユーザーが入力設定に指定した名前をEAが参照することで、チャート上の対象オブジェクトを正確に特定します。 名前を照合することで、EAは各トレンドラインの位置をリアルタイムで追跡し、他の線や図形がチャート上に存在しても、ユーザーが指定した特定のトレンドラインに対してのみ反応するようになっています。

input string down_trend = ""; // Down Trend Line
input string up_trend = ""; // Up Trend Line

ulong chart_id = ChartID();
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   ObjectSetInteger(chart_id,down_trend,OBJPROP_RAY_RIGHT,true);
   ObjectSetInteger(chart_id,up_trend,OBJPROP_RAY_RIGHT,true);

  }

説明

チャート上のトレンドラインを認識して操作するには、EAはまずそれらを理解している必要があります。そのため、ユーザーが2本のトレンドラインの名前を入力できるように入力設定を設計しています。1本は下降トレンドを示すために、もう1本は上昇トレンドを示すために使用されます。たとえチャート上に他の多数の線や記号が存在していても、この名前指定方式により、EAはどのオブジェクトが自分の対象であるかを正確に特定できます。

図4:オブジェクト名

EAが操作するチャート自体も、事前に把握しておく必要があります。MetaTrader 5の各チャートにはチャートIDという固有の識別番号が付与されており、EAはこのIDを取得することで、対象のチャートとその要素にのみ操作をおこなうことを保証します。

チャートの右側までトレンドラインを延長することも、この設定の重要な要素です。この延長により、トレンドラインはアンカーポイントを超えて将来の価格領域まで伸びることが可能になります。新しいローソク足が形成された後でも、EAがトレンドラインとの価格の相互作用を認識できるようにするため、この処理は欠かせません。この延長をおこなわない場合、トレンドラインはアンカーポイントで止まってしまい、EAは今後のブレイクアウトや反転を検知できなくなります。市場が変化する中でも、アンカーポイントを超えて線を延長することで、シグナルの認識と継続的な監視の信頼性を確保できます。

図5:アンカー価格


ローソク足および下降トレンドラインオブジェクトのデータ取得

価格がトレンドライン周辺でどのように動いているかをEAが判断するための次のステップはローソク足とトレンドラインのデータを取得することです。EAはまず、チャート上の直近5本のローソク足データをコピーします。この直近のローソク足だけでも、ブレイクアウトや反転が発生する可能性を確認することができます。

ローソク足データを取得した後、EAは同じ5本分の範囲内でトレンドラインのデータも収集します。この際、アンカーポイントではなく、直近ローソク足に対応するトレンドラインの価格のみを参照します。これにより、EAは同じ時間足の現在のローソク足の動きと、トレンドラインの正確な価格レベルを比較できるようになります。

EAは、トレンドラインと直近5本のローソク足の価格との相関を調べることで、価格がトレンドラインを上抜けまたは下抜け、または反転したタイミングを特定できます。この手法により、EAは最新かつ関連性の高い市場の動きにのみ反応し、検出精度を向上させることができます。

比喩的な説明

EAを市場の監視役、まるで現場を調査する探偵のような存在と考えてください。ローソク足は、特定の瞬間の価格の動きを示す写真のようなもので、一方、トレンドラインは重要な境界を示す縄のようなものです。

EAは各ローソク足を個別に分析し、特に直近5本に注目します。それぞれのローソク足の性質と、その時点でのトレンドラインの正確な位置を調べます。この手順は、ローソク足の動きが写った写真と、同じ期間のトレンドラインの位置を写した写真を並べて比較するような作業に似ています。

EAはこのデータを取得した後に分析を開始します。ローソク足の高値や安値はトレンドラインに接触していたか、ローソク足がトレンドラインを越えたときは上か下か、陽線か陰線か、などの問いを立てます。

トレーダーがチャートを目視で確認して、価格がラインに接触したり突破したタイミングを判断するのと同様に、EAはこれら2つの情報を並べて比較することで、ローソク足がトレンドラインとどのように相互作用したかを理解することができます。

input string down_trend = ""; // Down Trend Line
input string up_trend = ""; // Up Trend Line
input ENUM_TIMEFRAMES time_frame = PERIOD_CURRENT; // TIME FRAME

ulong chart_id = ChartID();

double close_price[];
double open_price[];
double low_price[];
double high_price[];
datetime time_price[];

double td_line_value;
double td1_line_value;
double td2_line_value;
double td3_line_value;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArraySetAsSeries(close_price, true);
   ArraySetAsSeries(open_price, true);
   ArraySetAsSeries(low_price, true);
   ArraySetAsSeries(high_price, true);
   ArraySetAsSeries(time_price, true);

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   ObjectSetInteger(chart_id,down_trend,OBJPROP_RAY_RIGHT,true);
   ObjectSetInteger(chart_id,up_trend,OBJPROP_RAY_RIGHT,true);

   CopyOpen(_Symbol, time_frame, 1, 5, open_price);
   CopyClose(_Symbol, time_frame, 1, 5, close_price);
   CopyLow(_Symbol, time_frame, 1, 5, low_price);
   CopyHigh(_Symbol, time_frame, 1, 5, high_price);
   CopyTime(_Symbol, time_frame, 1, 5, time_price);

//DOWN TREND

   td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0);
   td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0);
   td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0);
   td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0);

  }

説明

プログラムはまず、処理対象となる時間範囲を設定し、ローソク足情報を格納するための空のコンテナを準備します。この段階で、各ローソク足の始値、終値、高値、安値に加え、ローソク足がチャート上に出現した正確な時刻を、後ほどこれらのコンテナに保存できるようにします。分析を開始する前にこの設定をおこなうことで、プログラムは市場から包括的かつ整然とした価格データを取得できることを保証します。

double td_line_value;
double td1_line_value;
double td2_line_value;
double td3_line_value;

この段階では、特定の時点でのトレンドラインの位置を示す数値データを格納するためのストレージ領域を設定します。これらの数値は、チャート上の下降トレンドラインと市場価格の動きを比較するためにプログラムに使用されます。 コンテナは最新の情報が先頭に来るように整理されます。その結果、プログラムは直近のローソク足に即座にアクセスできるため、古いデータを順番に確認する手間を省き、最近の市場動向を効率的に分析できます。さらに、市場の値を格納する前に、すべてのコンテナが正しく整理されていることが保証されます。

プログラムは次に、直近5本のローソク足の情報を収集します。各ローソク足の価格およびチャート上に表示された時刻を取得し、この短いローソク足の系列を用いて、トレンドライン周辺で価格がどのように動いているかを監視し、ブレイクアウトや反転パターンが発生しているかを判断します。

td_line_value  = ObjectGetValueByTime(chart_id, down_trend, time_price[0], 0);
td1_line_value = ObjectGetValueByTime(chart_id, down_trend, time_price[1], 0);
td2_line_value = ObjectGetValueByTime(chart_id, down_trend, time_price[2], 0);
td3_line_value = ObjectGetValueByTime(chart_id, down_trend, time_price[3], 0);

それぞれの行は、指定したローソク足の時刻におけるトレンドラインの価格値を取得します。関数の最初のパラメータでどのチャートを調べるか(およびオブジェクト名、ここでは下降トレンドライン)を指定し、次のパラメータで正確な時刻(各ローソク足の形成時刻)とチャートウィンドウ(0はメインの価格チャート)を指定します。

簡単に言えば、この関数は各ローソク足が出現した瞬間にトレンドラインがどこにあったかを確認します。EAはローソク足の高値、安値、終値をこのラインの位置と比較できるため、ローソク足がトレンドラインに接触したか、またはラインを越えたかを判断できます。これにより、ブレイクアウトや反転の状況を特定することが可能になります。

 

下降トレンドの反転の識別

次のステップは、下降トレンドの反転を検出することです。これは売りの取引機会を示すサインとなります。この場合、EAは下降トレンドラインと直近ローソク足の相互作用を監視します。価格がラインに接近または接触した際に、ローソク足がラインの下で終値を付けた場合、潜在的な反転のサインと判断します。この動きは、売り手が市場の支配権を取り戻しつつあることを示す可能性があるため、売り取引の候補として認識されます。

しかし、過剰な取引やシグナルの重複は避ける必要があります。EAはこの判定をおこなう前に、直近の数本のローソク足内で取引シグナルが発生していないかを確認します。これにより、プログラムは新しいセットアップにのみ反応し、短時間で重複または不要な取引を開くことを防ぎます。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   ObjectSetInteger(chart_id,down_trend,OBJPROP_RAY_RIGHT,true);
   ObjectSetInteger(chart_id,up_trend,OBJPROP_RAY_RIGHT,true);

   CopyOpen(_Symbol, time_frame, 1, 5, open_price);
   CopyClose(_Symbol, time_frame, 1, 5, close_price);
   CopyLow(_Symbol, time_frame, 1, 5, low_price);
   CopyHigh(_Symbol, time_frame, 1, 5, high_price);
   CopyTime(_Symbol, time_frame, 1, 5, time_price);

//DOWN TREND

   td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0);
   td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0);
   td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0);
   td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0);

   bool prev_touch_down = false;

   if((high_price[1] > td1_line_value && close_price[1] < open_price[1])
      ||
      (high_price[2] > td2_line_value && close_price[2] < open_price[2])
     )
     {
      prev_touch_down = true;
     }
   int no_bars_down = 0;
   for(int i = 0; i <= 3; i++)
     {
      if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0))
        {
         for(int j = i; j >= 0; j--)
           {
            if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0))
              {
               no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent());

               break;
              }
           }
         break;
        }
     }
  }

説明

bool prev_touch_down = false;

if((high_price[1] > td1_line_value && close_price[1] < open_price[1])
   ||
   (high_price[2] > td2_line_value && close_price[2] < open_price[2])
  )
  {
   prev_touch_down = true;
  }

最初の行で変数がfalseに初期化されます。この変数は、直近のローソク足が下降トレンドラインへの有効な接触に続いて、売り方向の反応を示したかどうかを示すマーカーとして機能します。初期時点ではその条件は発生していないため、フラグはfalseのままです。概念としては、システムがトレンドラインに対する弱気の反応を確認した後、この変数をtrueに更新します。これにより、短時間での複数または重複する売りシグナルを避けるなど、今後の取引判断に活用できます。

if文の条件は、直近2本のローソク足が反転条件を満たすかどうかを確認します。条件の最初の部分(high_price[1] > td1_line_value && close_price[1] < open_price[1])は、直前の確定足を参照します。このローソク足の高値がトレンドラインを越えていたかを確認することで、価格がラインに接触またはわずかに突破したことを判定します。さらに、終値が始値より低いことを確認することで、陰線であることを確認します。この過程では、トレンドラインを試すために買い手が一時的に価格を押し上げたものの、売り手が市場の主導権を取り戻し、上ヒゲを残して下落させたことが示されます。

直前の拒否を記録するために、条件の第2部分では2本前のローソク足を確認します。直近2本のうちいずれかが拒否の基準を満たせば、有効な反応として認定されます。

波括弧{}内のコードは、条件がtrueと評価された場合にフラグの値をtrueに変更します。この時点で、市場はすでに下降トレンドラインに対してネガティブな反応を示したことになります。このフラグは後続のプログラムで過剰取引を防ぐための安全装置として利用でき、同じ付近での接触が繰り返し発生しても、追加の売りシグナルが生成されないようにします。

まとめると、このコードブロックは有効な下降トレンド反転シグナルの特定に役立ちます。ローソク足が下からトレンドラインに接近し、接触したうえで下落して終値を付けた場合、その行動は確認されたものと見なされます。プログラムはこの動きを特定してフラグを立てることで、より規律ある取引実行の基盤を築きます。こうすることで、価格の動きが明確にトレンドラインを突破した場合にのみ弱気の反転が確認され、不要な重複シグナルは回避されます。

int no_bars_down = 0;

for(int i = 0; i <= 3; i++)
  {
   if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0))
     {
      for(int j = i; j >= 0; j--)
        {
         if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0))
           {
            no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent());

            break;
           }
        }
      break;
     }
  }

「int no_bars_down = 0;」は、コードの冒頭でカウンタをゼロに初期化するために使用されます。このカウンタは、直近の有効な下落トレンドラインへの接触および反発から経過したローソク足の本数を記録します。 ループでは、直近の4本のローソク足を確認し、各ローソク足の始値がトレンドラインの下にあり、かつ高値がラインを越えているかを調べます。これにより、下からトレンドラインに接触したローソク足を特定しやすくなり、潜在的な反転の最初のサインを把握できます。

そのようなローソク足を検出した後、プログラムはさらに過去にさかのぼり、トレンドラインの下で閉じて陰線となった最初のローソク足を特定します。この段階は、市場がトレンドラインを拒絶したことを確認することで、売りの可能性があるシグナルを検証する役割を果たします。 プログラムは、この確認されたローソク足から現在までに経過したローソク足の本数を算出します。このカウントは、同じ場所での重複したシグナルや過剰な売買を防ぐのに役立ちます。EAは、直近の有効な反発シグナル以降で十分な値動きがあった場合にのみ新しい売買機会を考慮するように管理しており、これにより過剰取引を大幅に減らすことができます。

 

エントリー条件の追加

売りのエントリー条件を追加するのが次の段階です。EAは、下降トレンドの反転が確認され、かつ直近で同様のシグナルが発生していないことを検証した上で、どのような条件でポジションを作成するかを明確に定めることができます。正当なセットアップのみが取引を開始するようにするためには、トレンドラインへの接触、陰線による確認、そして直近シグナルから経過したローソク足の本数を組み合わせる必要があります。EAはこれらのエントリールールを確立することで、市場への参入を体系的におこない、過剰取引を防ぎながら、各取引がチャート上の反転パターンに沿ったものであることを保証できます。

#include <Trade/Trade.mqh>
CTrade trade;

int MagicNumber = 53217;
datetime lastTradeBarTime = 0;
double ask_price;
double take_profit;
//+------------------------------------------------------------------+
//| Expert initialization function                                    |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArraySetAsSeries(close_price, true);
   ArraySetAsSeries(open_price, true);
   ArraySetAsSeries(low_price, true);
   ArraySetAsSeries(high_price, true);
   ArraySetAsSeries(time_price, true);

   trade.SetExpertMagicNumber(MagicNumber);

//---
   return(INIT_SUCCEEDED);
  }
ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
datetime currentBarTime = iTime(_Symbol, time_frame, 0);

if(((high_price[1] >= td1_line_value && open_price[1] < td1_line_value) || (high_price[2] >= td2_line_value && open_price[2] < td2_line_value)
    || (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) || (high_price[0] >= td_line_value))
   && (close_price[0] < td_line_value && close_price[0] < open_price[0] && open_price[1] < td1_line_value)
   && (no_bars_down < 3)
   && prev_touch_down == false
   && (currentBarTime != lastTradeBarTime)
  )
  {
   take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4));

   trade.Sell(lot_size,_Symbol,ask_price, high_price[0], take_profit);
   lastTradeBarTime = currentBarTime;
  }

説明

MQL5の標準取引ライブラリは、最初の行「#include <Trade/Trade.mqh> 」で読み込まれます。このライブラリにより、取引の実行、注文の変更、ポジション管理に必要な関数やクラスがEAで利用可能になります。EAは「CTrade trade;」により生成された取引オブジェクトのインスタンスを用いて、体系的かつ安全に注文を発行します。

「int MagicNumber = 53217;」はマジックナンバーを定義します。これは、EAが建てるすべてのポジションに関連付けられる特別な番号です。「SetExpertMagicNumber(MagicNumber)」を使うことで、EAは手動取引や他のEAによる取引と自分の取引を区別できます。これにより、他の取引に影響を与えずに、ポジションの管理や変更、決済をおこなうことが可能になります。

「input double lot_size = 0.6;」は取引数量を設定するために使われます。これにより、ユーザーは入力設定から直接各取引のサイズを変更できます。「datetime currentBarTime = iTime(_Symbol, time_frame, 0);」は最新ローソク足の時刻を保持し、「ask_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);」は現在の市場のAsk価格を取得します。これらの値は、エントリー価格の設定、TP算出、同じローソク足での複数取引を防ぐために使用されます。

(high_price[1] >= td1_line_value && open_price[1] < td1_line_value) 
|| (high_price[2] >= td2_line_value && open_price[2] < td2_line_value) 
|| (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) 
|| (high_price[0] >= td_line_value)

この行は、直近のローソク足のいずれかが下降トレンドラインに接触した、あるいはわずかに越えたかどうかを判定します。(たとえば「high_price[1] >= td1_line_value && open_price[1] < td1_line_value」は、一つ前のローソク足の高値がトレンドラインを上回っている一方で、始値は下回っていることを確認します。)これは価格がトレンドラインに接近したことと、そこから生じる可能性のある反転状況を示しています。同様の判定は、2本前、3本前、そして現在のローソク足にも適用されます。論理演算子ORを使うことで、これらのローソク足のいずれかが条件を満たす場合に判定が通ることを保証します。

次に、確定的な下降圧力を確認する条件を、現在と直前のローソク足を調べることで追加しました。これは、売り勢力が強まり、上昇の勢いが弱まっていることを確認するもので、直近のローソク足がトレンドラインの下で終値を付けることを要求します。さらに、そのローソク足が始値よりも低く終わることで、下降圧力が確認されます。価格構造を安定させ、反転シグナルの精度を高めるために、直前のローソク足もトレンドラインの下で始値を付けている必要があります。

これにより、直近のローソク足によって下降反転が確認されます。ローソク足がトレンドラインを下回って終値を付けたことを確認します。これはモメンタムの低下と、売り手が主導権を握り始めたことを示しています。さらに、そのローソク足が始値よりも低く終わった場合に、下降圧力が確定したと判断されます。さらに、前のローソク足がトレンドラインの下で始値を付けていることで、下降の流れが一貫していることが示されます。これらの条件を組み合わせることで、一時的な価格の揺れによる不適切なエントリーを防ぎ、反転シグナルの信頼性を高めます。

現在のローソク足の時刻と、直前に実行した取引の時刻を比較することで、条件「currentBarTime != lastTradeBarTime」により、同じローソク足で複数の取引をおこなわないようにし、1本のローソク足につき1回のみエントリーが可能となります。すべてのエントリー条件が満たされた時点で、現在のAsk価格と条件確認に用いるローソク足の高値の絶対差を4倍してTPを算出し、リスクリワードレシオをプラスに設定します。

指定されたロットサイズ、通貨ペア、エントリー価格、条件確認に用いるローソク足の高値を基準にしたストップロス、算出した利食いを用いて、売り注文を出します。取引が成立した時点でlastTradeBarTimeを現在のローソク足の時刻に更新することで、同じローソク足での複数取引を防ぎます。

その後、EAはブレイクアウト+リテストで取引するか、単純な反転取引をおこなうかを判断する必要があります。ここまでで説明したのは下降トレンドの反転のみですが、先ほど確認した条件をもとに、EAがどのように有効な反転シグナルを判定するかが理解できます。反転ロジックが完成すれば、同じ考え方を応用して、ブレイクアウト+リテストの手法にも対応可能です。

input string down_trend = ""; // Down Trend Line
input string up_trend = ""; // Up Trend Line
input ENUM_TIMEFRAMES time_frame = PERIOD_CURRENT; // TIME FRAME
input double lot_size = 0.6; // LOT SIZE

enum line_type
  {
   reversal = 0, //REVERSAL
   break_out = 1, //BREAK-OUT
   reverse_break = 2 // REVERSAL AND BREAK-OUT
  };
input line_type line_exe =  reversal; // MODE
if(((high_price[1] >= td1_line_value && open_price[1] < td1_line_value) || (high_price[2] >= td2_line_value && open_price[2] < td2_line_value)
    || (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) || (high_price[0] >= td_line_value))
   && (close_price[0] < td_line_value && close_price[0] < open_price[0] && open_price[1] < td1_line_value)
   && (no_bars_down < 3)
   && prev_touch_down == false
   && (currentBarTime != lastTradeBarTime)
   && (line_exe == reversal || line_exe == reverse_break)
  )
  {
   take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4));

   trade.Sell(lot_size,_Symbol,ask_price, high_price[0], take_profit);
   lastTradeBarTime = currentBarTime;
  }

出力

図6:下降トレンドの反転


下降トレンドのブレイクアウトとリテストの識別

EAはまず、ローソク足が下降トレンドラインを上抜けして終値を付けるのを監視します。これは、以前のレジスタンスが破られたことを示しており、買いを狙ったブレイクアウト&リテストのセットアップを実行する準備となります。しかし、EAはすぐに取引を開始するわけではありません。価格がブレイクしたトレンドラインに再接触し、反発するリテストを待ちます。この動きによって、以前のレジスタンスがサポートとして機能していることが確認できます。

リテストの確認後、EAはその接触に続く強気のローソク足を探します。この強気の確認がエントリーポイントを示し、買い勢力が支配していることを表します。EAは、ブレイクアウト、リテストでの接触、そして確認の強気ローソク足の3つの条件がすべて満たされた場合に買い注文を実行します。価格の動きによってブレイクアウトが確認されてから取引をおこなうことで、早すぎるエントリーを防ぎ、偽のブレイクアウトの可能性を低減することができます。

td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0);
td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0);
td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0);
td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0);

bool prev_touch_down = false;

if((high_price[1] > td1_line_value && close_price[1] < open_price[1])
   ||
   (high_price[2] > td2_line_value && close_price[2] < open_price[2])
  )
  {
   prev_touch_down = true;
  }
int no_bars_down = 0;
for(int i = 0; i <= 3; i++)
  {
   if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0))
     {
      for(int j = i; j >= 0; j--)
        {
         if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0))
           {
            no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent());
            break;
           }
        }
      break;
     }
  }

//DOWN TREND

td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0);
td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0);
td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0);
td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0);

bool prev_touch_down = false;

if((high_price[1] > td1_line_value && close_price[1] < open_price[1])
   ||
   (high_price[2] > td2_line_value && close_price[2] < open_price[2])
  )
  {
   prev_touch_down = true;
  }
int no_bars_down = 0;
for(int i = 0; i <= 3; i++)
  {
   if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0))
     {
      for(int j = i; j >= 0; j--)
        {
         if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0))
           {
            no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent());

            break;
           }
        }
      break;
     }

ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
datetime currentBarTime = iTime(_Symbol, time_frame, 0);

if(((high_price[1] >= td1_line_value && open_price[1] < td1_line_value) || (high_price[2] >= td2_line_value && open_price[2] < td2_line_value)
    || (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) || (high_price[0] >= td_line_value))
   && (close_price[0] < td_line_value && close_price[0] < open_price[0] && open_price[1] < td1_line_value)
   && (no_bars_down < 3)
   && prev_touch_down == false
   && (currentBarTime != lastTradeBarTime)
   && (line_exe == reversal || line_exe == reverse_break)
  )
  {
   take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4));

   trade.Sell(lot_size,_Symbol,ask_price, high_price[0], take_profit);
   lastTradeBarTime = currentBarTime;

  }

// DOWNTREND BREAKOUT AMD RETEST
bool prev_touch_break_out_down = false;

if((low_price[1] < td1_line_value && close_price[1] > open_price[1]) ||
   (low_price[2] < td2_line_value && close_price[2] > open_price[2] && open_price[2] > td2_line_value))
  {
   prev_touch_break_out_down = true;
  }

int no_bars_down_breakout = 0;

for(int i = 0; i <= 3; i++)
  {

   if(low_price[i] < ObjectGetValueByTime(chart_id, down_trend, time_price[i], 0) &&
      open_price[i] > ObjectGetValueByTime(chart_id, down_trend, time_price[i], 0))
     {

      for(int j = i; j >= 0; j--)
        {
         if(close_price[j] > open_price[j] &&
            close_price[j] > ObjectGetValueByTime(chart_id, down_trend, time_price[j], 0))
           {

            no_bars_down_breakout = Bars(_Symbol, time_frame, time_price[j], TimeCurrent());
            break;
           }
        }
      break;
     }
  }
 
if(
   ((low_price[0] < td_line_value && open_price[0] > td_line_value) ||
    (low_price[1] < td1_line_value && open_price[1] > td1_line_value) ||
    (low_price[2] < td2_line_value && open_price[2] > td2_line_value) ||
    (low_price[3] < td3_line_value && open_price[3] > td3_line_value)) &&
   (close_price[0] > open_price[0]) && close_price[0] > td_line_value &&
   (no_bars_down_breakout < 3) &&
   (prev_touch_break_out_down == false) &&
   (currentBarTime != lastTradeBarTime)
   && (line_exe == break_out || line_exe == reverse_break)
)
  {
   take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4));

   trade.Buy(lot_size, _Symbol, ask_price, low_price[0], take_profit);

   lastTradeBarTime = currentBarTime;
  }

説明

コードの最初の部分で、ブール型のフラグが定義されており、直近で下降トレンドに対するブレイクアウト&リテストの動作が既に発生したかどうかを監視します。このフラグを使用することで、EAは同じセットアップが重複して追加の取引を発生させるのを防ぎます。次に、直近のローソク足を確認することで、ブレイクアウトシナリオが既に開始されているかどうかを判断します。 

さらに、ローソク足がトレンドラインの上で始値を付けているかどうかを確認し、価格がトレンドラインを突破してリテストしたことを確認します。EAが短期間に複数の取引を開くのを防ぐため、最後のブレイクアウトから経過したローソク足の本数を数えるカウンタがあり、ブレイクアウト接触が既に発生したことを示すフラグも設定されます。

その後、メインループ内で直近のローソク足を順に確認してブレイクアウトポイントを特定します。まず、始値がトレンドラインの上にあり、安値がその下にあるローソク足を探します。これは、トレンドラインが初めて突破されたことを示しており、ブレイクアウトの前兆となります。このローソク足が見つかった後、ネストされたループで過去にさかのぼり、トレンドラインの上で終値を付け、強気であるローソク足を探します。これにより、トレンドラインがレジスタンスからサポートに移行し、ブレイクアウトが有効であることが確認されます。確認が得られた時点で両方のループは停止され、不要な追加チェックを避けるとともに、カウンタはブレイクアウトから経過したローソク足の本数を反映するように調整されます。

このブレイクアウト&リテストのロジックは、反転とは大きく異なります。反転の場合、EAは下降トレンドラインに下から接触するローソク足を探して拒否を示します。一方で、ブレイクアウト&リテスト戦略では、EAはローソク足が下降トレンドラインを上抜けするのを待ち、その後リテストと強気のローソク足でトレンドの確認をおこないます。ブレイクアウトのセットアップは、市場方向の変化が確認された後に勢いを活かすことを目的としており、価格の拒否を狙う反転とは注目点が異なります。

if(
   ((low_price[0] < td_line_value && open_price[0] > td_line_value) ||
    (low_price[1] < td1_line_value && open_price[1] > td1_line_value) ||
    (low_price[2] < td2_line_value && open_price[2] > td2_line_value) ||
    (low_price[3] < td3_line_value && open_price[3] > td3_line_value)) &&
   (close_price[0] > open_price[0]) && close_price[0] > td_line_value &&
   (no_bars_down_breakout < 3) &&
   (prev_touch_break_out_down == false) &&
   (currentBarTime != lastTradeBarTime)
   && (line_exe == break_out || line_exe == reverse_break)
)
  {
   take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4));

   trade.Buy(lot_size, _Symbol, ask_price, low_price[0], take_profit);

   lastTradeBarTime = currentBarTime;
  }

条件の最初の部分では、下降トレンドラインがブレイクアウトされたかどうかを判定します。直近のローソク足を確認し、始値がトレンドラインの上にあり、かつ安値がトレンドラインの下に落ちたローソク足があるかを調べます。これは、ローソク足が上からトレンドラインを突破したことを示しており、潜在的なブレイクアウトの可能性を示唆します。この仕組みにより、EAは現在のローソク足に加えて直近3本のローソク足も確認することで、ブレイクアウト接触の遅延確認をおこなうことができます。

次に、条件「close_price[0] > open_price[0]」が適用されます。これは現在のローソク足が強気であり、「&& close_price[0] > td_line_value」の場合にトレンドラインの上で終値を付けたことを確認します。これにより、買い手が優勢であり、トレンドラインが実質的にレジスタンスからサポートに変化したことがブレイクアウトの確認となります。

前回確認されたセットアップから経過したローソク足の本数を追跡することで、EAは前回のブレイクアウトに近すぎる位置で取引をおこなわないようにします。これにより、新しい機会に集中でき、過剰取引を避けることが可能です。また、直近でブレイクアウト接触が記録されていないことを確認することで、同じ価格変動による重複取引も防ぎます。さらに、同じローソク足内で取引がすでにおこなわれていないことも確認し、1本のローソク足につき1回だけ取引を実行できるようにします。

次に、EAがブレイクアウト取引を許可するモードになっているか(単独で、または反転と組み合わせて)を確認します。すべての取引条件が満たされたら、EAは有利なリスクリワード比を用いて、現在の価格とブレイクアウト条件確認に用いるローソク足の安値との差からTPを計算します。その後、指定されたロットサイズで買い注文を出し、計算されたTPを設定し、SLはブレイクアウト条件確認に用いるローソク足の安値に設定します。さらに、同じローソク足内で重複エントリーが発生しないよう、取引時刻を記録します。

出力

図7:ブレイクアウトとリテスト


上昇トレンドの反転の識別

下降トレンドラインでのブレイクアウト&リテストや反転セットアップの認識方法を理解した後は、上昇トレンドラインでの反転の可能性を探る段階に進みます。上昇トレンドの場合のロジックは、基本的に下降トレンドの逆になります。ここでは、トレンドラインがレジスタンスではなくサポートを示しています。直近のローソク足の安値が上昇トレンドラインに接触または接近し、かつそのローソク足が始値よりも高い終値を付けた場合、これは正当な反転シグナルと見なされます。これは、価格がサポートをテストし、買い手が勢いを増し始めていることを示すため、潜在的な買いの機会を示唆します。

同じサポートテストによる複数の取引を避けるため、EAは直近でシグナルが生成されていないことを確認します。これは下降トレンドの反転と同様の処理です。また、現在のローソク足の時刻を直近取引の時刻と比較することで、1本のローソク足につき1回だけ取引が実行されることを保証します。このように、下降トレンド反転のロジックを上昇トレンドに適用することで、EAは一貫してリスク管理をおこないながら、過剰取引を避けつつ上昇トレンドの反転を体系的に認識することができます。

double t_line_value;
double t1_line_value;
double t2_line_value;
double t3_line_value;
// UP TREND
t_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[0],0);
t1_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[1],0);
t2_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[2],0);
t3_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[3],0);

int no_bars_up = 0;

for(int i = 0; i <= 3; i++)
  {

   if(low_price[i] < ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0) &&
      open_price[i] > ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0))
     {

      for(int j = i; j >= 0; j--)
        {

         if(close_price[j] > open_price[j] &&
            close_price[j] > ObjectGetValueByTime(chart_id, up_trend, time_price[j], 0))
           {

            no_bars_up = Bars(_Symbol, time_frame, time_price[j], TimeCurrent());

            break;
           }
        }
      break;
     }
  }

bool prev_touch_up = false;

if((low_price[1] < t1_line_value && close_price[1] > open_price[1]) ||
   (low_price[2] < t2_line_value && close_price[2] > open_price[2]))
  {

   prev_touch_up = true;  // Flag that a recent touch already occurred

  }
 
if(
   ((low_price[0] < t_line_value && open_price[0] > t_line_value) ||
    (low_price[1] < t1_line_value && open_price[1] > t1_line_value) ||
    (low_price[2] < t2_line_value && open_price[2] > t2_line_value) ||
    (low_price[3] < t3_line_value && open_price[3] > t3_line_value))
   &&
   (close_price[0] > open_price[0]) && close_price[0] > t_line_value
   &&
   (no_bars_up < 3)
   &&
   prev_touch_up == false
   &&
   (currentBarTime != lastTradeBarTime)
   &&
   (line_exe == reversal || line_exe == reverse_break)
)
  {
   take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4));

   trade.Buy(lot_size, _Symbol, ask_price, low_price[0],take_profit);
   lastTradeBarTime = currentBarTime; 
 
  }

説明

上昇トレンドラインの値は、直近のローソク足の時点で最初に初期化された変数に格納されます。それぞれの変数が異なるローソク足に対応しているため、EAはさまざまなタイミングで価格の動きをトレンドラインと比較することが可能です。これにより、EAは直近の4本のローソク足を監視でき、価格とトレンドラインの相互作用を特定する上で重要な役割を果たします。

次のステップでは、直近のローソク足に対する正確なトレンドラインの値を取得します。EAは、各ローソク足の時点でトレンドラインの価格を取得することで、ローソク足の安値がトレンドラインに触れたか、あるいは突破したかを正確に判断できます。これは上昇トレンドの反転を確認するための初期条件となります。

続いて、直近で確認された反転セットアップからの経過ローソク足数を、初期化されたカウンタで追跡します。サポートテストを示唆するローソク足を特定する際、EAは直近のローソク足を順に確認し、安値がトレンドラインを下回り、始値が上回っているローソク足を探します。買い手が介入していることを確認するため、さらに内部ループでその後のローソク足が陽線でトレンドラインの上で終値を付けているかを確認します。連続した重複シグナルを避けるため、確認後にカウンタを更新して経過ローソク足数を反映させます。

次に、トレンドラインが最近触れられたかどうかを示すブール型のフラグを設定します。EAは直近の複数のローソク足を確認し、安値がトレンドラインを下回った後に陽線となったローソク足があるかを判断します。こうしたローソク足が存在する場合、同じ価格の動きで複数の取引が発生しないように、フラグはtrueに設定されます。

最後に、買い注文を実行する前に、EAはいくつかの条件を確認します。現在のローソク足が陽線でトレンドラインの上で終値を付けていること、直近でのトレンドライン接触による取引がまだおこなわれていないこと、同じローソク足で既に取引がおこなわれていないこと、実行モードが反転取引を許可していること、そして直近のローソク足のいずれかがトレンドラインに接触または突破していることを確認します。

これらの条件がすべて満たされた場合、EAはエントリ価格と条件確認に用いるローソク足の安値の差に倍率を掛けて正のリスクリワードレシオを設定し、TPを決定します。その後、TPを適用し、買い注文を実行し、同じローソク足で複数取引が発生しないようにlastTradeBarTimeを更新し、SLを反転ローソク足の安値に設定します。


上昇トレンドのブレイクアウトとリテストの識別

上昇トレンドにおける反転の理解に続いて、次に検討するのが、上昇トレンドラインに対するブレイクアウトおよびリテストの可能性の識別です。この場合、ローソク足がトレンドラインを下回って終値を付けることで、サポートが突破されたことが示され、ブレイクアウトが確認されます。このブレイクアウトが発生した後、EAはすぐに取引をおこなうのではなく、リテストを待ちます。リテストとは、その後のローソク足の高値が再びトレンドラインに戻って接触する動きを指します。この挙動は、かつてサポートとして機能していたトレンドラインが、現在はレジスタンスとして作用していることを示しています。

// UP TREND
t_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[0],0);
t1_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[1],0);
t2_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[2],0);
t3_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[3],0);

int no_bars_up = 0;

for(int i = 0; i <= 3; i++)
  {

   if(low_price[i] < ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0) &&
      open_price[i] > ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0))
     {

      for(int j = i; j >= 0; j--)
        {

         if(close_price[j] > open_price[j] &&
            close_price[j] > ObjectGetValueByTime(chart_id, up_trend, time_price[j], 0))
           {

            no_bars_up = Bars(_Symbol, time_frame, time_price[j], TimeCurrent());

            break;
           }
        }
      break;
     }
  }

bool prev_touch_up = false;

if((low_price[1] < t1_line_value && close_price[1] > open_price[1]) ||
   (low_price[2] < t2_line_value && close_price[2] > open_price[2]))
  {

   prev_touch_up = true;  // Flag that a recent touch already occurred

  }

if(
   ((low_price[0] < t_line_value && open_price[0] > t_line_value) ||
    (low_price[1] < t1_line_value && open_price[1] > t1_line_value) ||
    (low_price[2] < t2_line_value && open_price[2] > t2_line_value) ||
    (low_price[3] < t3_line_value && open_price[3] > t3_line_value))
   &&
   (close_price[0] > open_price[0]) && close_price[0] > t_line_value
   &&
   (no_bars_up < 3)
   &&
   prev_touch_up == false
   &&
   (currentBarTime != lastTradeBarTime)
   &&
   (line_exe == reversal || line_exe == reverse_break)
)
  {
   take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4));

   trade.Buy(lot_size, _Symbol, ask_price, low_price[0],take_profit);
   lastTradeBarTime = currentBarTime; // Update last trade bar time to avoid duplicate signals
  }

// UPTREND BREAKOUT AMD RETEST

bool prev_touch_break_out_up = false;

if((high_price[1] > td1_line_value && close_price[1] < open_price[1])
   ||
   (high_price[2] > td2_line_value && close_price[2] < open_price[2])
  )
  {

   prev_touch_break_out_up = true;

  }

int no_bars_up_break_out = 0;

for(int i = 0; i <= 3; i++)
  {

   if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0)
     )
     {

      for(int j = i; j >= 0; j--)
        {

         if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0))
           {

            no_bars_up_break_out = Bars(_Symbol,time_frame,time_price[j],TimeCurrent());

            break;

           }

        }
      break;

     }

  }

if(((high_price[1] >= t1_line_value && open_price[1] < t1_line_value) || (high_price[2] >= t2_line_value && open_price[2] < t2_line_value)
    || (high_price[3] >= t3_line_value && open_price[3] < t3_line_value) || (high_price[0] >= t_line_value))
   && (close_price[0] < t_line_value && close_price[0] < open_price[0] && open_price[1] < t1_line_value)
   && (no_bars_up_break_out < 3)
   && (no_bars_up_break_out == false)
   && (currentBarTime != lastTradeBarTime)
   && (line_exe == break_out || line_exe == reverse_break)
  )
  {

   take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4));
   trade.Sell(lot_size,_Symbol,ask_price,high_price[0], take_profit);
   lastTradeBarTime = currentBarTime;

  }

説明

最初の処理では、直近でブレイクアウト後の接触がすでに発生しているかどうかを判定するために、ブール型のフラグを設定します。ローソク足が陰線となった場合、EAは直前のローソク足を確認し、それらの高値がトレンドラインに下側から接触していたかどうかを調べます。このような接触が検出された場合、同一のブレイクアウト事象から複数のシグナルが発生するのを防ぐため、フラグはtrueに設定されます。これにより、同じ価格の挙動によってEAが再度取引を実行してしまうことを防止します。

次にEAは、最後に有効と判断されたブレイクアウトから何本のローソク足が経過したかを算出します。直近のローソク足を順に調べ、始値がトレンドラインの下にあり、高値がトレンドラインを上抜けているものを探します。この中にネストされたループでは、その後に続くローソク足の中から、トレンドラインの下で終値を付けた陰線を検出します。この条件が確認されると、そのローソク足から現在のローソク足までに経過した本数を数えます。この本数は、直前のブレイクアウトに近すぎるタイミングで取引がおこなわれないようにするために使用され、過剰な取引を防ぎ、エントリ頻度を適切に管理する役割を果たします。。

複数のチェックを組み合わせて、売り注文を出すための主要な基準を提供します。リテストを検証するには、まず、最新のローソク足の1つがトレンドラインに触れたか、それを上回ったことを確認します。次に、現在のローソク足がトレンドラインの下で終値を付けた陰線であることを確認し、売り手の勢いが強まっていることを示します。さらに、現在のローソク足の時刻と直近の取引時刻を比較することで、同一ローソク足内で複数の取引がおこなわれないようにします。また、前回のブレイクアウトから十分な本数のローソク足があること、直近のブレイクアウトでの接触によってすでに取引が実行されていないこと、そしてEAの動作モードがブレイクアウト取引を許可していることも確認されます。

これらすべての条件が満たされた場合、EAは現在のAsk価格と確認用ローソク足の高値との差を基に、良好なリスクリワードレシオとなるよう係数を掛けてTPを算出します。その後、算出したTPを設定し、SLをブレイクアウト条件確認に用いるローソク足の高値に置いた上で、指定されたロットサイズで売り注文を実行します。最後に、同一ローソク足での重複取引を防ぐため、直近取引のローソク足時刻を更新します。この一連のロジックにより、EAは上昇トレンドにおけるブレイクアウトおよびリテストの機会を、重複や早すぎるエントリーを避けながら、安定して捉えることができます。

 

結論

前回のチャートオブジェクトに関する学習を踏まえ、本記事では矩形ではなくトレンドラインに焦点を当てました。チャート上に描画されたトレンドラインに対して、価格が反転する場面やブレイクする場面をEAが識別し、それを基に自動で取引を実行する方法を解説しました。この手法は、手動によるトレンドライン分析と自動売買を組み合わせることで、広く用いられているテクニカル分析ツールを、MQL5環境において実用的な売買シグナルへと昇華させるものです。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/19968

添付されたファイル |
最後のコメント | ディスカッションに移動 (1)
Stanislav Korotky
Stanislav Korotky | 22 10月 2025 において 16:20
この種のより柔軟で強力なソリューションは、記事TradeObjectsで 紹介されています:MetaTrader グラフィカルオブジェクトに基づく取引の自動化
機械学習の限界を克服する(第6回):効果的なメモリクロスバリデーション 機械学習の限界を克服する(第6回):効果的なメモリクロスバリデーション
本記事では、時系列クロスバリデーションにおける従来のアプローチと、その前提に疑問を投げかける新しい考え方を比較します。特に、市場環境が時間とともに変化するという点を十分に扱えていないという、古典的手法の弱点に焦点を当てます。これらの問題を踏まえ、Effective Memory Cross-Validation (EMCV)という、ドメインを意識した検証手法を紹介します。このアプローチは、「過去データは多ければ多いほど良い」という長年の常識を見直すものです。
ダイナミックスイングアーキテクチャ:スイングから自動売買までの市場構造認識 ダイナミックスイングアーキテクチャ:スイングから自動売買までの市場構造認識
本記事では、市場のスイングを高精度で捉え、自動売買を実現する完全自動化MQL5システムを紹介します。従来の固定ローソク足数に基づくスイングインジケーターとは異なり、このシステムは進行中の市場構造に動的に適応し、スイングハイおよびスイングローをリアルタイムで検出します。これにより、形成されつつあるトレンドの値動きを的確に捉え、取引機会を逃さず捕捉することが可能です。
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
知っておくべきMQL5ウィザードのテクニック(第85回):ストキャスティクスとFrAMAのパターンを用いたβ-VAEによる推論 知っておくべきMQL5ウィザードのテクニック(第85回):ストキャスティクスとFrAMAのパターンを用いたβ-VAEによる推論
本記事は、ストキャスティクスとフラクタル適応型移動平均の組み合わせを紹介した「第84回」の続きです。今回は推論フェーズでの学習結果の活用に焦点を移し、前回の記事で取り上げた低調なパターンの成績を改善できるかどうかを検討します。ストキャスティクスとFrAMAは、モメンタムとトレンドを補完する関係にあります。推論フェーズでの学習結果の活用では、以前に考察したβ変分オートエンコーダ(β-VAE)のアルゴリズムを再度利用します。また、いつものように、MQL5ウィザードとの統合を目的として設計されたカスタムシグナルクラスの実装も継続します。