MT5自動売買ソフトの作成5 ストキャスティクスを作る
ストキャスティクスとは
通常のストキャスティクスは下記の線で構成されています。
%K =(当日終値-n日間の最安値)÷(n日間の最高値-n日間の最安値)×100 %D = %Kの単純移動平均 Slow%D = %Dの単純移動平均
当日の終値が過去数日間のどの位置にあるのかがわかります。
ストキャスティクスでは「売られすぎ」や「買われすぎ」といった相場の過熱度が判断できます。オシレーター系の基本ですね。
オシレーター系インジケータの特徴ですが、トレンドに入るとずっと買われすぎ、ずっと売られすぎ状態になってしまいます。なのでレンジ状態(行ったり来たりの状態)でのみ参考になります。
前回のMACDはオシレータ系に入っていますが、指数移動平均がベースなのでトレンド系に近いとインジケータです。そのため、ストキャスティクスはMACDと組み合わせて使われることがあります。
今回作るストキャスティクスは
%D(Slow%Kとも言います)のみを使います。ただし1本ではなく4期間の4本編みにします。
4本のストキャスティクスが纏まるところがシグナルになる感じですね。
想像つかないと思いますので画像を。
4本の各期間は、9、14、38、62にしています。(通貨ペアで有効な期間が変わると思いますので、いろいろ試してみましょう)
DLLのプログラム
普通の計算式
extern "C" __declspec(dllexport) void DllStochasArray(const int size, const int period, const int slow, const double* close, const double* lowArg, const double* highArg, double* out) { auto pStoch = make_unique<double[]>(size); for (int i = period; i <= size; i++) { double high = 0.0; double low = 100000.0; for (int n = 0; n < period; n++) { if (high < highArg[i - period + n]) { high = highArg[i - period + n]; } if (low > lowArg[i - period + n]) { low = lowArg[i - period + n]; } } pStoch[i - 1] = (close[i - 1] - low) * 100.0 / (high - low); } smaArray(size, slow, pStoch.get(), out); }
period期間の高値・安値を調べて、%K(pStoch)を計算します。%Kをslow期間で単純移動平均して%Dを算出します。
このストキャスティクス関数を4本分呼び出せば良いのですが、せっかくC++でDLLを作成するのですから、今回はC++要素を入れてみましょう。
4本全部計算してみましょう。
extern "C" __declspec(dllexport) void DllStochasBraid(const int size, const int slow, const int period1, const int period2, const int period3, const int period4, const double* close, const double* lowArg, const double* highArg, double* out1, double* out2, double* out3, double* out4) { vector<int> periods = { period1, period2, period3, period4 }; vector<map<double, int>> mapHighs = { map<double, int>(), map<double, int>(), map<double, int>(), map<double, int>() }; vector<map<double, int>> mapLows = { map<double, int>(), map<double, int>(), map<double, int>(), map<double, int>() }; auto ptr1 = make_unique<double[]>(size); auto ptr2 = make_unique<double[]>(size); auto ptr3 = make_unique<double[]>(size); auto ptr4 = make_unique<double[]>(size); vector<unique_ptr<double[]>*> stocks = { &ptr1, &ptr2, &ptr3, &ptr4 }; for (int i = 0; i < size; i++) { for (int n = 0; n < periods.size(); n++) { // HIGH. LOW値をmapに入れておく mapHighs[n][highArg[i]] = mapLows[n][lowArg[i]] = 1; if (i >= periods[n]) { // 期間が過ぎたら入れ替える auto ith = mapHighs[n].find(highArg[i - periods[n]]); if (ith != mapHighs[n].end()) mapHighs[n].erase(ith); auto itl = mapLows[n].find(lowArg[i - periods[n]]); if (itl != mapLows[n].end()) mapLows[n].erase(itl); // 期間が来たらストキャスティクスを計算する (*stocks[n])[i] = (close[i] - mapLows[n].begin()->first) * 100.0 / (mapHighs[n].rbegin()->first - mapLows[n].begin()->first); (*stocks[n])[i] = ((*stocks[n])[i] > 100.0) ? 100.0 : ((*stocks[n])[i] < 0.0) ? 0.0 : (*stocks[n])[i]; } } } smaArray(size, slow, stocks[0]->get(), out1); smaArray(size, slow, stocks[1]->get(), out2); smaArray(size, slow, stocks[2]->get(), out3); smaArray(size, slow, stocks[3]->get(), out4); }
初見のキーワードがあると思います。(初見でない人は飛ばしてください)
-
動的な配列と考えてください。
[数値]
で各要素にアクセスできます。 map
連想配列と考えてください。
[文字列・数値]
で各要素にアクセスできます。例えば
map<string, string> a
であれば、a["abc"] = "def";
のように"abc"の要素に"def"を登録できます。
("abc"をキー、"def"を値と言います)
また map は登録されたら自動的にキーでソートします。
今回はこのmapはキーでソートするという機能を使って高値の最大値、安値の最小値を取り出します。 (キーをソートするので、値には適当な"1"を固定で入れています・・・あまり良いプログラムとは言えませんので参考程度で)
(*stocks[n])[i] = (close[i] - mapLows[n].begin()->first) * 100.0 / (mapHighs[n].rbegin()->first - mapLows[n].begin()->first);
.begin()->first
がmapの最初の要素、.rbegin()->first
がmapの最後の要素です。
mapHighs、mapLowsは、各期間分の高値・安値を登録しています。
periods期間が過ぎたら.erase(ith)
で要素から削除します。
stocks
にはperiods期間の%Kが計算されます。
最後に smaArray でslow期間で単純移動平均を行いout1~4に出力します。
全体のコード
// dllmain.cpp : DLL アプリケーションのエントリ ポイントを定義します。 #include "pch.h" #include <memory> #include <vector> #include <map> using namespace std; BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } static void smaArray(const int size, const int period, const double* close, double* out) { for (int i = period; i <= size; i++) { double total = 0.0; for (int n = 0; n < period; n++) { total += close[i - period + n]; } out[i - 1] = total / period; } } extern "C" __declspec(dllexport) void DllStochasBraid(const int size, const int slow, const int period1, const int period2, const int period3, const int period4, const double* close, const double* lowArg, const double* highArg, double* out1, double* out2, double* out3, double* out4) { vector<int> periods = { period1, period2, period3, period4 }; vector<map<double, int>> mapHighs = { map<double, int>(), map<double, int>(), map<double, int>(), map<double, int>() }; vector<map<double, int>> mapLows = { map<double, int>(), map<double, int>(), map<double, int>(), map<double, int>() }; auto ptr1 = make_unique<double[]>(size); auto ptr2 = make_unique<double[]>(size); auto ptr3 = make_unique<double[]>(size); auto ptr4 = make_unique<double[]>(size); vector<unique_ptr<double[]>*> stocks = { &ptr1, &ptr2, &ptr3, &ptr4 }; for (int i = 0; i < size; i++) { for (int n = 0; n < periods.size(); n++) { // HIGH. LOW値をmapに入れておく mapHighs[n][highArg[i]] = mapLows[n][lowArg[i]] = 1; if (i >= periods[n]) { // 期間が過ぎたら入れ替える auto ith = mapHighs[n].find(highArg[i - periods[n]]); if (ith != mapHighs[n].end()) mapHighs[n].erase(ith); auto itl = mapLows[n].find(lowArg[i - periods[n]]); if (itl != mapLows[n].end()) mapLows[n].erase(itl); // 期間が来たらストキャスティクスを計算する (*stocks[n])[i] = (close[i] - mapLows[n].begin()->first) * 100.0 / (mapHighs[n].rbegin()->first - mapLows[n].begin()->first); (*stocks[n])[i] = ((*stocks[n])[i] > 100.0) ? 100.0 : ((*stocks[n])[i] < 0.0) ? 0.0 : (*stocks[n])[i]; } } } smaArray(size, slow, stocks[0]->get(), out1); smaArray(size, slow, stocks[1]->get(), out2); smaArray(size, slow, stocks[2]->get(), out3); smaArray(size, slow, stocks[3]->get(), out4); }
インジケータのプログラム
//+------------------------------------------------------------------+ //| dll_test.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_minimum 0 #property indicator_maximum 100 #property indicator_buffers 4 #property indicator_plots 4 //--- plot memConf #property indicator_label1 "stoch1" #property indicator_type1 DRAW_LINE #property indicator_color1 Orange #property indicator_style1 STYLE_SOLID #property indicator_width1 1 #property indicator_label2 "stoch2" #property indicator_type2 DRAW_LINE #property indicator_color2 Chocolate #property indicator_style2 STYLE_SOLID #property indicator_width2 1 #property indicator_label3 "stoch3" #property indicator_type3 DRAW_LINE #property indicator_color3 Turquoise #property indicator_style3 STYLE_SOLID #property indicator_width3 1 #property indicator_label4 "stoch4" #property indicator_type4 DRAW_LINE #property indicator_color4 LimeGreen #property indicator_style4 STYLE_SOLID #property indicator_width4 1 #define barCount 20000 //--- indicator buffers double stochasChart1[]; double stochasChart2[]; double stochasChart3[]; double stochasChart4[]; double closeBuffer[barCount]; double lowBuffer[barCount]; double highBuffer[barCount]; double out1Buffer[barCount]; double out2Buffer[barCount]; double out3Buffer[barCount]; double out4Buffer[barCount]; #import "D:\\Projects\\Dll_test\\x64\\Debug\\Dll_test.dll" void DllStochasBraid(const int size, const int slow, const int period1, const int period2, const int period3, const int period4, const double& close[], const double& low[], double& high[], double& out1[], double& out2[], double& out3[], double& out4[]); #import //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0, stochasChart1, INDICATOR_DATA); SetIndexBuffer(1, stochasChart2, INDICATOR_DATA); SetIndexBuffer(2, stochasChart3, INDICATOR_DATA); SetIndexBuffer(3, stochasChart4, INDICATOR_DATA); ArraySetAsSeries(stochasChart1, true); ArraySetAsSeries(stochasChart2, true); ArraySetAsSeries(stochasChart3, true); ArraySetAsSeries(stochasChart4, true); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| 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[]) { //--- ArraySetAsSeries(close, true); ArraySetAsSeries(high, true); ArraySetAsSeries(low, true); int size = rates_total - prev_calculated; size = (size > barCount) ? barCount : size; ArrayCopy(closeBuffer, close, 0, 0, size); ArrayCopy(highBuffer, high, 0, 0, size); ArrayCopy(lowBuffer, low, 0, 0, size); DllStochasBraid(size, 3, 9, 14, 38, 62, closeBuffer, lowBuffer, highBuffer, out1Buffer, out2Buffer, out3Buffer, out4Buffer); ArrayCopy(stochasChart1, out1Buffer, 0, 0, size); ArrayCopy(stochasChart2, out2Buffer, 0, 0, size); ArrayCopy(stochasChart3, out3Buffer, 0, 0, size); ArrayCopy(stochasChart4, out4Buffer, 0, 0, size); //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
今回はストキャスティクス4本を表示します。
#property indicator_minimum 0
はチャート表示の最小値、#property indicator_maximum 100
は最大値を指定します。
また、インジケータバッファ、プロット数を4にして、各インジケータの色や種類を指定しています。
#property indicator_separate_window #property indicator_minimum 0 #property indicator_maximum 100 #property indicator_buffers 4 #property indicator_plots 4 //--- plot memConf #property indicator_label1 "stoch1" #property indicator_type1 DRAW_LINE #property indicator_color1 Orange #property indicator_style1 STYLE_SOLID #property indicator_width1 1
そしてDLLとの受け渡しバッファはClose、High、Lowと出力用合わせて7つ用意します。
double closeBuffer[barCount]; double lowBuffer[barCount]; double highBuffer[barCount]; double out1Buffer[barCount]; double out2Buffer[barCount]; double out3Buffer[barCount]; double out4Buffer[barCount];
DLLの呼び出しは、4本分のストキャスティクス用パラメータを指定します。
void DllStochasBraid(const int size, const int slow, const int period1, const int period2, const int period3, const int period4, const double& close[], const double& low[], double& high[], double& out1[], double& out2[], double& out3[], double& out4[]);
MSCodeにコピーして、ビルドをします。
ストキャスティクス4本表示して比べてみましょう。
次回
次回は、またオシレータ系インジケータのRCIを作ってみましょう。