English Deutsch
preview
MQL5で自己最適化エキスパートアドバイザーを構築する(第2回):USDJPYスキャルピング戦略

MQL5で自己最適化エキスパートアドバイザーを構築する(第2回):USDJPYスキャルピング戦略

MetaTrader 5 | 15 4月 2025, 07:34
162 0
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana

MQL5での自己最適化エキスパートアドバイザー(EA)の構築に関する前回の議論では、取引アプリケーションのエントリーおよびエグジットシグナルを作成するために線形回帰モデルを構築しました。前回の記事へのリンクは、こちらにあります。振り返ってみると、機械学習モデルで利用可能なすべての可動部分が必要ではないかもしれません。むしろ、機械学習モデルは、動的なルールを使って現実世界の問題を解決する方法の一例として捉えることができます。その後、同じ単純な思考と論理の原則を使って、維持が大変な巨大なコードベースを作成することなく、取引アプリケーションの収益性をさらに高めることができるかもしれません。

この記事では、日足でUSDJPYペアを取引して利益を上げることを目指します。取引戦略はローソク足パターンに基づいています。特に、抱き線によって作成された反転パターンを取引します。強気の抱き線のルールは、始値が前日の終値よりも低く、終値が前日の始値よりも高い場合に満たされます。下の図1に例を示します。これらのローソク足パターンは、特定の価格レベルがかなりの強さで拒否されたことを示していると考えられています。

図1:特定された強気ローソク足パターンの例

トレーダーは、抱き線パターンが市場に新たなトレンドが形成されつつある兆候であると考えます。これらが正しく識別された場合、通常は新しいトレンドの方向に沿った一貫した価格の動きが続きます。下の図2を参照してください。これにより、取引パターンを正しく識別しようとする取引戦略の基礎が作られます。弱気の抱き線は下降トレンドの始まりを識別するために使用できます。同じルールを先ほど説明したのと逆の方法で適用します。

図2:この特定の例では、ローソク足パターンは信頼できるものであった

通常、これらの戦略はすべての時間足において有効だと考えられています。しかし、私は日足が最も信頼性が高いと考えており、この演習では日足を選択しました。これらの特定の市場パターンを理解することで生成されたエントリーシグナルを取引するための戦略を実装してみましょう。また、当初の戦略に調整を加えることで、収益性を高めることができるかどうかも注目したいと思います。



MQL5入門

私たちのプログラムには、ローソク足パターンで利益を上げて取引するという目標を達成するために必要な6つの主要な部分があります。

部分
用途
初期化
システムのこの部分は、グローバル変数の読み込みと設定を担当します。

初期化解除

アプリケーションが使用しなくなったリソースを解放し、安定したエンドユーザーエクスペリエンスを確保します。
OnTick
システム変数を更新し、現在のチャートをスキャンしてローソク足パターンを探します。
カスタム関数
目標を達成するために必要な専門的な業務を遂行します。
システム定数
エンドユーザーによる変更を意図していない定数
グローバル変数
最後に発注した注文の種類、現在提示されている市場価格、およびボラティリティレベルを追跡します。このために、「trade」や「bid」などの変数が作成されました。ATRは、ポジションのストップロスとテイクプロフィットを設定するのに役立ちます。

当初、私たちの戦略では、ローソク足パターンが見つかった場合にのみ取引をおこないます。パターンが特定され、ポジションがない場合は、シグナルを取得し、ATRを使用してストップロスを設定および調整します。それ以外の場合は、私たちが開始した取引はすべて私たちのシステムによって管理されます。したがって、システムのグローバル変数は次のようになります。

変数
詳細
trade
現在空いているポジションの種類を知らせることで、今後考えられるストップやその他のタスクの更新が容易になります。
atr_handler
ストップロスを一貫して更新するために重要
bid、ask
市場価格を追跡します

まず、取引戦略のベンチマークバージョンを構築します。まず、システム定数を定義することから始めましょう。これらの定数は、#defineディレクティブを使用して作成されます。#defineディレクティブは、MQL5エディターに組み込まれたプリプロセッサに、指定したマクロ識別子の出現箇所を置き換え、その代わりにマクロ識別子の右側に割り当てたものを配置するように指示します。

