以下は、前回の「離散データを補間して連続化するインジケータ」に続けて、その生成された「連続データ」からフーリエ変換を行い、10個の周波数成分を三角関数(サイン・コサイン)展開で表示するサンプルコード例です。
ポイント
前回のインジケータをベースにし、補間後のSmoothBufferに対して離散的なフーリエ変換(DFT)を行います。
基本的なDFTを用いて、k=1~10程度の低次のサイン・コサイン成分を求めます。
フーリエ級数展開として、
𝑥[𝑛]≈𝑎0+∑𝑘=1〜10[𝑎𝑘cos(2𝜋𝑘𝑛/𝑁)+
𝑏𝑘sin(2𝜋𝑘𝑛/𝑁)]
x[n]≈a0+k=1∑10[akcos(2πkn/N)+
bksin(2πkn/N)]
の形の係数a_k、b_kを計算し、結果をチャート上に表示(Comment)します。
簡易実装のため、滑らかな曲線を生成するインジケータ内部で完結しています。
a_k、b_kの求め方:
𝑎𝑘=2𝑁∑𝑛=0
𝑁−1𝑥[𝑛]cos(2𝜋𝑘𝑛𝑁)
,
𝑏𝑘=2𝑁∑𝑛=0
𝑁−1𝑥[𝑛]sin(2𝜋𝑘𝑛𝑁)
ak=N2
n=0∑N−1
x[n]cos(N2πkn),bk
=N2
n=0∑N−1
x[n]sin(N2πkn)
※a_0はk=0の場合で、
𝑎0=1𝑁∑𝑛=0𝑁−1𝑥[𝑛]a 0
=N1
n=0∑N−1
x[n]
#property copyright "YourCompany"
#property link "http://www.example.com"
#property indicator_separate_window false
#property indicator_buffers 1
#property indicator_color1 Blue
#property indicator_width1 2
#property indicator_style1 STYLE_SOLID
extern int InterpolationPoints=5;
extern int NumOfComponents=10; // 表示するフーリエ成分数
double SmoothBuffer[];
//------------------------------------------
int init()
{
IndicatorBuffers(1);
SetIndexStyle(0, DRAW_LINE);
SetIndexBuffer(0, SmoothBuffer);
IndicatorShortName("Continuous Curve from M5 + Fourier Components");
return(0);
}
//------------------------------------------
int start()
{
int counted_bars = IndicatorCounted();
if(counted_bars < 0) return(-1);
int total_bars = Bars;
string sym = Symbol();
int timeFrame = PERIOD_M5;
int limit = MathMin(1000, total_bars);
ArraySetAsSeries(SmoothBuffer,true);
// M5の終値取得
double closeArray[];
ArraySetAsSeries(closeArray, true);
ArrayResize(closeArray, limit);
for(int i=0; i<limit; i++)
{
closeArray[i] = iClose(sym, timeFrame, i);
}
// 線形補間によるスムースデータ生成
for(int i=0; i<limit*InterpolationPoints; i++)
SmoothBuffer[i] = EMPTY_VALUE;
int outIndex=0;
for(int i=limit-1; i>0; i--)
{
double startVal = closeArray[i];
double endVal = closeArray[i-1];
for(int j=0; j<InterpolationPoints; j++)
{
double t = (double)j/(double)InterpolationPoints;
double val = startVal*(1.0-t) + endVal*t;
SmoothBuffer[outIndex] = val;
outIndex++;
}
}
// 最後の点
SmoothBuffer[outIndex] = closeArray[0];
int N = outIndex+1; // 補間後のデータ数
// DFTによるフーリエ係数算出
// a0, a_k, b_kを計算
// a0 = (1/N)*Σ x[n]
double a0=0.0;
for(int n=0; n<N; n++)
a0 += SmoothBuffer[n];
a0 /= N;
double a[], b[];
ArrayResize(a, NumOfComponents+1);
ArrayResize(b, NumOfComponents+1);
// k=1~NumOfComponentsまで計算
for(int k=1; k<=NumOfComponents; k++)
{
double sum_cos=0.0;
double sum_sin=0.0;
for(int n=0; n<N; n++)
{
double theta = 2.0*MathPi*k*n/(double)N;
sum_cos += SmoothBuffer[n]*MathCos(theta);
sum_sin += SmoothBuffer[n]*MathSin(theta);
}
// a_k, b_kの計算
a[k] = (2.0/(double)N)*sum_cos;
b[k] = (2.0/(double)N)*sum_sin;
}
// 取得したフーリエ成分を表示
// ここではChart上のComment関数を使って表示する
// a0 と a_k, b_kを列挙
string commentStr = "Fourier Components:
";
commentStr += StringFormat("a0 = %.5f
", a0);
for(int k=1; k<=NumOfComponents; k++)
{
commentStr += StringFormat(" k=%d: a%d=%.5f, b%d=%.5f
", k, k, a[k], k, b[k]);
}
Comment(commentStr);
return(0);
}
//------------------------------------------
int deinit()
{
Comment("");
return(0);
}
説明
元データ生成部分:
前回のインジケータと同様に、M5終値データを取得し、InterpolationPointsに応じて線形補間してSmoothBufferに格納。これが「連続的な曲線」に相当します。
フーリエ成分計算:
SmoothBufferに格納されたN点のデータx[n]に対して、DFTを実行し、以下を求めます。
a0 = (1/N)*Σ x[n] (直流成分)
a_k, b_k = 周波数 k のコサイン・サイン係数
計算後、a0、a_k、b_kをComment関数でチャート上に表示します。
拡張・改良:
周波数成分数NumOfComponentsはパラメータで指定。
より大きなデータ数、より高度な平滑化にも対応可能。
FFT(高速フーリエ変換)を実装すればパフォーマンス向上も可能ですが、ここでは簡易的なDFT。
表示結果:
チャート上にはa0をはじめ、a1,b1~a10,b10までの値が表示され、これにより元の波形が10次までのサイン・コサイン成分で近似できることが分かります。
以上のコード例により、前段で生成した「連続データ」をフーリエ変換して、10個の三角関数成分として表示することが可能になります。
※AIで予測とかマヌケな奴等が多いが、好きな時に好きなタイミングで好きなように介入して意図的に相場をいじれるようなものを予測なんかできるわけがない。
フーリエ変換して不当な介入・操作が行われた時期を特定し、相場にその変換が現れる前に検知するしかないのだ。
例えばレンジ相場が続いていたのにいきなり急激なトレンド・大きな変化が発生した場合、その変化が現れる前に不当な介入・操作が必ずあるのだ。
その不当な介入・操作はフーリエ変換して分解した波の成分の中に含まれているのだ。
また逆にトレンドが続いていたのにいきなりレンジ相場になってしまった場合にも同じことが言える。何者かが不当な介入・操作をしたからトレンド相場からいきなりレンジ相場になるのだ。
レンジ⇔トレンドの切り替えの原因となる不当介入・操作の波を検知すべし!