MathTanh関数の働き・役割
MathTanh関数は、指定された数値の双曲線正接(ハイパボリックタンジェント)を計算し、その結果を返します。双曲線正接は、数学や物理学でよく使われる双曲線関数の一つで、特定の範囲(-1から+1)内で値が収まる特徴を持っています。MQL5では、MathTanh関数を利用して、さまざまな数値に対する双曲線正接を求めることが可能です。
また、MathTanh関数の代替として、tanh関数も同様の動作を行います。
双曲線正接とは
双曲線正接(ハイパボリックタンジェント)は、三角関数(角度を基にした関数)の「正接(タンジェント)」に似た性質を持ちますが、双曲線(特定の曲線の一種)に関係する関数です。通常の三角関数が円の形に基づいて計算されるのに対し、双曲線正接は双曲線の形に基づいて計算されます。双曲線正接の値は、以下の数式で求めることができます。
tanh(x) = (e^(2*x) - 1) / (e^(2*x) + 1)
ここで「e」は「ネイピア数(自然対数の底)」と呼ばれる特別な数で、約2.718という値を持っています。この数式は、xの2倍をネイピア数のべき乗としたものから1を引いたものを、同じものに1を加えた値で割ることで、双曲線正接を計算する方法です。
具体的な計算例
いくつかの具体例で、計算の過程を見てみましょう。
例1:x = 1の場合
1を双曲線正接に当てはめて計算してみます。
- e^(2*1) = e^2 ≈ 7.38906
- 分子:7.38906 – 1 = 6.38906
- 分母:7.38906 + 1 = 8.38906
- 6.38906 / 8.38906 ≈ 0.7616
したがって、xが1のとき、双曲線正接の値は約0.7616となります。
例2:x = 0の場合
0を双曲線正接に当てはめて計算してみます。
- e^(2*0) = e^0 = 1(eの0乗は常に1になります)
- 分子:1 – 1 = 0
- 分母:1 + 1 = 2
- 0 / 2 = 0
したがって、xが0のとき、双曲線正接の値は0となります。
例3:x = -1の場合
-1を双曲線正接に当てはめて計算してみます。
- e^(2*(-1)) = e^(-2) ≈ 0.13534
- 分子:0.13534 – 1 = -0.86466
- 分母:0.13534 + 1 = 1.13534
- -0.86466 / 1.13534 ≈ -0.7616
したがって、xが-1のとき、双曲線正接の値は約-0.7616となります。
双曲線正接の性質
双曲線正接は、入力した値がどれだけ大きくなっても、常に-1から+1の範囲に収まる特徴があります。このため、双曲線正接は、データのスケールを抑えたり、値を-1から+1の範囲に制限したい場合などに利用されます。
MathTanh関数の引数について
double MathTanh(
double value // 数値
);
例えば、valueに1.0を指定した場合、MathTanh関数は1.0の双曲線正接の値を計算して返します。この関数は、正の数でも負の数でも任意の実数を受け付け、値が-1から+1の範囲で返されるため、さまざまな数値での計算が可能です。
MathTanh関数の戻り値について
MathTanh関数は、指定された実数の双曲線正接の値を計算し、その結果をdouble型で返します。戻り値の範囲は-1から+1に制限され、どのような数値を入力してもこの範囲を超えることはありません。
例えば、MathTanh関数に1.0を渡した場合、約0.7616という双曲線正接の値が返されます。また、-1.0を渡した場合には、約-0.7616という値が返されます。
MathTanh関数を使ったサンプルコード
#define GRAPH_WIDTH 750 // グラフの幅を750ピクセルに設定
#define GRAPH_HEIGHT 350 // グラフの高さを350ピクセルに設定
#include <Graphics\Graphic.mqh> // グラフィック描画用のライブラリをインクルード
CGraphic ExtGraph; // グラフィックオブジェクトのインスタンスを作成
//+------------------------------------------------------------------+
//| スクリプトプログラム開始関数 |
//+------------------------------------------------------------------+
void OnStart()
{
// deltaベクトルを作成し、2πを100分割した値で初期化
// Fullメソッドを使用して101個の要素を持つベクトルを作成
vector delta = vector::Full(101, 2 * M_PI / 100);
delta[0] = 0; // ベクトルの最初の値を0に設定
//--- deltaステップで0から2πまでの101個の値を累積して取得する
vector X = delta.CumSum(); // deltaの累積値をXに格納
//--- Xベクトルの各値の双曲線正接値を計算する
vector Y = MathTanh(X); // 各Xの双曲線正接をYベクトルに格納
//--- 計算された値をベクトルから配列に転送する
double x_array[], y_array[]; // x座標とy座標の配列を定義
X.Swap(x_array); // Xベクトルの内容をx_arrayに転送
Y.Swap(y_array); // Yベクトルの内容をy_arrayに転送
//--- 計算されたベクトル値のグラフを描画する
CurvePlot(x_array, y_array, clrDodgerBlue); // グラフの曲線を描画
//--- EscapeキーまたはPgDnキーを押してグラフを削除し、終了するまで待機する
while (!IsStopped()) // スクリプトが停止されるまでループ
{
if (StopKeyPressed()) // 停止キーが押されていればループを抜ける
break;
Sleep(16); // CPU負荷を下げるために短時間の待機
}
//--- クリーンアップ
ExtGraph.Destroy(); // グラフィックオブジェクトを破棄
}
//+------------------------------------------------------------------+
//| ESCが押されたら「true」を返す |
//| PgDnが押されたらグラフのスクリーンショットを撮り、「true」を返す |
//| その他の場合は「false」を返す |
//+------------------------------------------------------------------+
bool StopKeyPressed()
{
//--- ESCキーが押されたら「true」を返す
if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) != 0)
return (true);
//--- PgDnが押されたらグラフのスクリーンショットを撮り、「true」を返す
if (TerminalInfoInteger(TERMINAL_KEYSTATE_PAGEDOWN) != 0 &&
MakeAndSaveScreenshot(MQLInfoString(MQL_PROGRAM_NAME) + "_Screenshot"))
return (true);
//--- どちらのキーも押されていなければ「false」を返す
return (false);
}
//+------------------------------------------------------------------+
//| グラフオブジェクトを作成して曲線を描く |
//+------------------------------------------------------------------+
void CurvePlot(double &x_array[], double &y_array[], const color colour)
{
// グラフオブジェクトを作成し、サイズを設定
ExtGraph.Create(ChartID(), "Graphic", 0, 0, 0, GRAPH_WIDTH, GRAPH_HEIGHT);
// 配列の内容で曲線を追加し、色を指定
ExtGraph.CurveAdd(x_array, y_array, ColorToARGB(colour), CURVE_LINES);
// グラフのインデント(上方向の余白)を追加
ExtGraph.IndentUp(30);
// 全ての曲線をプロット
ExtGraph.CurvePlotAll();
// グラフ上に案内テキストを追加
string text1 = "Press ESC to delete the graph and stop the script, or";
string text2 = "Press PgDn to create a screen, delete the graph and stop the script";
ExtGraph.TextAdd(54, 9, text1, ColorToARGB(clrBlack));
ExtGraph.TextAdd(54, 21, text2, ColorToARGB(clrBlack));
// グラフの更新
ExtGraph.Update();
}
//+------------------------------------------------------------------+
//| スクリーンショットを撮り、画像をファイルに保存する |
//+------------------------------------------------------------------+
bool MakeAndSaveScreenshot(const string file_name)
{
// ファイル名リストを格納する配列
string file_names[];
// エラー状態をリセット
ResetLastError();
// 保存するファイルの選択ダイアログを表示し、ファイルが選択された場合に続行
int selected = FileSelectDialog("Save Picture", NULL, "All files (*.*)|*.*", FSD_WRITE_FILE, file_names, file_name + ".png");
if (selected < 1)
{
// エラーが発生した場合はエラーメッセージを出力
if (selected < 0)
PrintFormat("%s: FileSelectDialog() function returned error %d", __FUNCTION__, GetLastError());
return false; // エラーの場合はfalseを返す
}
// スクリーンショットを保存
bool res = false;
if (ChartSetInteger(0, CHART_SHOW, false)) // チャートを一時的に非表示
res = ChartScreenShot(0, file_names[0], GRAPH_WIDTH, GRAPH_HEIGHT);
ChartSetInteger(0, CHART_SHOW, true); // チャートを再表示
return (res); // 成功した場合はtrueを返す
}
このコードは、0から2πまでの範囲を100等分して得られる数値に対して双曲線正接を計算し、その結果をもとにグラフを描画するスクリプトです。
スクリプトを実行すると、計算された双曲線正接の値が表示され、画面に「ESCキーを押して終了」や「PgDnキーでスクリーンショットを撮る」という案内が表示されます。ESCまたはPgDnキーを押すと、グラフが削除され、スクリプトが終了します。PgDnキーを押した場合には、グラフのスクリーンショットも保存されます。
サンプルコード解説1: グローバル領域での定義
#define GRAPH_WIDTH 750 // グラフの幅を設定
#define GRAPH_HEIGHT 350 // グラフの高さを設定
#include <Graphics\Graphic.mqh> // グラフィック描画用のライブラリをインクルード
CGraphic ExtGraph; // CGraphicクラスのインスタンスを作成
定義の詳細
グラフの幅と高さの定義
グラフの幅を750ピクセル(デジタル画像を構成する最小の単位)に、グラフの高さを350ピクセルに設定しています。defineディレクティブを使用して定数を定義することで、コード内でこれらの値を使用する際に簡単に参照できるようになります。
グラフィックライブラリのインクルード
includeディレクティブを使用して、グラフィック関連の機能を提供するライブラリファイル「Graphic.mqh」をインクルードしています。このライブラリには、グラフの描画や曲線の追加など、グラフィック操作に必要な関数やクラスが定義されています。
グラフィックオブジェクトの作成
CGraphicクラスのインスタンスであるExtGraphオブジェクトを作成しています。このインスタンスは、グラフの描画や操作に使用されます。
クラスはオブジェクト指向プログラミングの基本要素であり、特定の機能を持つオブジェクト(変数や配列など)を作成するためのテンプレートです。
サンプルコード解説2:OnStart関数の中その1
//+------------------------------------------------------------------+
//| スクリプトプログラム開始関数 |
//+------------------------------------------------------------------+
void OnStart()
{
// deltaベクトルを作成し、2πを100分割した値で初期化
// Fullメソッドを使用して101個の要素を持つベクトルを作成
vector delta = vector::Full(101, 2 * M_PI / 100);
delta[0] = 0; // ベクトルの最初の値を0に設定
//--- deltaステップで0から2πまでの101個の値を累積して取得する
vector X = delta.CumSum(); // deltaの累積値をXに格納
//--- Xベクトルの各値の双曲線正接値を計算する
vector Y = MathTanh(X); // 各Xの双曲線正接をYベクトルに格納
上記のコードは、OnStart関数内で双曲線正接の値を計算するための準備段階を示しています。
まず、deltaという名前のベクトルを作成します。このベクトルには0から2πまでを100分割した値が格納されます。ここでは、vectorクラスのFullメソッドを使用し、2πを100分割した間隔を持つ101個の要素がdeltaに設定されています。このdeltaベクトルの最初の要素は0に設定され、0から2πまでの間隔をもつ一連の値が準備されます。
次に、deltaベクトルの各要素を累積していくことで、0から2πまでの連続的な値を得たXベクトルを作成します。この操作にはCumSumメソッドを使用し、deltaの累積和をXに格納しています。これにより、Xには0から2πまで増加する101個の値が含まれ、双曲線正接を計算するための基となる値が準備されます。
最後に、Xベクトルの各値について双曲線正接の計算を行い、その結果をYベクトルに格納します。
サンプルコード解説3:OnStart関数の中その2
// ベクトルの計算結果を配列に転送
double x_array[],y_array[];
X.Swap(x_array); // Xベクトルの値をx_array配列に転送
Y.Swap(y_array); // Yベクトルの値をy_array配列に転送
// 計算結果をもとに、グラフを描画する
CurvePlot(x_array, y_array, clrDodgerBlue);
このセクションでは、ベクトルの計算結果を配列に転送し、グラフを描画する手順について解説します。
まず、x_arrayおよびy_arrayと宣言し、x座標とy座標の値を保持する配列を用意しています。次に、XベクトルとYベクトルの計算結果を、それぞれx_arrayとy_arrayという配列に転送しています。この転送にはSwapメソッドが使用され、これによってXベクトルの内容がx_array配列に、Yベクトルの内容がy_array配列に簡単にコピーされます。
その後、CurvePlot関数を使用して、x_arrayとy_arrayの値をもとにグラフを描画しています。CurvePlot関数の引数には描画するデータの配列であるx_arrayとy_array、および色指定のためのclrDodgerBlueが渡され、指定された色でグラフが描かれます。
サンプルコード解説4:OnStart関数部分その3
//--- EscapeキーまたはPgDnキーを押してグラフを削除し、終了するまで待機
while (!IsStopped())
{
if (StopKeyPressed()) // 停止ボタンが押されているかを確認
break;
Sleep(16); // 16ミリ秒待機してから次のループへ
}
//--- グラフィックのクリーンアップ
ExtGraph.Destroy(); // ExtGraphオブジェクトを削除してメモリを解放
}
この部分のコードは、グラフを表示させたまま、ESCキーまたはPgDnキーが押されるのを待機する処理です。
まず、while文でループを開始し、スクリプトが停止されていない間、つまりIsStopped関数がfalseを返す間はループが続きます。ループの中でStopKeyPressed関数が呼ばれ、ESCキーまたはPgDnキーが押されたかを確認します。もし、いずれかのキーが押されている場合、break文によってループを抜け、待機処理を終了します。これにより、ユーザーが任意のタイミングでグラフの表示を終了できるようになっています。
ループ内でSleep関数が16ミリ秒の待機を挟むことで、CPU負荷を軽減しながらキーの入力を定期的に確認します。待機処理が終了すると、グラフのクリーンアップに移ります。ExtGraphインスタンスに対してDestroyメソッドを呼び出し、グラフを破棄して使用していたメモリを解放します。これにより、スクリプトの終了時にリソースが適切に解放されます。
サンプルコード解説5: StopKeyPressed関数(オリジナル関数)部分
//+------------------------------------------------------------------+
//| ESCが押されたら「true」を返す |
//| PgDnが押されたら、グラフのスクリーンショットを撮り、「true」を返す |
//| その他の場合は「false」を返す |
//+------------------------------------------------------------------+
bool StopKeyPressed()
{
// --- ESCが押されたら「true」を返す
if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) != 0)
return(true);
// --- PgDnが押されてグラフのスクリーンショットが正常に取得されたら、「true」を返す
if (TerminalInfoInteger(TERMINAL_KEYSTATE_PAGEDOWN) != 0 && MakeAndSaveScreenshot(MQLInfoString(MQL_PROGRAM_NAME) + "_Screenshot"))
return(true);
// --- その他の場合は「false」を返す
return(false);
}
StopKeyPressed関数は、ESCキーやPgDnキーが押されたかどうかを検出し、特定の動作を行うためのカスタム関数です。この関数は、グラフ表示の終了条件を管理する重要な役割を持っています。
まず、TerminalInfoInteger関数を使用してESCキーの状態を確認しています。引数として、TERMINAL_KEYSTATE_ESCAPEという識別子を指定しています。この識別子は、ESCキーの押下状態を取得するために使用され、キーが押されている場合には非ゼロの値が返されます。もし非ゼロが返された場合、関数はtrueを返し、スクリプト内でグラフの表示を終了させることができます。
次に、PgDnキーが押されているかどうかを確認しています。この場合もTerminalInfoInteger関数を使用しており、引数としてTERMINAL_KEYSTATE_PAGEDOWNという識別子を指定しています。この識別子は、PgDnキーの押下状態を取得するために使用され、押されていれば非ゼロが返されます。PgDnキーが押されているときには、さらにMakeAndSaveScreenshot関数を呼び出してスクリーンショットをファイルに保存します。
MakeAndSaveScreenshot関数には、スクリーンショットのファイル名を指定するための文字列が引数として渡されています。この文字列は、MQLInfoString関数を使用して生成されています。MQLInfoString関数の引数には、MQL_PROGRAM_NAMEという識別子が指定されており、これによって現在のスクリプト名が取得されます。スクリーンショットのファイル名には、このスクリプト名に「_Screenshot」という文字列を追加し、ファイルが保存されます。
スクリーンショットの保存に成功した場合にはtrueが返され、PgDnキーによる終了動作とスクリーンショットの保存が同時に行われます。いずれのキーも押されていない場合にはfalseが返され、スクリプトは実行を続行します。この構造により、ESCまたはPgDnが押されるまでグラフを表示し、必要に応じてスクリーンショットを保存してからスクリプトを終了する動作が可能になります。
サンプルコード解説6:CurvePlot関数(オリジナル関数)部分
//+------------------------------------------------------------------+
//| グラフオブジェクトを作成して曲線を描画 |
//+------------------------------------------------------------------+
void CurvePlot(double &x_array[], double &y_array[], const color colour)
{
// グラフオブジェクトを作成(チャートID、名前、座標などを設定)
ExtGraph.Create(ChartID(), "Graphic", 0, 0, 0, GRAPH_WIDTH, GRAPH_HEIGHT);
// カーブ(曲線)を追加し、色とラインの種類を指定
ExtGraph.CurveAdd(x_array, y_array, ColorToARGB(colour), CURVE_LINES);
// テキストのインデント位置を少し上に設定
ExtGraph.IndentUp(30);
// すべての曲線を描画
ExtGraph.CurvePlotAll();
// ESCキーとPgDnキーに関する操作方法の説明を追加
string text1 = "Press ESC to delete the graph and stop the script, or";
string text2 = "Press PgDn to create a screen, delete the graph and stop the script";
ExtGraph.TextAdd(54, 9, text1, ColorToARGB(clrBlack));
ExtGraph.TextAdd(54, 21, text2, ColorToARGB(clrBlack));
// グラフの更新
ExtGraph.Update();
}
CurvePlot関数は、渡された配列データをもとにグラフを作成し、指定した色で曲線を描画するためのカスタム関数です。この関数には、x軸とy軸のデータ配列、および曲線の色を指定するための引数が含まれています。
最初に、ExtGraphインスタンスのCreateメソッドを使用してグラフを作成しています。Createメソッドの引数には、ChartID、グラフの名前(”Graphic”)、座標(0, 0)、および幅と高さ(GRAPH_WIDTHとGRAPH_HEIGHT)が指定されています。ChartID関数は、現在のチャートIDを取得する関数で、これにより生成されたグラフは現在のチャートに描画されます。
次に、ExtGraphインスタンスのCurveAddメソッドを使用して、x軸とy軸の配列データをもとに曲線を追加します。CurveAddメソッドの引数には、x_arrayとy_arrayの配列、指定した色をARGB形式に変換するためのColorToARGB関数、そして曲線のスタイル(CURVE_LINES)が渡されています。この処理によって、指定の色とスタイルで曲線が描画されます。
続いて、IndentUpメソッドを使用してグラフの上部に30ピクセル(デジタル画像を構成する最小の単位)の空白を追加しています。これにより、グラフ上に余白が確保され、グラフが画面に適切に配置されるようになります。
その後、CurvePlotAllメソッドを使用して、追加した曲線をグラフに描画しています。
さらに、グラフの操作方法についての説明文を追加しています。text1およびtext2という文字列には、それぞれ「ESCキーでグラフを削除してスクリプトを停止する」「PgDnキーでスクリーンショットを作成してからグラフを削除し、スクリプトを停止する」という内容の説明が含まれています。TextAddメソッドを使って、これらのテキストを画面の指定位置(x=54, y=9 と x=54, y=21)に描画し、説明が表示されるようにしています。
また、色の指定にはColorToARGB関数を使用しています。ColorToARGB関数は、指定された色をARGB(Alpha、Red、Green、Blue)形式に変換し、透過度や色の設定が反映されるようにします。これにより、TextAddメソッドで追加するテキストや曲線が指定の色で正しく表示されます。
最後に、Updateメソッドを呼び出してグラフの描画を更新し、設定したデータやテキストを反映させます。この一連の処理により、x軸とy軸のデータに基づく曲線が描画され、操作の説明が表示されたグラフが完成します。
MathTanh関数を使ってEAを作る際のアイディア
ボラティリティの判定指標として利用
MathTanh関数は、入力した値が大きくなっても-1から+1の範囲内に収まるため、価格変動のボラティリティを一定のスケールで評価する指標として利用できます。たとえば、価格の変動をMathTanh関数で正規化し、その結果を基にエントリーやエグジットの判断を行うEAを作成することで、ボラティリティが急上昇するポイントでのトレード判断が可能になります。
トレンドの転換を検出するインジケータとして
MathTanh関数の特性を使い、価格変動の双曲線正接を算出し、トレンドの強弱や転換点を検出するインジケータを構築することができます。値が1や-1に近づくことでトレンドのピークやボトムを示唆するため、これらのポイントでエントリーや決済を行うEAを作成することが考えられます。
リスク管理のための数値正規化
リスク管理のために、価格やボラティリティを双曲線正接で正規化し、極端な値に影響されない形でリスクを評価することが可能です。これにより、ポジションサイズやエントリータイミングをリスクに応じて調整し、損失のリスクを低減するEAを構築できます。
他のインジケータとの組み合わせによるシグナル精度向上
MathTanh関数で価格の変動幅を抑えた値を得ることで、他のインジケータと組み合わせたトレードシグナルの精度を向上させることができます。たとえば、RSIや移動平均線と組み合わせることで、トレンドフォローや逆張りの精度を上げるトレードロジックを実現できるでしょう。