最初に定義したシステム定数は「SYMBOL」です。アプリケーションをコンパイルすると、プリプロセッサはコード内のすべての「SYMBOL」のインスタンスを値「USDJPY」に置き換えます。このシンプルな機能により、システムを完全に予測可能な方法で制御できるようになり、テスト全体で一貫性が保証されます。これらは私たちにとって魅力的な属性です。

//+------------------------------------------------------------------+
//|                                      Dynamic Stops Benchmark.mq5 |
//|                                        Gamuchirai Zororo Ndawana |
//|                          https://www.mql5.com/ja/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Zororo Ndawana"
#property link      "https://www.mql5.com/ja/gamuchiraindawa"
#property version   "1.00"
//+------------------------------------------------------------------+
//| This trading application is intended to serve as our benchmark.  |
//| Our goal is to learn what it will take to surpass the benchmark. |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| System constants                                                 |
//+------------------------------------------------------------------+
#define SYMBOL          "USDJPY"    //--- System pair
#define DAILY           PERIOD_D1   //--- Daily  time frame
#define VOL             0.1         //--- Trading volume
#define ATR_PERIOD      14          //--- Technical Indicator ATR Period
#define ATR_MULTIPLE    2           //--- Stop loss ATR multiple

取引ライブラリもロードする必要があります。

//+------------------------------------------------------------------+
//| Libraries                                                        |
//+------------------------------------------------------------------+
#include <Trade/Trade.mqh>
CTrade Trade;

ここで、グローバル変数を定義します。これらの変数は、ポジションと現在の市場相場を追跡するのに役立ちます。

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
int    trade = 0;
int    atr_handler;
double atr[];
double bid,ask;

初期化時に、システム変数の初期化を担当する特殊な関数を呼び出します。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   setup();
//---
   return(INIT_SUCCEEDED);
  }

私たちが取引アプリケーションを使用しなくなった場合は、使用しなくなったテクニカル指標を解放します。

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Release the indicator
   release();
  }

1日の終わりにシステム変数を一度更新します。リスク管理を改善するために、これを好みに合わせて変更することができます。バックテストがタイムリーに完了し、行った変更を比較しやすくなるように、システム変数を1日に1回だけ更新することを選択しています。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   update();
  }
//+------------------------------------------------------------------+

最初に構築するカスタム関数は、消費しなくなったシステムリソースを解放する役割を担います。

//+------------------------------------------------------------------+
//| Custom Functions                                                 |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Release variables we don't need                                  |
//+------------------------------------------------------------------+
void release(void)
  {
   IndicatorRelease(atr_handler);
  }

システム変数を1日に1回更新します。

//+------------------------------------------------------------------+
//| Update system                                                    |
//+------------------------------------------------------------------+
void update(void)
  {
   static datetime daily_timestamp;
   datetime daily_time = iTime(SYMBOL,DAILY,0);
   if(daily_timestamp != daily_time)
     {
      //--- Update the time
      daily_timestamp = daily_time;
      //--- Update system variables
      daily_update();
      //--- Do we have an oppurtunity to trade?
      if((PositionsTotal() == 0))
         find_setup();
      //--- Do we have positions to manage?
      if(PositionsTotal() > 0)
         manage_setup();
     }
  }

ストップロスまたはテイクプロフィットの新しいポジションの方が収益性が高い場合にのみ、ストップロスとテイクプロフィットを更新して取引を管理します。

//+------------------------------------------------------------------+
//| Manage our trades                                                |
//+------------------------------------------------------------------+
void manage_setup(void)
  {
//--- Select the position
   if(PositionSelect(SYMBOL))
     {
      //--- Get ready to update the SL/TP
      double initial_sl  = PositionGetDouble(POSITION_SL);
      double initial_tp  = PositionGetDouble(POSITION_TP);
      double buy_sl      = (ask - (ATR_MULTIPLE * atr[0]));
      double sell_sl     = (bid + (ATR_MULTIPLE * atr[0]));
      double buy_tp      = (ask + (ATR_MULTIPLE * atr[0]));
      double sell_tp     = (bid - (ATR_MULTIPLE * atr[0]));
      double new_sl      = ((trade == 1) && (initial_sl <  buy_sl))? (buy_sl) : ((trade == -1) && (initial_sl > sell_sl)) ? (sell_sl) : (initial_sl);
      double new_tp      = ((trade == 1) && (initial_tp <  buy_tp))? (buy_tp) : ((trade == -1) && (initial_tp > sell_tp)) ? (sell_tp) : (initial_tp);
      //--- Update the position
      Trade.PositionModify(SYMBOL,new_sl,new_tp);
     }
  }

