[MT4]チャートを分析して、一番多いパターンが来たらトレードするEA
目次/もくじ
パターン分析トレードとは
今回はMT4のファイル関数を使って、パターン分析トレードシステムを作成しました。
何を言っているかというと、「このパターンが来たら次にこのパターンになる確率が最も高い」みたいなものを分析して、トレードします。
良く人間がやるパターン別のトレード法みたいなものをちょっと簡単に機械にやらせてみようって回です。
実はプログラミングでは「パターンが来たらトレードする」というのは得ですが、「どのパターンが多いか調べる」ということになると意外とやっている人が少ないって点もあります。
分析方法
まずチャートの状態をカテゴライズします。
ロウソク足で分類しても良いのですが、一度試してみた結果、出現パターンが均一化してしまう※ので、今回は移動平均線を使いました。
※これってロウソク足パターン分析&トレードが意味ないってことを表していると思うんですけどね… ロウソク足が陽線→陰線→陽線になったら次は〇線みたいな分析は50%50%になってしまうので、丁半賭博をやっていたということでしょうか…
それは置いといて..短期、中期、長期の3種類の移動平均線を用意し、それぞれの位置関係から、相場の状態を分類します。
分かりやすく全パターン羅列すると、
(短期、中期、長期)に並んでいる状態(1)
(短期、長期、中期)に並んでいる状態(2)
(中期、短期、長期)に並んでいる状態(3)
(中期、長期、短期)に並んでいる状態(4)
(長期、短期、中期)に並んでいる状態(5)
(長期、中期、短期)に並んでいる状態(6)
の6状態が存在することになります。
つまり、移動平均線が3本あれば必ずこの6つのどれかの状態にカテゴライズされるという訳です。
”状態”と”パターン”の定義
次に、
それぞれの状態に番号をつけ、
どのようにその状態が推移していったかをファイル関数を使って記録していきます。
例:状態1 → 状態2 → 状態1 → 状態3 →・・・
これをずーーと記録していくと、3つの移動平均線の状態推移を表した数字群が出来上がります。
次に、その長い数列の中から、もっとも出現確率が高いパターンを分析します。
このパターンは連続する数によって大きく変わるので、今回は3桁までとしました。
つまり、連続した3つの数字において、もっとも出現確率が高いパターンを割り出します。状態1→状態2ときたら次に状態?が最も気やすいというのが確率的にわかるって訳です。
ここが比較的大変なポイントですが、連続した3つの数字のパターンをすべて書き出し、それぞれに番号を振ります。先ほどのまでの数字は”状態”に対するナンバリングでしたが、これは”パターン”に対するナンバリングです。
具体的には、
状態1→状態2→状態1 のパターンをパターン1とする。
状態1→状態2→状態3 のパターンをパターン2とする。
…
のような感じです。
記録と検索
そして、その文字列を数列に対して検索し、何回検索できるかをカウントします。これならMQLの関数でも可能ですね。
それがすべて終了すると、もっとも出現頻度が高いパターンの番号が分かります。
そして、出現頻度が高いパターンが現れた際に、利益が取れる方向にエントリーするようにプログラムを組みます。
スタートする前のロウソク足1000本では、状態の変化回数は92回で、
652のパターンが最も出現頻度が高いということを示しています。
このコードの問題点としては、過去のロウソク足は1000本までしか参照できないというMT4の仕様がネックになっています。(この記事はかなり古いので今やればもっといけるかも)
推移だけを元にしているので、テストモデルはコントロールポイントでOKです。
下手に全ティックなどにすると、かなり重くなるかもしれません。
2019/1/1~2019/12/31 EURUSD H1バックテスト結果
ソースコード
EAのダウンロード
ソースコードのダウンロード
extern double Lot = 0.1; extern int MAperiod1 = 5; extern int MAperiod2 = 20; extern int MAperiod3 = 100; //extern int MAperiod4 = 40; //extern int MAperiod5 = 80; extern int ExamineBars = 1000; extern int Magic = 314221; static string StateFlow[1000]; static int Bar[2],EntryBar; static string System; static int BestStateFlowNum; static string BestStateFlow; static int EntryStateNum; static string EntryStateFlow; static int EntrySearchLen; static int EntryDirection; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //Create StateFlow int A = 0; for(int i=1; i<=6 ;i++) { for( int p=1; p<=6; p++) { for( int q=1; q<=6; q++) { if( i == p || p ==q || q==i) continue; A++; StateFlow[A] = IntegerToString(i)+IntegerToString(p)+IntegerToString(q); //Print("["+A+"]"+" is... "+StateFlow[A]); } } } // this 6 comes from the total number of the StateFlows. //the result of this are like /* StateFlow[1] = "12"; StateFlow[2] = "13"; StateFlow[3] = "14"; StateFlow[4] = "15"; StateFlow[5] = "16"; StateFlow[6] = "21"; StateFlow[7] = "23"; StateFlow[8] = "24"; StateFlow[9] = "25"; StateFlow[10] = "26"; StateFlow[11] = "31"; StateFlow[12] = "32"; StateFlow[13] = "34"; .... */ //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Bar[1] = Bar[0]; Bar[0] = Bars; if( Bar[0] != Bar[1] ) { string FileText; int ExistedBar; int StateFlowChange; for( int m=ExamineBars ; m>0; m--) { //Print("SearchStateNum "+m+" "+SearchStateNum(m)); if( SearchStateNum(m) != SearchStateNum(m+1) ) { FileText += IntegerToString(SearchStateNum(m),1); StateFlowChange++; } if( iClose(Symbol(),Period(),m) != 0 ) ExistedBar++; } //Print("FileText "+FileText); Print("ExamineBars are "+ExamineBars+" Existed Bar are "+ExistedBar); Print("StateFlow changes "+StateFlowChange+" times"); string FileName=Symbol()+Period()+"StateFlow"+".txt"; int FileHandle=FileOpen(FileName,FILE_WRITE|FILE_TXT|FILE_COMMON); //Print("Handle "+FileHandle); FileWriteString(FileHandle,FileText); FileClose(FileHandle); string AnalyzedDataStr; int StateFlowTimes[1000]; for(int j=1;j<=120;j++ ) { //Get StateFlow data FileName=Symbol()+Period()+"StateFlow"+".txt"; FileHandle = FileOpen(FileName,FILE_READ|FILE_TXT|FILE_COMMON); string SearchData = FileReadString(FileHandle,0); FileClose(FileHandle); string ExtractedData; int StateFlowPlace; //Search most appearable StateFlow StateFlowPlace = StringFind(SearchData,(StateFlow[j])); ExtractedData = StringSubstr(SearchData,StateFlowPlace+1); while(true) { StateFlowPlace = StringFind(ExtractedData,(StateFlow[j])); if( StateFlowPlace == -1 ) break; else { ExtractedData = StringSubstr(ExtractedData,StateFlowPlace+1); StateFlowTimes[j]++; } } AnalyzedDataStr += (StateFlow[j]+":"+StateFlowTimes[j]+";"); //Print(StateFlow[j]+":"+StateFlowTimes[j]+","); if( BestStateFlowNum < StateFlowTimes[j] ) { BestStateFlowNum = StateFlowTimes[j]; BestStateFlow = StateFlow[j]; } } //Write Analyzed data on Analyze.txt FileName = Symbol()+Period()+"Analyze"+".txt"; FileHandle = FileOpen(FileName,FILE_WRITE|FILE_TXT|FILE_COMMON); FileWriteString(FileHandle,AnalyzedDataStr); FileClose(FileHandle); //write best StateFlow on BestStateFlow.txt FileName = Symbol()+Period()+"BestStateFlow"+".txt"; FileHandle = FileOpen(FileName,FILE_WRITE|FILE_TXT|FILE_COMMON); FileWriteString(FileHandle,BestStateFlow); FileClose(FileHandle); //StateFlow means the flow of state EntryStateFlow = StringSubstr(BestStateFlow,0,StringLen(BestStateFlow)-1); //State means the state EntryStateNum = StringToInteger(StringSubstr(EntryStateFlow,StringLen(EntryStateFlow)-1,1)); string BeforeState = StringSubstr(BestStateFlow,StringLen(BestStateFlow)-2,1); string AfterState = StringSubstr(BestStateFlow,StringLen(BestStateFlow)-1,1); EntryDirection = GetEntryDirection(BeforeState,AfterState); EntrySearchLen = StringLen(BestStateFlow)-1; Print("BestStateFlow "+BestStateFlow); Print("EntryDirection "+EntryDirection); Print("EntryStateFlow "+EntryStateFlow); } //CLOSE if( OrdersTotal() > 0 ) { if( EntryBar != Bars ) { bool RSelect = OrderSelect(0,SELECT_BY_POS); if( OrderType() == OP_BUY ) { //if State changed if( GlobalVariableGet("EntriedState") != SearchStateNum(0) ) { bool RClose = OrderClose(OrderTicket(),OrderLots(),Bid,3,clrRed); } } else if( OrderType() == OP_SELL ) { if( GlobalVariableGet("EntriedState") != SearchStateNum(0) ) { RClose = OrderClose(OrderTicket(),OrderLots(),Ask,3,clrBlue); } } } } if( Bar[0] != Bar[1] ) { //Create Current StateFlow string CurrentStateFlow = ""; for(int k=EntrySearchLen; k>=1;k--) { CurrentStateFlow += StringToInteger(SearchStateNum(k)); } //ENTRY if( OrdersTotal() == 0 ) { if( CurrentStateFlow == EntryStateFlow ) { int Ticket; //BUY if( EntryDirection == 1 ){ Ticket = OrderSend(Symbol(),OP_BUY,Lot,Ask,3,0,0,WindowExpertName(),Magic,0,clrRed); EntryBar = Bars; GlobalVariableSet("EntriedState",EntryStateNum); GlobalVariableSet("EntriedBestStateFlow",BestStateFlow); //Print("CurrentStateFlow "+CurrentStateFlow+" EntryStateFlow "+EntryStateFlow); } //SELL if( EntryDirection == -1 ){ Ticket = OrderSend(Symbol(),OP_SELL,Lot,Bid,3,0,0,WindowExpertName(),Magic,0,clrBlue); EntryBar = Bars; GlobalVariableSet("EntriedState",EntryStateNum); GlobalVariableSet("EntriedBestStateFlow",BestStateFlow); //Print("CurrentStateFlow "+CurrentStateFlow+" EntryStateFlow "+EntryStateFlow); } } } } } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- } //+------------------------------------------------------------------+ string DigitFix3(string FixedStr) { string DummyReturn; if( StringToInteger(FixedStr) < 10 ) DummyReturn = "00"+FixedStr; else if( StringToInteger(FixedStr) < 100 ) DummyReturn = "0"+FixedStr; //else if( StringToInteger(FixedStr) == -1 ) DummyReturn = "365"; else DummyReturn = FixedStr; return(DummyReturn); } int SearchStateNum(int Shift) { double MA[10]; MA[1] = iMA(Symbol(),Period(),MAperiod1,0,MODE_SMA,PRICE_CLOSE,Shift); MA[2] = iMA(Symbol(),Period(),MAperiod2,0,MODE_SMA,PRICE_CLOSE,Shift); MA[3] = iMA(Symbol(),Period(),MAperiod3,0,MODE_SMA,PRICE_CLOSE,Shift); //MA[4] = iMA(Symbol(),Period(),MAperiod4,0,MODE_SMA,PRICE_CLOSE,Shift); //MA[5] = iMA(Symbol(),Period(),MAperiod5,0,MODE_SMA,PRICE_CLOSE,Shift); /* int StateNum; //State1 123 if( MA[1] >= MA[2] && MA[2] >= MA[3] ) StateNum = 1; //State2 132 else if( MA[1] >= MA[3] && MA[3] >= MA[2] ) StateNum = 2; //State3 213 else if( MA[2] >= MA[1] && MA[1] >= MA[3] ) StateNum = 3; //State4 231 else if( MA[2] >= MA[3] && MA[3] >= MA[1] ) StateNum = 4; //State5 312 else if( MA[3] >= MA[1] && MA[1] >= MA[2] ) StateNum = 5; //State6 321 else if( MA[3] >= MA[2] && MA[2] >= MA[1] ) StateNum = 6; else if( MA[1] == MA[2] && MA[2] == MA[3] ) StateNum = 6; else if( MA[3] >= MA[2] && MA[2] >= MA[1] ) StateNum = 6; else if( MA[3] >= MA[2] && MA[2] >= MA[1] ) StateNum = 6; */ int StateNum; int f=0; for( int a =1;a<=3;a++) { for( int b=1;b<=3;b++) { for( int c=1;c<=3;c++) { if( a == b || b == c || c == a ) continue; f++; if( MA[a] >= MA[b] && MA[b] >= MA[c] ) { StateNum = f; break; } } if( StateNum != 0 ) break; } if( StateNum != 0 ) break; } return(StateNum); /* 111x 112x 113x 121x 122x 123 131x 132 133x 211x 212x 213 221x 222x 223x 231 232x 233x 311x 312 313x 321 322x 323x 331x 332x 333x */ } string StateNumToStr(int InpStateNum) { /* string State; switch(StateNum){ case 1: State = "123";break; case 2: State = "132";break; case 3: State = "213";break; case 4: State = "231";break; case 5: State = "312";break; case 6: State = "321";break; default:State = "000";break; } return(State); */ int StateNum; string StateStr[20]; int f; for( int a =1;a<=3;a++) { for( int b=1;b<=3;b++) { for( int c=1;c<=3;c++) { if( a == b || b == c || c == a) continue; f++; StateNum = f; StateStr[f] = IntegerToString(a,1)+IntegerToString(b,1)+IntegerToString(c,1); if( InpStateNum == StateNum ) return(StateStr[StateNum]); } } } return("E");//Error } int GetEntryDirection(int StateNumBefore, int StateNumAfter) { string StateBeforeStr = StateNumToStr(StateNumBefore); string StateAfterStr = StateNumToStr(StateNumAfter); if( StringFind(StateAfterStr,"1",0) < StringFind(StateBeforeStr,"1",0) ) return(1); if( StringFind(StateAfterStr,"1",0) > StringFind(StateBeforeStr,"1",0) ) return(-1); else return(0); }
関連記事
-
-
プログラマ向け自動売買開発アイディア
「MQL4/MQL5は扱えるようになったけど、プログラミングのアイディアがない」というプログラマは比
-
-
(MQL4)WEBサイトの情報を取得するやり方[EA]WebRequest
MT4のチャート上にWEBサイトの情報を参照する方法について紹介します。 背景
-
-
2chのスレをテキストマイニングするやり方
よく「大衆の逆をいけば勝てる」みたいなことが相場の世界では言われますよね。今回は2chの市況版の住民
-
-
保護中: [MT4EA]完全無敗 勝率100%のバックテストを生成するEA[ソースコードあり]
今回はバックテストで完璧な成績を出すEAを作成しました。 意味は...ありません。ただの道楽です。
-
-
[MT4/MT5]EAに口座縛り/期間限定縛りをかける種類と方法
良いEAができた場合、身内で配布したい場合があります。しかし、身内に渡してしばらく経ってから自分のE