[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);
}
関連記事
-
-
保護中: [MT4EA]完全無敗 勝率100%のバックテストを生成するEA[ソースコードあり]
今回はバックテストで完璧な成績を出すEAを作成しました。 意味は...ありません。ただの道楽です。
-
-
OANDAのAPIの始め方と使い方とレート比較
オアンダのAPIやります。 金融業界、とりわけFX業界ではFIX APIが機関投資
-
-
[MQL4]MT4でマルチタスク/マルチスレッド処理
MT4/MT5は基本的にC言語ベースなのでマルチスレッドはできません。 しかし、複数のチャート上で
-
-
利用可能なトレード系金融APIまとめ FIX API,REST API,OPEN API
今まで当たり前のようにMT4/MT5/TradeStationで開発をしてきましたが、そういえばAP
-
-
[MT4/MT5]EAに口座縛り/期間限定縛りをかける種類と方法
良いEAができた場合、身内で配布したい場合があります。しかし、身内に渡してしばらく経ってから自分のE