テクニカル指標を設定します。今のところ、管理すべきテクニカル指標は1つだけです。

//+------------------------------------------------------------------+
//| Get our technical indicators ready                               |
//+------------------------------------------------------------------+
void setup(void)
  {
   atr_handler         = iATR(SYMBOL,DAILY,ATR_PERIOD);
  }

システム状態を更新します。

//+------------------------------------------------------------------+
//| Daily update routine                                             |
//+------------------------------------------------------------------+
void daily_update(void)
  {
//--- Get current prices
   ask = SymbolInfoDouble(SYMBOL,SYMBOL_ASK);
   bid = SymbolInfoDouble(SYMBOL,SYMBOL_BID);
//--- Update Technical Indicators
   CopyBuffer(atr_handler,0,0,1,atr);
//--- Check for engulfing candles.
   int candles_state = check_candles();
//--- Give feedback
   Comment("Candle State: ",candles_state);
  }

ローソク足パターンを確認します。パターンが見つかった場合は、1または-1を返して、ロングまたはショート取引をおこないます。そうでなければ、待つことになります。

//+------------------------------------------------------------------+
//| Check if we have any engulfing candles                           |
//+------------------------------------------------------------------+
int check_candles(void)
  {
//--- Return 1 if we have a bullish engulfing candle
   if((iOpen(SYMBOL,DAILY,0) < iClose(SYMBOL,DAILY,1)) && (iClose(SYMBOL,DAILY,0) > iOpen(SYMBOL,DAILY,1)))
      return(1);

//--- Return -1 if we have a bearish engulfing candle
   if((iOpen(SYMBOL,DAILY,0) > iClose(SYMBOL,DAILY,1)) && (iClose(SYMBOL,DAILY,0) < iOpen(SYMBOL,DAILY,1)))
      return(-1);

//--- Otherwise return 0
   return(0);
  }

ローソク足の状態が0でない場合、システムは取引セットアップが見つかったことを認識します。それ以外の場合は、現時点ではこれ以上おこなう必要はありません。

//+------------------------------------------------------------------+
//| Find setup                                                       |
//+------------------------------------------------------------------+
void find_setup(void)
  {
//--- Our sentiment is bullish
   int candles_state = check_candles();
   if(candles_state == 1)
     {
      Trade.Buy(VOL,SYMBOL,ask,(ask - (ATR_MULTIPLE * atr[0])),(ask + (ATR_MULTIPLE * atr[0])),"");
      trade = 1;
     }

//--- Our sentiment is bearish
   if(candles_state == -1)
     {
      Trade.Sell(VOL,SYMBOL,bid,(bid + (ATR_MULTIPLE * atr[0])),(bid - (ATR_MULTIPLE * atr[0])),"");
      trade = -1;
     }
  }
//+------------------------------------------------------------------+

下の図3では、システムがどのようになっているかを確認できます。私たちのシステムは、ローソク足パターンの有無を追跡し、パターンが見つかった場合に取引をおこないます。現在の設定では、ストップロスとテイクプロフィットのポジションは1日の終わりに1回移動されます。

戦略の可視化

図3:USDJPYの日足での取引戦略の可視化

2020年1月1日から2024年11月末までの4年間の履歴データを使用して新しい戦略をテストします。こちらの手順に従って進めたが設定を変更したい場合は、システム変数にも適切な変更を加えるようにしてください。それ以外の場合、システムは指定した銘柄と時間枠に関係なく、日足でUSDJPYの取引を継続します。

システム設定

図4:バックテストの主な設定

ランダム遅延は実際の取引シナリオに最も近いため、システムのストレステストが可能になります。実際にこの戦略を使用することを検討している場合は、意図した取引設定に合わせて「Deposit」と口座レバレッジを必ず調整してください。

2番目の設定

図5:バックテストのモデリングタイプとアカウントサイズの選択

