最初にタスクを分割しましょう
0)インジケーターロジック
1)インジケーター量子化ステップ
2)インジケーターパフォーマンス
MQL4
MetaTrader4 Terminalカスタムインジケータープログラミングは、基盤となるプラットフォームのより深い理解に依存しています。QUOTE ...
取引された商品価格を変更する各外部マーケットイベントは、からのメッセージのネットワーク配信によってlcoalhostに通知されますMetaTrader4 Server。これは別名Tickであり、元々はと呼ばれていた関数の呼び出しをトリガーします。start()
新しいNewでは名前が。MQL4.56789
に変更されましたOnTick()
。
以下の変更されたMQL4
リストには、コアロジックの曖昧性解消に関する注釈が含まれています。これは、以下にリストされているすべての手順の前に行う必要があります。
1)インジケーターの量子化ステップ
コードはまだ非常に非効率的ですが(以下の[2]のように)、ロジックには、出力が任意の形式に量子化されたストレートハードル形式は含まれていません{binary | 三元| 任意の状態数}-量子化されたシステム。インジケーターのコアロジックがクリアされると、量子化ステップはR(1)からI(1 )への簡単な変換になります。
2)インジケーターのパフォーマンス
ティックの到着は、提案されたカスタムインジケーター計算の唯一の可変部分であるまたはのいずれかを変更できますが、変更する必要はありません。High[0]
Low[0]
これは、再計算の範囲を縮小する方法の中心的なアイデアであり、MQL4
コードはティックごとに実現する必要があります。MT4の最近のバージョンでは、すべてのカスタムインジケーターが単一のスレッドを共有し、カスタムインジケーターの効率的なアルゴリズム化により多くのストレスがかけられています。これらは、不十分で非効率的なコードループおよび畳み込み/再帰の再実行に関するプラットフォームの取引決定をブロックする可能性があります。
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1 Lime
#property indicator_color2 Red
#property indicator_color3 CLR_NONE
#property indicator_color4 CLR_NONE
extern int P = 13;
extern int T = 3000;
extern double P2 = 0.001;
double G[]; // 0: LINE
double R[]; // 1: LINE
double B3[]; // 2: BUT NEVER PAINTED, NEVER CONSUMED _?_
double B4[]; // 3: BUT NEVER PAINTED, NEVER CONSUMED _?_
int init(){
IndicatorBuffers(4);
SetIndexBuffer( 0, G );SetIndexStyle( 0, DRAW_LINE, STYLE_SOLID, 1, Lime );
SetIndexBuffer( 1, R );SetIndexStyle( 1, DRAW_LINE, STYLE_SOLID, 1, Red );
SetIndexBuffer( 2, B3 );SetIndexStyle( 2, DRAW_NONE );
SetIndexBuffer( 3, B4 );SetIndexStyle( 3, DRAW_NONE );
return(0);
}
int start(){
if ( Bars <= 38 ) return(0); // JIT/RET in case Bars < 39 --^ --^ --^ --^
if ( T >= Bars ) T = Bars; // (TRIM´d) T < Bars .OR. = Bars
int aDrawBegins = Bars - T + P + 1; // ( extern P = 13 ) + 1 + ( Bars - ( extern T = 3000 if T < Bars else Bars ) )
//tIndexDrawBegin( 0, Bars - T + P + 1 ); // PREF: ( reused 4x )
SetIndexDrawBegin( 0, aDrawBegins ); // Draw 14+ last candles -- PREF: why a per tick hard-coded SHIFTING / enforced re-draw?
SetIndexDrawBegin( 1, aDrawBegins ); // Draw 14+ last candles -- PREF: why a per tick hard-coded SHIFTING / enforced re-draw?
SetIndexDrawBegin( 2, aDrawBegins ); // Draw 14+ last candles -- PREF: why a per tick hard-coded SHIFTING / enforced re-draw?
SetIndexDrawBegin( 3, aDrawBegins ); // Draw 14+ last candles -- PREF: why a per tick hard-coded SHIFTING / enforced re-draw?
double A, S1, S2; // auxiliary var for bar-mid-price calculi
int Z; // auxiliary stepper
int Opt = IndicatorCounted(); // Opt ( NEVER RE-USED )
if ( Opt < P ){ // if ( ( extern P = 13 ) > IndicatorCounted() )
// ----------------------- ??? ----------------------------------------------------- NEVER EXEC´d: for( Z = 1++ v/s Z <= 0 )
for ( Z = 1; Z <= 0; Z++ ) G[T-Z] = 0.0; // .STO G[T-Z], 0., BUT NEVER EXEC´d: for( Z = 1++ v/s Z <= 0 )
for ( Z = 1; Z <= 0; Z++ ) R[T-Z] = 0.0; // .STO R[T-Z], 0., BUT NEVER EXEC´d: for( Z = 1++ v/s Z <= 0 )
// ----------------------- ??? ----------------------------------------------------- NEVER EXEC´d: for( Z = 1++ v/s Z <= 0 )
}
Z = T - P - 1; // .STO Z, ( T = Bars (TRIM´d) ) - ( extern P = 13 ) - 1
while( Z >= 0 ){ // .DEC Z
// !!! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // PERF: very inefficient to RE-calc STATIC ( ( extern P = 13 ) - 1 )-DEEP CONVOLUTIONS per tick !!
S1 = 0.0; for ( int C = 0; C <= P - 1; C++ ){ S1 = S1 + ( High[Z+C] + Low[Z+C] ) / 2; }
S2 = 0.0; for ( int C = 0; C <= P - 1; C++ ){ S2 = S2 + ( ( High[Z+C] + Low[Z+C] ) * ( C+1 ) / 2 );}
// !!! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // PERF: very inefficient to RE-calc STATIC ( ( extern P = 13 ) - 1 )-DEEP CONVOLUTIONS per tick !!
A = S1 / S2;
G[Z] = A; // .STO G[Z], A if Z >= 0
if ( Z > 0 ){ R[Z-1] = A;} // .STO R[Z-1], A if Z > 0
Z--;
}
for ( int N = T - P - 2; N >= 0; N-- ){ // .STO N, ( T = Bars (TRIM´d) ) - ( extern P = 13 ) - 2
if ( N > 0 ){ // N > 0:
if ( G[N-1] > G[N] ){ R[N] = EMPTY_VALUE; continue;} // .BLNK R[N], EMPTY if G[N-1] > G[N]
if ( G[N-1] < G[N] ){ G[N] = R[N]; continue;} // .SET G[N], R[N] if G[N-1] < G[N]
}
// ?? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // WHY MANY-TIMES RE-ASSIGNED A CONST. VALUE HERE, INSIDE A FOR(){...}-loop body? -------------- ??
B3[0] = G[0] + P2; // .STO B3[0], G[0] + ( extern P2 = 0.001 )
B4[0] = G[0] - P2; // .STO B4[0], G[0] - ( extern P2 = 0.001 )
// forced quantise using 2 extra buffers
// ?? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // WHY MANY-TIMES RE-ASSIGNED A CONST. VALUE HERE, INSIDE A FOR(){...}-loop body? -------------- ??
}
return(0);
}
新規-MQL4.56789
構文
このOnCalculate()
関数は、によってインジケーター値を計算する必要がある場合にのみ、カスタムインジケーターで呼び出されますCalculate event。これは通常、インジケーターが計算されるシンボルに対して新しいティックが受信されたときに発生します。このインジケーターは、このシンボルの価格チャートに添付する必要はありません。
最初のrates_total
パラメーターには、bars
計算用のインジケーターで使用可能なの数が含まれ、チャートで使用可能なバーの数に対応します。
OnCalculate()
の戻り値と2番目の入力パラメータの関係に注意する必要がありますprev_calculated
。OnCalculate()
関数呼び出し中に、パラメーターには前の呼び出し中にprev_calculated
返された値が含まれます。これにより、カスタムインジケーターを計算するための経済的なアルゴリズムが可能になり、この関数の前回の実行以降に変更されていないバーの繰り返し計算を回避できます。OnCalculate()
このためには、通常rates_total
、現在の関数呼び出しのバーの数を含むパラメーターの値を返すだけで十分です。価格データの最後の呼び出しOnCalculate()
が変更された場合(より深い履歴がダウンロードされたか、履歴ブランクが埋められた場合)、入力パラメーターの値はprev_calculated
端末によってゼロに設定されます。
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate( const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[]
)
{
// Get the number of bars available now for the current Symbol and chart period
int barsNow = Bars( _Symbol, PERIOD_CURRENT );
// .RET value of prev_calculated for a next call
return( rates_total );
}