知っておくべきMQL5ウィザードのテクニック(第01回):回帰分析
1.はじめに
MQL5ウィザードは、MQL5ライブラリで事前にコード化された取引のほとんどの単純な側面を備えており、エキスパートアドバイザー(EA)の迅速な構築と展開を可能にします。トレーダーは、特別なエントリ条件やエグジット条件など、取引の独自の側面に集中することができます。ライブラリには、「アクセラレーターオシレーター」インジケーターのシグナルや「適応移動平均」インジケーターのシグナルなど、いくつかのエントリシグナルクラスとエグジットシグナルクラスが含まれています。ただ、ほとんどのトレーダーが成功した戦略に変換できないだろう遅行指標に基づいています。これが、独自のカスタムシグナルを作成する機能が不可欠である理由です。この記事では、回帰分析でこれをおこなう方法を探ります。
2. クラスの作成
2.1 回帰分析は、ウィキペディアによると、従属変数と1つ以上の独立変数の間の関係を推定するための一連の統計プロセスです。価格データは時系列であるため、これはトレーダーのEAシグナルに役立ちます。したがって、これによって以前の価格と価格変更が将来の価格と価格変更に影響を与える能力をテストできます。回帰分析は、次の式で表すことができます。 ここで、従属変数であり、したがって予測される変数であるyは、それぞれ独自の係数βと誤差εを持つ以前のx値に依存します。 xの値とyの値は、それぞれ以前の価格レベルと予想される価格レベルであると考えることができます。価格レベルだけでなく、価格の変化も同様の方法で調べることができます。 未知のyはx、β、およびεに依存します。これらのうち既知なのは、xとβ0(y切片)だけです。y切片が既知なのは、xi1の直前の価格であるためです。したがって、xごとにそれぞれのβとεを見つける必要があります。 各x i1 は時系列の前の時点でyIだったので、連立方程式を使用してβ値を解くことができます。たとえば、価格の次の変化が以前の2つの変化のみに依存している場合、現在の方程式は のようになります。
そして、前の方程式は のようになります。
誤差εは個別に推定するため、β値の2つの連立方程式を解くことができます。ウィキペディアでの数式のx値の番号付けはMQL5「series」形式ではありません。つまり、番号が最も大きいxが最新です。したがって、上記の2つの方程式のx値の番号を付け直して、それらがどのように同時であることができることを示しました。ここでも、式1のβ0を表すy切片xi1とxi0から始めます。連立方程式を解くには行列を使用した方が効率的です。このためのツールはMQL5ライブラリにあります。
2.2 MQL5ライブラリには、統計に関するクラスの広範なコレクションと、それらをゼロからコーディングする必要性を明らかに否定するような、一般的なアルゴリズムがあります。そのコードも公開されているため、個別に確認できます。ここでの目的のためには、solvers.mqhファイルのCDenseSolverクラスにあるRMatrixSolve関数を使用します。 この関数の中心にあるのは、行列LU分解を使用して、迅速かつ効率的にβ値を求めることです。これについてはMetaQuotesアーカイブに記事が書かれており、ウィキペディアでもこちらに説明があります。
β値を求める前に、CExpertSignalクラスがどのように構造化されているかを調べておくと役に立ちます。ウィザードで作成できるほぼすべてのEAシグナルクラスには、LongCondition関数とShortCondition関数があります。ご想像のとおり、この2つはそれぞれ買いと売りを設定する値を返します。この値は、ウィザードのSignal_ThresholdOpenおよびSignal_ThresholdClose入力パラメータにマップされるため、0~100の範囲の整数である必要があります。通常、取引をおこなう場合、ポジションを決済する条件は、開く条件よりも保守的ではないようにします。つまり、始値のしきい値は終値のしきい値よりも高くなります。したがって、シグナルを開発する際には、決済しきい値を計算するための入力パラメータと、オープニングしきい値用の別の類似した入力パラメータを用意します。条件を計算するときに使用する入力の選択は、ポジションがあるかどうかによって決まります。ポジションがある場合は、決済パラメータを使用します。ない場合は、開始パラメータを使用します。以下は、これら2つのパラメータセットを示すEAシグナルクラスインターフェイスのコードです。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CSignalDUAL_RA : public CExpertSignal { protected: CiMA m_h_ma; // highs MA handle CiMA m_l_ma; // lows MA handle CiATR m_ATR; //--- adjusted parameters int m_size; double m_open_determination,m_close_determination; int m_open_collinearity,m_open_data,m_open_error; int m_close_collinearity,m_close_data,m_close_error; public: CSignalDUAL_RA(); ~CSignalDUAL_RA(); //--- methods of setting adjustable parameters //--- PARAMETER FOR SETTING THE NUMBER OF INDEPENDENT VARIABLES void Size(int value) { m_size=value; } //--- PARAMETERS FOR SETTING THE OPEN 'THRESHOLD' FOR THE EXPERTSIGNAL CLASS void OpenCollinearity(int value) { m_open_collinearity=value; } void OpenDetermination(double value) { m_open_determination=value; } void OpenError(int value) { m_open_error=value; } void OpenData(int value) { m_open_data=value; } //--- PARAMETERS FOR SETTING THE CLOSE 'THRESHOLD' FOR THE EXPERTSIGNAL CLASS void CloseCollinearity(int value) { m_close_collinearity=value; } void CloseDetermination(double value) { m_close_determination=value; } void CloseError(int value) { m_close_error=value; } void CloseData(int value) { m_close_data=value; } //--- method of verification of settings virtual bool ValidationSettings(void); //--- method of creating the indicator and timeseries virtual bool InitIndicators(CIndicators *indicators); //--- methods for detection of levels of entering the market virtual bool OpenLongParams(double &price,double &sl,double &tp,datetime &expiration); virtual bool OpenShortParams(double &price,double &sl,double &tp,datetime &expiration); //--- methods of checking if the market models are formed virtual int LongCondition(void); virtual int ShortCondition(void); protected: //--- method of initialization of the oscillator bool InitRA(CIndicators *indicators); //--- methods of getting data int CheckDetermination(int ind,bool close); double CheckCollinearity(int ind,bool close); // double GetY(int ind,bool close); double GetE(int ind,bool close); double Data(int ind,bool close); // };
次は、LongConditionおよびShortCondition関数のコードです。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CSignalDUAL_RA::LongCondition(void) { int _check=CheckDetermination(0,PositionSelect(m_symbol.Name())); if(_check>0){ return(_check); } return(0); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CSignalDUAL_RA::ShortCondition(void) { int _check=CheckDetermination(0,PositionSelect(m_symbol.Name())); if(_check<0){ return((int)fabs(_check)); } return(0); }
引き続き、β値を求めるために、GetY関数を使用します。以下がコードです。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double CSignalDUAL_RA::GetY(int ind,bool close) { double _y=0.0; CMatrixDouble _a;_a.Resize(m_size,m_size); double _b[];ArrayResize(_b,m_size);ArrayInitialize(_b,0.0); for(int r=0;r<m_size;r++) { _b[r]=Data(r,close); for(int c=0;c<m_size;c++) { _a[r].Set(c,Data(r+c+1, close)); } } int _info=0; CDenseSolver _S; CDenseSolverReport _r; double _x[];ArrayResize(_x,m_size);ArrayInitialize(_x,0.0); _S.RMatrixSolve(_a,m_size,_b,_info,_r,_x); for(int r=0;r<m_size;r++) { _y+=(Data(r,close)*_x[r]); } //--- return(_y); }
参照されているData関数は、取引されている銘柄の終値の変化とま同じ終値の移動平均の変化を切り替えます。使用されるオプションは、開始しきい値または終了しきい値のどちらを計算するかに応じて、m_open_dataまたはm_close_data入力パラメーターのいずれかによって定義されます。データを選択するためのコードは、以下の列挙に示されています。
enum Edata { DATA_TREND=0, // changes in moving average close DATA_RANGE=1 // changes in close };
そして、これを選択するData関数を以下に示します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double CSignalDUAL_RA::Data(int ind,bool close) { if(!close) { if(Edata(m_open_data)==DATA_TREND) { m_h_ma.Refresh(-1); return((m_l_ma.Main(StartIndex()+ind)-m_l_ma.Main(StartIndex()+ind+1))-(m_h_ma.Main(StartIndex()+ind)-m_h_ma.Main(StartIndex()+ind+1))); } else if(Edata(m_open_data)==DATA_RANGE) { return((Low(StartIndex()+ind)-Low(StartIndex()+ind+1))-(High(StartIndex()+ind)-High(StartIndex()+ind+1))); } } else if(close) { if(Edata(m_close_data)==DATA_TREND) { m_h_ma.Refresh(-1); return((m_l_ma.Main(StartIndex()+ind)-m_l_ma.Main(StartIndex()+ind+1))-(m_h_ma.Main(StartIndex()+ind)-m_h_ma.Main(StartIndex()+ind+1))); } else if(Edata(m_close_data)==DATA_RANGE) { return((Low(StartIndex()+ind)-Low(StartIndex()+ind+1))-(High(StartIndex()+ind)-High(StartIndex()+ind+1))); } } return(0.0); }
β値を取得したら、誤差の推定に進むことができます。
2.3 ウィキペディアによると、標準誤差は、次の式で推定できます。
sを標準偏差、nを標本サイズとすると、この誤差は、どんなに熱心に計算してもすべての予測が常に100%正確であるとは限らないという現実を思い起こさせます。誤差が発生することを常に考慮に入れ、予期する必要があります。式に示されている標準偏差は、予測値と実際の値の間で測定されます。比較のために、予測と実際の最後の差異などのそのままの誤差を確認することもできます。これら2つのオプションは、以下の列挙から選択できます。
enum Eerror { ERROR_LAST=0, // use the last error ERROR_STANDARD=1 // use standard error }
GetE関数は、上記の式を使用している間、入力パラメータ(m_open_errorまたはm_close_error)に応じてエラー推定値を返します。以下がコードです。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double CSignalDUAL_RA::GetE(int ind,bool close) { if(!close) { if(Eerror(m_open_error)==ERROR_STANDARD) { double _se=0.0; for(int r=0;r<m_size;r++) { _se+=pow(Data(r,close)-GetY(r+1,close),2.0); } _se=sqrt(_se/(m_size-1)); _se=_se/sqrt(m_size); return(_se); } else if(Eerror(m_open_error)==ERROR_LAST){ return(Data(ind,close)-GetY(ind+1,close)); } } else if(close) { if(Eerror(m_close_error)==ERROR_STANDARD) { double _se=0.0; for(int r=0;r<m_size;r++){ _se+=pow(Data(r,close)-GetY(r+1,close),2.0); } _se=sqrt(_se/(m_size-1)); _se=_se/sqrt(m_size); return(_se); } else if(Eerror(m_close_error)==ERROR_LAST){ return(Data(ind,close)-GetY(ind+1,close)); } } //--- return(Data(ind,close)-GetY(ind+1,close)); }
繰り返しになりますが、m_open_errorまたはm_close_errorの使用は、ポジションがあるかどうかによって決まります。誤差の推定値が得られたら、yを大まかなに予測できるはずです。ただし、回帰分析には多くの落とし穴があります。そのような落とし穴の1つは、独立変数が類似しすぎて、予測値が過大になる可能性があることです。この現象は多重共線性と呼ばれ、確認する価値があります。
2.4 ウィキペディアがこちらで定義している多重共線性は、Investopediaによる重回帰モデルの2つ以上の独立変数間に発生する高い相互相関として推測できます。 数式自体はなく、分散拡大係数(variance inflation factor、VIF)によって検出されます。この係数は、すべての独立変数(x)を使用して、これらの各変数がyの予測においてどのように一意であるかを理解するのに役立ちます。これは以下の式で求められます。ここで、Rは各独立変数の他の変数に対する回帰です。
ただし、ここでの目的のために、多重共線性を考慮して、独立変数の最近の2つのデータセット間のスピアマン相関の逆を取り、それを正規化します。データセットの長さは、最小長が3である「m_size入力パラメータによって設定されます。正規化により、単純にこれを2から引いて結果を反転します。この正規化された重みは、誤差推定値、予測値、またはその両方に乗算するか、未使用にすることができます。これらのオプションは、以下の列挙にリストされています。
enum Echeck { CHECK_Y=0, // check for y only CHECK_E=1, // check for the error only CHECK_ALL=2, // check for both the y and the error CHECK_NONE=-1 // do not use collinearity checks };
適用される重みの選択は、m_open_collinearityまたはm_close_collinearity入力パラメータによっても設定されます。 繰り返しますが、これはポジションが開いているかどうかによって異なります。CheckCollinearityのコードを以下に示します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double CSignalDUAL_RA::CheckCollinearity(int ind,bool close) { double _check=0.0; double _c=0.0,_array_1[],_array_2[],_r=0.0; ArrayResize(_array_1,m_size);ArrayResize(_array_2,m_size); ArrayInitialize(_array_1,0.0);ArrayInitialize(_array_2,0.0); for(int s=0; s<m_size; s++) { _array_1[s]=Data(ind+s,close); _array_2[s]=Data(m_size+ind+s,close); } _c=1.0/(2.0+fmin(-1.0,MathCorrelationSpearman(_array_1,_array_2,_r))); double _i=Data(m_size+ind,close), //y intercept _y=GetY(ind,close), //product sum of x and its B coefficients _e=GetE(ind,close); //error if(!close) { if(Echeck(m_open_collinearity)==CHECK_Y){ _check=_i+(_c*_y)+_e; } else if(Echeck(m_open_collinearity)==CHECK_E){ _check=_i+_y+(_c*_e); } else if(Echeck(m_open_collinearity)==CHECK_ALL){ _check=_i+(_c*(_y+_e)); } else if(Echeck(m_open_collinearity)==CHECK_NONE){ _check=_i+(_y+_e); } } else if(close) { if(Echeck(m_close_collinearity)==CHECK_Y){ _check=_i+(_c*_y)+_e; } else if(Echeck(m_close_collinearity)==CHECK_E){ _check=_i+_y+(_c*_e); } else if(Echeck(m_close_collinearity)==CHECK_ALL){ _check=_i+(_c*(_y+_e)); } else if(Echeck(m_close_collinearity)==CHECK_NONE){ _check=_i+(_y+_e); } } //--- return(_check); }
多重共線性について確認するだけでなく、市場の外因性の変化が原因で、回帰分析が予想通りにならない場合があります。これを追跡し、シグナルの独立変数が従属変数(予測)に影響を与える能力を測定するために、決定係数を使用します。
2.5 決定係数は、Investopediaに従って特定の事象の結果を予測するときに、1つの変数の違いが2つ目の変数の違いによってどのように説明できるかを調べる統計的測定値です。ウィキペディアもより包括的な定義を提供しており、以下に示す数式はそこから採用されています。
二乗和の式(yは実際の値、fは予測値)
合計の総計の式(yは実際の値、ÿはこれらの値の移動平均)
そして最後に、係数自体はR二乗とも呼ばれます。
この係数がおこなうことは、xがyに影響を与える程度を測定することです。前述のように、回帰が後退して市場から離れた方が安全であることを意味する期間があるため、これは重要です。これをフィルターを介して監視することにより、システムが信頼できるときに取引する可能性が高くなります。通常、この係数は0より大きく、1が理想的です。しきい値を定義する際に使用される入力パラメータは、m_open_determinationまたはm_close_determinationで、これもポジションの数に依存します。以下のCheckDetermination関数によって計算された決定係数がこのパラメータより小さい場合、買いまたは売りの条件はゼロを返します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CSignalDUAL_RA::CheckDetermination(int ind,bool close) { int _check=0; m_h_ma.Refresh(-1);m_l_ma.Refresh(-1); double _det=0.0,_ss_res=0.0,_ss_tot=0.0; for(int r=0;r<m_size;r++) { _ss_res+=pow(Data(r,close)-GetY(r+1,close),2.0); _ss_tot+=pow(Data(r,close)-((m_l_ma.Main(r)-m_l_ma.Main(r+1))-(m_h_ma.Main(r)-m_h_ma.Main(r+1))),2.0); } if(_ss_tot!=0.0) { _det=(1.0-(_ss_res/_ss_tot)); if(_det>=m_open_determination) { double _threshold=0.0; for(int r=0; r<m_size; r++){ _threshold=fmax(_threshold,fabs(Data(r,close))); } double _y=CheckCollinearity(ind,close); _check=int(round(100.0*_y/fmax(fabs(_y),fabs(_threshold)))); } } //--- return(_check); }
決定係数を確認できれば、有効なシグナルが得られます。次に続くのは、MQL5ウィザードでこのシグナルをEAに組むことです。
3. MQL5ウィザードによる組み立て
3.1 EAを組み立てる際には、カスタム補助コードをMQL5ウィザードのコードと一緒に使用できます。これは完全にオプションであり、トレーダーのスタイルに合わせます。この記事では、銘柄の一般的なATRに基づくカスタム指値注文の開始と、同じ指標に基づくトレーリングポジションのシステムについて見ていきます。テイクプロフィットターゲットは使用しません。
3.1.1 ATRベースの指値注文は、OpenLongParams関数「とOpenShortParams関数をオーバーロードし、以下に示すようにシグナルクラスでカスタマイズすることで設定できます。
//+------------------------------------------------------------------+ //| Detecting the levels for buying | //+------------------------------------------------------------------+ bool CSignalDUAL_RA::OpenLongParams(double &price,double &sl,double &tp,datetime &expiration) { CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL; //--- if(general==NULL) { m_ATR.Refresh(-1); //--- if a base price is not specified explicitly, take the current market price double base_price=(m_base_price==0.0) ? m_symbol.Ask() : m_base_price; //--- price overload that sets entry price to be based on ATR price =m_symbol.NormalizePrice(base_price-(m_price_level*(m_ATR.Main(0)/m_symbol.Point()))*PriceLevelUnit()); sl =0.0; tp =0.0; expiration+=m_expiration*PeriodSeconds(m_period); return(true); } //--- return(general.OpenLongParams(price,sl,tp,expiration)); } //+------------------------------------------------------------------+ //| Detecting the levels for selling | //+------------------------------------------------------------------+ bool CSignalDUAL_RA::OpenShortParams(double &price,double &sl,double &tp,datetime &expiration) { CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL; //--- if(general==NULL) { m_ATR.Refresh(-1); //--- if a base price is not specified explicitly, take the current market price double base_price=(m_base_price==0.0) ? m_symbol.Bid() : m_base_price; //--- price overload that sets entry price to be based on ATR price =m_symbol.NormalizePrice(base_price+(m_price_level*(m_ATR.Main(0)/m_symbol.Point()))*PriceLevelUnit()); sl =0.0; tp =0.0; expiration+=m_expiration*PeriodSeconds(m_period); return(true); } //--- return(general.OpenShortParams(price,sl,tp,expiration)); }
MQL5ウィザードで生成されたEAには、Signal_PriceLevel入力パラメータがあります。デフォルトではゼロですが、値が割り当てられた場合、成行注文がおこなわれる現在の価格からの距離を、取引銘柄の価格ポイントで表します。この入力が負の場合は逆指値注文が出され、正の場合は指値注文が出されます。 doubleデータ型です。ここでの目的のために、この入力はATRの現在の価格ポイントの分数または倍数になります。
3.1.2 また、ATRトレーリングクラスまた、ATRを使用してストップロスを設定および移動する、カスタマイズされたCExpertTrailingクラスです。その主要な機能の実装は、以下のコードにあります。
//+------------------------------------------------------------------+ //| Checking trailing stop and/or profit for long position. | //+------------------------------------------------------------------+ bool CTrailingATR::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp) { //--- check if(position==NULL) return(false); //--- m_ATR.Refresh(-1); double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits()); //--- sl adjustment to be based on ATR double new_sl=NormalizeDouble(level-(m_atr_weight*(m_ATR.Main(0)/m_symbol.Point())),m_symbol.Digits()); double pos_sl=position.StopLoss(); double base =(pos_sl==0.0) ? position.PriceOpen() : pos_sl; //--- sl=EMPTY_VALUE; tp=EMPTY_VALUE; if(new_sl>base && new_sl<level) sl=new_sl; //--- return(sl!=EMPTY_VALUE); } //+------------------------------------------------------------------+ //| Checking trailing stop and/or profit for short position. | //+------------------------------------------------------------------+ bool CTrailingATR::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp) { //--- check if(position==NULL) return(false); //--- m_ATR.Refresh(-1); double level =NormalizeDouble(m_symbol.Ask()+m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits()); //--- sl adjustment to be based on ATR double new_sl=NormalizeDouble(level+(m_atr_weight*(m_ATR.Main(0)/m_symbol.Point())),m_symbol.Digits()); double pos_sl=position.StopLoss(); double base =(pos_sl==0.0) ? position.PriceOpen() : pos_sl; //--- sl=EMPTY_VALUE; tp=EMPTY_VALUE; if(new_sl<base && new_sl>level) sl=new_sl; //--- return(sl!=EMPTY_VALUE); }
ここでも、m_atr_weightは、m_price_levelと同様に最適化可能なパラメータとなり、ポジションをどの程度追跡できるかを設定します。
3.2 ウィザードの組み立てでは、以下に示すように、シグナルの選択のみが注目すべき段階であり、簡単な方法でおこなわれます。
そして、以下に示すカスタムのトレーリングメソッドを追加します。
4.ストラテジーテスターでのテスト
4.1 コンパイルはMQL5ウィザードの組み立てに続くもので、EAファイルを作成し、コードにエラーがないことを確認します。
4.2 ストラテジーテスターの入力タブでEAのデフォルト入力設定もおこなう必要があります。ここで重要なのは、Signal_TakeLevelとSignal_StopLevelがゼロに設定されていることを確認することです。これは、前述のように、この記事の目的上、終了はトレーリングストップまたはSignal_ThresholdClose入力パラメータによってのみ定義されるためです。
4.3 最適化は、取引する証券会社の実際のティックで理想的に実行する必要があります。この記事では、2018.01.01から2021.01.01までのV字型の期間の4時間枠でEURUSDを最適化します。比較のために、2つの最適化を実行します。1つ目は成行注文のみを使用し、2つ目は未決注文に対してオープンです。最適化は負の値から正の値になるため、Signal_PriceLevelがゼロになる可能性があるため、成行注文のみを使用するオプションを引き続き検討するため、「opento」未決注文を使用します。最適化は、以下に示すように未決注文を使用するオプションの前に設定できます。これと指値注文を使用しないオプションとの唯一の違いは、後でSignal_PriceLevel入力パラメーターを最適化された入力の一部ではなく0のままにすることです。
4.4 最適化の結果を以下に示します。1つ目は、成行注文のみで取引した場合の最良の結果のレポートとエクイティ曲線です。
レポート1の一部
次に、指値注文を使用して同様にレポートと曲線を作成します。
レポート2の一部
回帰分析によると、指値注文を使用することで利益を犠牲にしてドローダウンが少なくなるため、利益が得られるようです。トレーリングストップクラスや資金管理タイプの変更など、このシステムを強化するために他の変更をおこなうこともできます。テスト目的で、固定証拠金の割合を使用し、基準を「複雑な基準」に設定して最適化しました。ただし、この記事の範囲外のものを展開する前に、過去のティックデータで可能な限り広範囲にテストし、十分なフォワードウォークを実行することが望ましいです。
5.結論
5.1MQL5ウィザードは、明らかに、すべてのトレーダーの武器庫にあるべき、機知に富んだツールです。ここで検討したのは、共線性や決定係数などの回帰分析の統計的概念を取り入れ、それらを堅牢なトレーディングシステムの基礎として使用する方法です。次のステップは、ティックデータ履歴の広範なテストと、トレーダーの経験またはMQL5ライブラリの組み込みシグナルに基づいて、このシグナルを他の独自のシグナルと組み合わせて、より包括的な取引システムを考え出すことができるかどうかを調査することです。これらの一連の記事の場合と同様に、この記事は目標を提供することを意図したものではなく、市場へのトレーダーのアプローチにより適合するように調整できるプロセスを提供することを目的としています。ご精読ありがとうございました。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/11066
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索