この戦略によって生み出されるエクイティカーブは有望です。私たちのスキャルピング戦略により、このバックテストで口座サイズが約4%増加しました。他の取引戦略と同様に、損失が続く期間が続きましたが、この戦略の非常に注目すべき点は、損失期間から回復する能力です。

システムの収益性

図6:取引口座残高を時間の経過とともに可視化する

それでは、戦略のパフォーマンスを詳しく見てみましょう。現在の形では、戦略のシャープ比は1.12、成功率は44.68%でした。平均利益への影響を最小限に抑えながら、平均損失を133.22ドルから0に近づけるには何が必要でしょうか。

バックテスト結果

図7:バックテストのパフォーマンスの詳細な分析



成果の向上

システムは現状では利益を上げています。損失を出している取引をよりコントロールできるようにするために、何か変更できる点はあるでしょうか。元の戦略にいくつか変更を提案します。

変更の提案
 意図した目的
追加確認
すでに利益が出ている戦略と並行して追加の確認戦略を使用することで、利益が出ない取引をさらに排除できる可能性があります。
ストップロスに余分なパディングを追加する
勝ち取引でストップが掛かる回数を最小限に抑えたいと考えています。
市場の変動を考慮する
各市場には潜在的に独自のボラティリティレベルがあります。取引戦略では、プロのトレーダーのように、過去のボラティリティレベルを考慮し、ある程度のコンテキストで現在の価格レベルを分析するように努める必要があります。

これらの変更を実施することで、利益のない取引の割合が減ることを期待しています。こうした決定をおこなう際には、常に取引オフが必要になります。結局のところ、新しい戦略では、古い戦略では簡単に管理できた利益の出る取引を逃してしまうことがあります。

平均損失の規模を制御できないと、最終的に、努力して蓄積した利益をすべて失う可能性があることは当然です。希望する変更を実現するには、アプリケーションの現在のバージョンに変更を導入する必要があります。

システム変更
詳細
新しいシステム変数
市場のボラティリティを考慮するには、まず過去からどれだけのデータを取得する必要があるかを決定する必要があります。これは、「fetch」という適切な名前の新しいシステム変数によって処理されます。さらに、使用するテクニカル指標のパラメータを修正する必要があります。
テクニカル指標
テクニカル指標取引戦略を使用することで、追加の確認を得ることができます。今日は、移動平均チャネル戦略を採用します。したがって、この新しい情報を保存するために、新しいインジケーターハンドラとバッファを作成します。
シグナルの合流
「sentiment」という名前の新しいグローバル変数を作成します。ローソク足パターンとテクニカル指標の両方が強気(/弱気)の場合、その値は1/(-1)になります。それ以外の場合、その値は0になります。私たちのシステムは、センチメント値が0でない場合にのみ取引をおこないます。
カスタム関数
システムに期待する動作を実現するには、すでに作成したカスタマイズされた関数の一部を拡張し、いくつかの新しい関数を作成する必要があります。


確認戦略の概要

私たちの確認戦略は、移動平均チャネル取引戦略に基づいています。この戦略は、それぞれ高値と安値に従う2つの移動平均によって作成されます。2つの移動平均線がチャネルを形成します。移動平均線は互いに交差しないことに注意してください。したがって、エントリーシグナルは、2つの移動平均線の間の領域外でローソク足が完全に形成されたときに生成されます。

この戦略の根拠は、高移動平均と低移動平均の間の価格レベルは安定していると考えられることです。一方、価格レベルが2つの移動平均線の間の領域を超えて形成されると、市場に不均衡が生じていると認識されます。この戦略は、不均衡の方向への新たなトレンドの形成を示唆しています。下の図8は、この戦略をどのように使用するかを示しています。

赤い矢印は、戦略に従ってショートポジションを占めるのに最適な領域を表しています。  価格レベルがチャネルに戻るまで、セットアップは通常有効であると見なされます。その時点で、ポジションはクローズされ、次の不均衡が検出されるまで待つことになります。この2番目の不均衡は青い矢印で示されています。不均衡は移動平均チャネルの上に現れたため、ロングのシグナルと解釈されたでしょう。

図8:エントリーポイントとエグジットポイントを特定するための移動平均チャネル戦略

市場で経験した過去の高値と安値も考慮して、この考えをさらに拡張します。過去1年間の市場における最高価格と最低価格の中間点を計算します。さらに、この情報を使用して、終値が過去の高値と安値の中間点を上回っている場合にのみロングポジションを配置するように制限または適用し、ショートポジションの場合はその逆になります。

図9の赤い水平線は、過去1年間の最高値と最安値の平均を表しています。この中間点は私たちのシステムによって毎日更新され、私たちのアプリケーションがその下の価格レベルを表示するためのレンズとして機能します。

中間点をマークする

図9:過去1年間の市場で提示された最高値と最安値の歴史的な中間点

ポジションタイプ
新しいポジション基準
ロング
移動平均チャネルの上に強気の抱き線が形成され、価格レベルは年間平均ボラティリティレベルを上回っています。
ショート
移動平均チャネルの上に、弱気の抱き線が形成され、価格レベルは年間平均のボラティリティレベルを上回っています。

うまくいけば、2つの戦略を組み合わせて使用することで、古いシステムを悩ませていた不採算の取引を除外しながら、保持したい収益性の高い取引を保持できるようになります。これらの変更を実装して、どれほど効果があるかを確認してみましょう。まず、移動平均チャネルの期間と、中間点を計算するために取得するデータ履歴データの量を固定する新しいシステム変数を定義する必要があります。

//+------------------------------------------------------------------+
//|                                  USDJPY Price Action Benchmark 2 |
//|                                        Gamuchirai Zororo Ndawana |
//|                          https://www.mql5.com/ja/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Zororo Ndawana"
#property link      "https://www.mql5.com/ja/gamuchiraindawa"
#property version   "1.00"
//+------------------------------------------------------------------+
//| This trading application is intended to surpass our benchmark.   |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| System constants                                                 |
//+------------------------------------------------------------------+
//--- I have intentionally omitted parts of the system that remained unchanged
#define FETCH           365            //--- How much should we fetch?
#define MA_PERIOD       90             //--- Moving average period

定義した市場の状態を追跡するには、いくつかの追加のグローバル変数も必要になります。

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
int    sentiment = 0;
int    trade = 0;
int    ma_high_handler, ma_low_handler;
double ma_high[],ma_low[];

アプリケーション本体は同じままです。ただし、呼び出される関数の一部は変更されています。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Setup our system varaibles
   setup();
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Release any resources 
   release();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Update system variables
   update();
  }
//+------------------------------------------------------------------+

次に、カスタム関数に加えられた変更を確認しましょう。最初の2つの変更は、テクニカル指標を読み込み、その後解放することです。

//+------------------------------------------------------------------+
//| Custom Functions                                                 |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Release our technical indicators                                 |
//+------------------------------------------------------------------+
void release(void)
  {
   IndicatorRelease(atr_handler);
   IndicatorRelease(ma_low_handler);
   IndicatorRelease(ma_high_handler);
  }

コードベースに対するこれらの変更は連携して行われ、簡単に理解できます。

//+------------------------------------------------------------------+
//| Get our technical indicators ready                               |
//+------------------------------------------------------------------+
void setup(void)
  {
   atr_handler         = iATR(SYMBOL,DAILY,ATR_PERIOD);
   ma_high_handler     = iMA(SYMBOL,DAILY,MA_PERIOD,0,MODE_EMA,PRICE_HIGH);
   ma_low_handler      = iMA(SYMBOL,DAILY,MA_PERIOD,0,MODE_EMA,PRICE_LOW);
  }

毎日の更新ルーチンも拡張する必要があります。現在、私たちは、現在の価格レベルが、この市場から予想される過去のノイズレベルとどのように比較されるかを知ることにも興味を持っています。ローソク足パターンと価格レベルが一致する感情を示している場合、今が取引を実行するのに良いタイミングであるかどうか、移動平均チャネルからの検証を求めます。

//+------------------------------------------------------------------+
//| Daily update routine                                             |
//+------------------------------------------------------------------+
void daily_update(void)
  {
//--- Get current prices
   ask = SymbolInfoDouble(SYMBOL,SYMBOL_ASK);
   bid = SymbolInfoDouble(SYMBOL,SYMBOL_BID);
//--- Update Technical Indicators
   CopyBuffer(atr_handler,0,0,1,atr);
   CopyBuffer(ma_high_handler,0,0,1,ma_high);
   CopyBuffer(ma_low_handler,0,0,1,ma_low);
//--- Check for engulfing candles.
   int candles_state = check_candles();
//--- Compare current price levels to historical price levels in the market
   int price_state  = check_price_levels();
//--- Check our tech
//--- What is our sentiment?
//--- Our sentiment is well defined.
   if(candles_state == price_state)
      sentiment = candles_state;
//--- Wait.
   if(candles_state != price_state)
      sentiment = 0;
//--- Give feedback
   Comment("Sentiment: ",sentiment,"\nCandle State: ",candles_state,"\nPrice State: ",price_state);
  }

MQL5ベクトル型を使用して、市場統計を即座に簡単に計算し、追跡します。

//+------------------------------------------------------------------+
//| Check if we are closer to the all time high or low               |
//+------------------------------------------------------------------+
int check_price_levels(void)
  {
//--- Get historical prices
   vector highs = vector::Zeros(FETCH);
   vector lows  = vector::Zeros(FETCH);
   highs.CopyRates(SYMBOL,DAILY,COPY_RATES_HIGH,0,FETCH);
   lows.CopyRates(SYMBOL,DAILY,COPY_RATES_LOW,0,FETCH);

//--- First we shall calculate the mid point between the all time high and low
   vector mid = ((highs + lows) / 2);

//--- Return 1 if we are above the mid point
   if(iClose(SYMBOL,DAILY,0) > mid.Mean())
      return(1);

//--- Return -1 if we are above the mid point
   if(iClose(SYMBOL,DAILY,0) < mid.Mean())
      return(-1);

//--- Otherwise return 0
   return(0);
  }

新しい取引セットアップのルールでは、2つの追加フィルターを考慮します。1つは年間の中間点に対する価格の位置、もう1つは移動平均チャネルに対する価格の位置です。両方の戦略が一致したら、それに従って取引をおこないます。
//+------------------------------------------------------------------+
//| Find setup                                                       |
//+------------------------------------------------------------------+
void find_setup(void)
  {
//--- Our sentiment is bullish
   if(sentiment == 1)
     {
      if((iOpen(SYMBOL,DAILY,0) > ma_high[0]) && (iClose(SYMBOL,DAILY,0) > ma_high[0]))
        {
         Trade.Buy(VOL,SYMBOL,ask,(ask - (ATR_MULTIPLE * atr[0])),(ask + (ATR_MULTIPLE * atr[0])),"");
         trade = 1;
        }
     }

//--- Our sentiment is bearish
   if(sentiment == -1)
     {
      if((iOpen(SYMBOL,DAILY,0) < ma_low[0]) && (iClose(SYMBOL,DAILY,0) < ma_low[0]))
        {
         Trade.Sell(VOL,SYMBOL,bid,(bid + (ATR_MULTIPLE * atr[0])),(bid - (ATR_MULTIPLE * atr[0])),"");
         trade = -1;
        }
     }
  }
//+------------------------------------------------------------------+

戦略が実際にどのように機能するかを見てみましょう。現在の戦略では、ポジションを取る前に満たすべき3つの条件を監視しています。これらの条件が偶然すべて満たされることがないよう、慎重に選定している点にご注目ください。

新しく改善された戦略

図10:過去の市場データに基づいて、改訂されたUSDJPYスキャルピング戦略をバックテストする

前述したように、バックテストの長さと期間に関する設定は、両方のテスト間で一貫性を保つために固定されます。したがって、日付は前回のテストの日付と一致します。

新しいUSDJPY戦略をテストする

図11:バックテストの設定は両方のテストで固定される

これらの特定の設定は、使用を想定している環境に合わせて自由に調整してください。

USDJPYスキャルピング戦略のための2番目の入力バッチ

図12:バックテストの2番目の設定

新しい戦略によって生成されたエクイティカーブは、最初のバックテストと比較してドローダウンの期間が少なくなっています。たとえば、2020年1月から2023年12月にかけて、当初の戦略によるエクイティカーブは初期残高の周辺で変動を繰り返し、ほとんど成長が見られませんでした。一方で、新しい戦略のエクイティカーブにはそのような望ましくない特徴は見られず、2022年9月からバックテスト終了時点にかけて、より穏やかで安定した成長を示しています。

改訂されたUSDJPY戦略によって生成された新しいエクイティカーブ

図13:改訂された取引戦略によって生み出されたエクイティカーブ

さらに詳しく調査した結果、平均損失および負け取引の割合を0に近づけるという目標は概ね達成できていることがわかりました。ただし、負け取引の割合は約55%から約54%へと、わずかにしか改善されていません。加えて、今回の変更により、戦略全体の収益性はやや低下しています。しかし、これはロットサイズを安全に増やすことで補うことができるため、重大な問題ではありません。市場は常に変動するダイナミックな環境であり、今回導入した新たな安全対策が、将来的に非常に重要な役割を果たす可能性があります。

新しいUSDJYスキャルピング戦略の詳細なパフォーマンス分析

図14:2番目の取引戦略の詳細な分析



結論

本記事では、ローソク足パターンによって生成されたシグナルを活用したトレード戦略の可能性について解説しました。このような戦略には、「ローソク足パターンの形成自体は観察できても、その後に必ずしも同じような価格変動が続くとは限らない」といった批判が存在し、その有効性に疑問を抱く声もあります。

しかし、本戦略で紹介した調整を実施しつつ、ご自身の市場に対する理解を組み合わせることで、戦略の収益性に対する懸念はある程度払拭できると考えています。とはいえ、私たちが加える変更が戦略のパフォーマンスにどのような影響を与えるかは、常に明確とは限らず、そこが一つの課題でもあります。

ファイル
詳細
USDJPY Price Action Benchmark
当初のボラティリティの高いバージョンの取引戦略です。収益性は高かったものの、リスクも大きく伴っていました。
USDJPY Price Action Strategy 2
私たちが一緒に構築した洗練されたバージョンの戦略です。収益性は同等ながら、損失を最小限に抑えることを目指しています。

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

MQL5での取引戦略の自動化(第2回):一目均衡表とオーサムオシレーターを備えた雲抜けシステム MQL5での取引戦略の自動化(第2回):一目均衡表とオーサムオシレーターを備えた雲抜けシステム
この記事では、一目均衡表とオーサムオシレーター(Awesome Oscillator)を活用し、「雲抜け戦略」を自動化するエキスパートアドバイザー(EA)を作成します。インジケーターハンドルの初期化、ブレイクアウト条件の検出、自動売買におけるエントリーおよびエグジットの実装手順について、段階的に解説します。さらに、トレーリングストップやポジション管理ロジックを組み込むことで、EAのパフォーマンスと市場適応力を高める方法にも触れます。
プライスアクション分析ツールキットの開発(第5回):Volatility Navigator EA プライスアクション分析ツールキットの開発(第5回):Volatility Navigator EA
市場の方向性を判断するのは簡単ですが、いつエントリーするかを知るのは難しい場合があります。連載「プライスアクション分析ツールキットの開発」の一環として、エントリーポイント、テイクプロフィットレベル、ストップロスの配置を提供する別のツールを紹介できることを嬉しく思います。これを実現するために、MQL5プログラミング言語を利用しました。この記事では、各ステップについて詳しく見ていきましょう。
独自のLLMをEAに統合する(第5部):LLMを使った取引戦略の開発とテスト(III) - アダプタチューニング 独自のLLMをEAに統合する(第5部):LLMを使った取引戦略の開発とテスト(III) - アダプタチューニング
今日の人工知能の急速な発展に伴い、言語モデル(LLM)は人工知能の重要な部分となっています。私たちは、強力なLLMをアルゴリズム取引に統合する方法を考える必要があります。ほとんどの人にとって、これらの強力なモデルをニーズに応じてファインチューニングし、ローカルに展開して、アルゴリズム取引に適用することは困難です。本連載では、この目標を達成するために段階的なアプローチをとっていきます。
MQL5における数値予測を強化するアンサンブル法 MQL5における数値予測を強化するアンサンブル法
この記事では、MQL5における複数のアンサンブル学習手法の実装を紹介し、それらの手法がさまざまな状況下でどの程度有効かを検証します。
OSZAR »