English Русский 中文 Español Deutsch Português
preview
ウィリアム・ギャンの手法(第1回):ギャンアングルインジケーターの作成

ウィリアム・ギャンの手法(第1回):ギャンアングルインジケーターの作成

MetaTrader 5トレーディング |
212 18
Yevgeniy Koshtenko
Yevgeniy Koshtenko

はじめに

ウィリアム・デルバート・ギャンは、伝説的なトレーダーであり、優れたテクニカルアナリストとして知られています。彼の革新的な市場分析手法は、現代のトレーダーからもなお高い関心を集めています。ギャンの分析ツールの中でも特に重要なのが、価格変動を予測し、潜在的なサポートおよびレジスタンスレベルを特定するために用いられる「ギャンアングル」です。

本記事では、MQL5を用いてギャンアングルインジケーターを作成し、ウィリアム・ギャンの取引手法の世界に踏み込んでいきます。このツールの理論的背景を詳しく解説し、MetaTrader 5プラットフォームでカスタムインジケーターとして段階的に実装する方法を紹介します。

新たな分析ツールを求める経験豊富なトレーダーの方も、テクニカル指標の幅を広げたい初心者の方も、本記事を通じてウィリアム・ギャンの最も興味深い手法の一つを深く理解し、実際の取引に活用する手助けとなれば幸いです。


ギャンアングル作成の歴史

ウィリアム・デルバート・ギャン(1878~1955)は、市場の動きを長年研究し、時間と価格の関係に関する独自の理解をもとに、20世紀初頭に独自の角度分析システムを開発しました。

ギャンは、市場の動きには予測可能な幾何学的パターンが存在し、それらを数学、幾何学、さらには占星術を組み合わせることで予測できると考えていました。彼は、時間と価格の動きが完璧に調和した状態を示す「角度」という概念を考案し、チャート上に対角線として描くことで市場の動向を分析しました。

ギャン理論の中心となるのは、45度の角度(1×1アングル)が時間と価格の完全なバランスを示すという考え方です。彼は、価格がこの角度に沿って上昇または下降する場合、市場は安定したバランスの取れたトレンドを維持すると考えました。

さらに、ギャンは2×1、3×1、4×1といった異なる比率の角度や、その逆数を用いて、時間と価格のさまざまな関係を表現しました。これらの視点は、彼の取引システムや市場分析の基盤となっています。

ギャンの研究の一部は今なお議論の余地があるものの、彼が生み出したギャンアングルをはじめとする手法は、現在でも世界中のトレーダーやアナリストの関心を集め続けており、現代の取引においても重要な役割を果たしています。


ギャンアングル理論とテクニカル分析におけるその重要性

ギャンアングル理論は、市場の動きがチャート上に描かれる特定の角度のプロットを用いて識別できる予測可能な幾何学的パターンに従うという考えに基づいています。この理論の根幹には、時間と価格のバランスという概念があり、1期間あたり1単位の価格変動を前提とした1×1の角度(45度)が、完全な均衡を表すとされています。

ギャンはさらに、2×1、3×1、4×1といったさまざまな角度や、それらの逆数を用いたシステムを開発しました。これらの角度は、時間と価格の動きの特定の関係を反映しており、市場のトレンドを分析する際の指標となります。これらの角度は動的なサポートおよびレジスタンスレベルとして機能し、トレーダーがトレンドの強さや方向を判断するのに役立ちます。一般に、角度が急であるほどトレンドが強いことを示し、逆に角度が緩やかであるほどトレンドの勢いが弱いことを示します。


ギャンアングル構築の基本原則


ギャンアングルの構築は、トレーダーがテクニカル分析でこのツールを効果的に活用できるようにするためのいくつかの重要な原則に基づいています。最も重要なのは、開始点の選択です。通常、この開始点はチャート上の重要な最小値または最大値から選ばれます。角度の構築はこの選ばれた点から始まります。

基本的な角度は、チャート上で45度の線を形成する1×1角度です。この角度は、時間と価格の完璧なバランスを反映しており、価格が1期間あたり1単位変化することを示します。2×1、3×1、4×1などの他の角度やその逆数は、この基本角度を基にして構築されます。

プロットをおこなう際には、チャートのスケールを考慮することが重要です。トレーダーは、正確な角度を確保するために特別なテンプレートやツールを使用することが多いです。ギャンアングルの線は未来に向かって延びるため、これらの線を利用して潜在的なサポートおよびレジスタンスのレベルを予測することができます。


ギャンアングルの種類とその解釈

ウィリアム・ギャンは、テクニカル分析において、それぞれ独自の意味と解釈を持つ角度のシステムを開発しました。中でも、1x1(45度)は最も基本的な角度とされ、時間と価格のバランスを反映しています。この角度は、トレンドの強さを評価するための基準となり、重要なガイドラインとして機能します。

2x1の角度(63.75度)は、価格が時間の2倍の速さで上昇していることを示し、これは多くの場合、強い強気トレンドの兆候として解釈されます。対照的に、1x2の角度(26.25度)は、価格の上昇が時間に対して遅いことを示し、トレンドが弱まっている可能性があることを示唆しています。

3x1(71.25度)と4x1(75度)はより積極的な価格変動を示し、通常、非常に強いトレンドや市場の過熱を示唆します。それに対して、1x3(18.75度)と1x4(15度)の角度は、より平坦な傾きとなり、これらの角度は強いサポートや抵抗を示している可能性があります。

ギャンアングルの解釈は、その角度の傾斜だけにとどまりません。価格がこれらの角度線とどのように相互作用するかを考慮することも重要です。価格が角度線を横切る場合、トレンドの潜在的な変化を示唆することがあります。また、価格が角度線に沿って動く場合、その動きは現在のトレンドの強さを確認するものと解釈されることが一般的です。


取引におけるギャンアングルの実用的応用

トレーダーは、トレンドの特定からポジションのエントリーポイントやエグジットポイントの選択に至るまで、さまざまな目的でギャンアングルを活用します。

トレンドを判断するためには、まず重要な最小値または最大値から1x1の角度をプロットします。価格がこのラインより上に動く場合は、上昇トレンドが示唆され、逆に下に動く場合は下降トレンドを示唆します。また、2x1や3x1などの急角度のラインは、トレンドの強さを確認するための指標として使用されます。

エントリーポイントを決定する際、多くのトレーダーは価格がギャンアングルラインを突破する瞬間や、反発するタイミングを注視します。例えば、価格が上昇して1x1ラインで反発する場合、それはポジションに入る潜在的な機会として捉えられることがあります。

リスク管理においても、ギャンアングルはよく使用されます。トレーダーは、ロングポジションの場合、最も近い角度ラインのすぐ下にストップロスを設定することができ、ショートポジションの場合はそのすぐ上にストップロスを設定することができます。

長期的な取引では、ギャンアングルは市場全体の方向性を決定するのに有効です。1x2や1x4などの浅い角度を用いることで、長期的なトレンドを評価し、戦略的な決定を下すための手助けとなります。


ギャンアングルを使った取引戦略の例

ギャンアングルは、トレーダーにさまざまな取引戦略を作成するための幅広いオプションを提供します。実際の取引で効果的に使用できる方法の例をいくつか示します。

アングルバウンス戦略は、ギャンアングルラインがサポートレベルまたはレジスタンスレベルとして機能することが多いという仮定に基づいています。トレーダーは、価格がギャンアングルライン(特に1x1または2x1)に近づき、そこから反発する状況を探します。ポジションへのエントリーは、ローソク足の反転パターンの形成など、リバウンドの確認後に実行されます。

もう一つの人気のある戦略は、アングルブレイクアウトです。ここでトレーダーは、特に取引量の増加を伴う場合、価格が重要なギャンアングルラインを突破するのを待ちます。上向きのブレイクアウトは潜在的なロングポジションのシグナルとなる可能性があり、下向きのブレイクアウトはショートポジションのシグナルとなる可能性があります。

ギャンファン戦略では、単一の点から放射状に広がる複数の角度を使用して扇形の構造を形成します。トレーダーは、価格がさまざまなファンラインとどのように相互作用するかを分析し、これを使用してサポート、レジスタンスレベル、および潜在的な反転ポイントを決定します。

角度と時間サイクルを組み合わせるのは、トレーダーがギャンアングルと、同じくギャンによって開発された時間サイクルの概念を組み合わせる、より複雑な戦略です。ここでは、重要なタイムラインとギャンアングルの交点が分析され、市場への参入または退出の重要な瞬間が決定されます。

多時間枠戦略では、異なる時間枠でギャンアングルを分析します。たとえば、トレーダーは日足チャートで1x1の角度を使用して全体的な傾向を判断し、次に時間足チャートに切り替えて、より急な角度を使用してエントリーポイントを探す場合があります。


MQL5でギャンアングルインジケーターを作成する基本的な手順


MQL5でギャンアングルインジケーターを作成するには、いくつかの重要な手順が必要です。このプロセスでは、ギャンアングルの構築の原則とMetaTrader 5環境でのプログラミングの詳細の両方を理解する必要があります。

最初のステップは、インジケーターの構造を定義することです。ここでは、インジケーター名、角度を設定するための入力パラメーター、必要なライブラリなどの基本的なパラメーターを設定します。

ギャンアングルを構築するための主なロジックは、OnCalculate()関数にあります。ここでは、角度をプロットするための開始点を定義し、各角度の座標を計算し、チャートに線を描画します。

重要な点は、チャートのスケールと選択した時間間隔を考慮して、角度の座標を正しく計算することです。これには、正確な数学的アプローチと、ギャンアングルの幾何学の理解が必要です。

最後の段階は、インジケーターのテストとデバッグです。異なる時間枠と商品における角度の構築の妥当性を確認する必要があります。


インジケーターコード構造

以下は、MetaTrader 5で使用できるギャンアングルインジケーターの基本コードです。

#property copyright "Copyright 2024, Evgeniy Shtenco"
#property link      "https://www.mql5.com/ja/users/koshtenko"
#property version   "1.00"
#property indicator_chart_window

// Input parameters
input datetime StartDate = D'2023.01.01 00:00'; // Start date for analysis
input datetime EndDate = D'2023.12.31 23:59';   // End date for analysis
input color GannFanColor = clrBlue;             // Color for Gann Fan lines

// Global variables
double extremumPrice;
datetime extremumTime;
double oppositeExtremumPrice;
datetime oppositeExtremumTime;
bool isTrendUp;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    ObjectsDeleteAll(0, "GannFan_");
    ObjectsDeleteAll(0, "OppositeGannFan_");
}

//+------------------------------------------------------------------+
//| 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[])
{
    if(rates_total < 1) return(0);

    // Clear previous objects
    if (prev_calculated == 0)
    {
        ObjectsDeleteAll(0, "GannFan_");
        ObjectsDeleteAll(0, "OppositeGannFan_");
    }

    // Find extremums within the specified date range
    FindExtremums(rates_total, high, low, time);

    // Draw Gann Fans
    DrawGannFan(extremumPrice, extremumTime);
    DrawOppositeGannFan(oppositeExtremumPrice, oppositeExtremumTime);

    return(rates_total);
}

//+------------------------------------------------------------------+
//| Find both extremums within the specified date range              |
//+------------------------------------------------------------------+
void FindExtremums(const int rates_total, const double &high[], const double &low[], const datetime &time[])
{
    int startIndex = -1;
    int endIndex = -1;

    for (int i = 0; i < rates_total; i++)
    {
        if (time[i] >= StartDate && startIndex == -1)
        {
            startIndex = i;
        }
        if (time[i] <= EndDate)
        {
            endIndex = i;
        }
    }

    if (startIndex == -1 || endIndex == -1 || startIndex > endIndex)
    {
        Print("Error: Invalid date range or no data available in the specified range");
        return;
    }

    int highestIndex = ArrayMaximum(high, startIndex, endIndex - startIndex + 1);
    int lowestIndex = ArrayMinimum(low, startIndex, endIndex - startIndex + 1);

    // Determine the most recent extremum
    if (time[highestIndex] > time[lowestIndex])
    {
        extremumPrice = high[highestIndex];
        extremumTime = time[highestIndex];
        oppositeExtremumPrice = low[lowestIndex];
        oppositeExtremumTime = time[lowestIndex];
        isTrendUp = false;
    }
    else
    {
        extremumPrice = low[lowestIndex];
        extremumTime = time[lowestIndex];
        oppositeExtremumPrice = high[highestIndex];
        oppositeExtremumTime = time[highestIndex];
        isTrendUp = true;
    }
}

//+------------------------------------------------------------------+
//| Draw Gann Fan                                                    |
//+------------------------------------------------------------------+
void DrawGannFan(double extremum, datetime extremumTime)
{
    double angles[] = {82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = {"1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    datetime endTime = extremumTime + PeriodSeconds() * 300;

    for(int i = 0; i < ArraySize(angles); i++)
    {
        string label = "GannFan_" + angleNames[i];
        double angle = angles[i];
        
        double priceShift = MathTan(angle * M_PI / 180.0) * 300 * _Point;
        double endPrice;
        
        if(isTrendUp)
        {
            endPrice = extremum + priceShift;
        }
        else
        {
            endPrice = extremum - priceShift;
            angle = -angle; // Invert the angle for a downtrend
        }

        if(ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, endTime, endPrice))
        {
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Gann Fan " + angleNames[i]);
        }
        else
        {
            Print("Failed to create Gann Fan line: ", GetLastError());
        }
    }
}

//+------------------------------------------------------------------+
//| Draw Opposite Gann Fan                                           |
//+------------------------------------------------------------------+
void DrawOppositeGannFan(double extremum, datetime extremumTime)
{
    double angles[] = {82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = {"1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    datetime endTime = extremumTime + PeriodSeconds() * 300;

    for(int i = 0; i < ArraySize(angles); i++)
    {
        string label = "OppositeGannFan_" + angleNames[i];
        double angle = angles[i];
        
        double priceShift = MathTan(angle * M_PI / 180.0) * 300 * _Point;
        double endPrice;
        
        if(!isTrendUp) // Opposite trend
        {
            endPrice = extremum + priceShift;
        }
        else
        {
            endPrice = extremum - priceShift;
            angle = -angle; // Invert the angle for a downtrend
        }

        if(ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, endTime, endPrice))
        {
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Opposite Gann Fan " + angleNames[i]);
        }
        else
        {
            Print("Failed to create Opposite Gann Fan line: ", GetLastError());
        }
    }
}

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
    // Redraw objects when chart changes
    if(id == CHARTEVENT_CHART_CHANGE)
    {
        // Find extremums and redraw Gann Fans
        int rates_total = Bars(_Symbol, PERIOD_CURRENT);
        double high[], low[];
        datetime time[];
        ArraySetAsSeries(high, true);
        ArraySetAsSeries(low, true);
        ArraySetAsSeries(time, true);
        CopyHigh(_Symbol, PERIOD_CURRENT, 0, rates_total, high);
        CopyLow(_Symbol, PERIOD_CURRENT, 0, rates_total, low);
        CopyTime(_Symbol, PERIOD_CURRENT, 0, rates_total, time);
        
        FindExtremums(rates_total, high, low, time);
        DrawGannFan(extremumPrice, extremumTime);
        DrawOppositeGannFan(oppositeExtremumPrice, oppositeExtremumTime);
    }
}


主な関数とその目的

このコードは、チャート上にギャンファン角度を描画するMetaTrader 5インジケーターです。主な機能とその目的の説明は次のとおりです。

  1. OnInit()はインジケーターの初期化関数です。この場合、単に成功した初期化結果を返します。
  2. OnDeinit()は、インジケーターがチャートから削除されたときに、インジケーターによって作成されたすべてのオブジェクトを削除する初期化解除関数です。
  3. OnCalculate()はインジケーターの主な機能です。ティックごとに呼び出されます。以前のオブジェクトをクリアし、指定された日付範囲内の極値を見つけ、ギャンアングルを描画します。
  4. FindExtremums()は、指定された日付範囲内で価格の極値(最大値と最小値)を見つける関数です。どの極値がより最近のものかを判断し、トレンドの方向を確立します。
  5. DrawGannFan()は、見つかった極値からメインのギャンファンを描画する関数です。9つの異なる角度の線を作成します。
  6. DrawOppositeGannFan()は、別の極値から反対のギャンファンを描画する関数です。また、9つの角度の線も作成しますが、方向は逆になります。
  7. OnChartEvent()はチャートイベントに応答する関数です。この場合、チャートが変化するとギャンファンが再描画されます。

このインジケーターは入力を使用して、分析の日付範囲(StartDateとEndDate)と線の色(GannFanColor)を設定します。この範囲内で価格の極値を見つけ、トレンドの方向を決定し、2つのギャンファン(1つは最後の極値から、もう1つは反対の極値から)を描画します。各ファンは、異なるギャンアングル(82.5°、75°、71.25°、63.75°、45°、26.25°、18.75°、15°、7.5°)に対応する9本の線で構成されています。

コードにはエラー処理やチャートが変更されたときの動的な更新も含まれており、非常に堅牢でさまざまな市場状況に適応できます。ArrayMaximum()やArrayMinimum()などのMQL5関数を使用すると、効率的なデータ処理が保証されます。

ギャンアングル計算アルゴリズム

このインジケーターのギャンアングルを計算するアルゴリズムは、極値点からの線の幾何学的構築に基づいています。このアルゴリズムの主な側面は次のとおりです。

  • 極値の特定:このインジケーターは、指定された時間範囲内の最高価格と最低価格を検出します。これらの極端な値のうち、後者はメインのギャンファンの開始点として使用され、前者は反対のファンの開始点として使用されます。
  • 角度セット:固定角度セットが使用されます。82.5°、75°、71.25°、63.75°、45°、26.25°、18.75°、15°、7.5°。これらの角度は、従来のギャン比率に対応します。1x8、1x4、1x3、1x2、1x1、2x1、3x1、4x1、8x1。
  • 終点の計算:角度ごとに、線の終点が計算されます。計算は次の式に基づいています。
endPrice = extremum + MathTan(angle * M_PI / 180.0) * 300 * Point
  • ここで、300は、線を構築するために使用される従来の先行バーの数です。
  • 下降トレンドの反転:トレンドが下向きの場合、角度が反転し(符号が変わり)、線は極値から下向きになります。
  • ライン構築:各角度に対して、極値点から計算された終点までの線オブジェクト(OBJ_TREND)が作成されます。将来のデータをカバーするために、線は右に延長されます。
  • ダブルファン:アルゴリズムは2回適用されます。1回目は最後の極値からのメインファンに対して、2回目は最初の極値からの反対のファンに対して適用されます。これにより、両側の潜在的なサポートレベルとレジスタンスレベルを視覚化できます。
  • 動的更新:チャートが変更されると(たとえば、新しいデータが到着した場合)、アルゴリズムは極値を再計算してファンを再構築し、分析が最新の状態になるようにします。

このアルゴリズムにより、チャート上で古典的なギャンアングルを視覚化することができ、トレーダーに潜在的なサポート、レジスタンスレベル、トレンドの方向を分析するツールが提供されます。 


利益を上げて取引することは可能か

ギャンアングルを使用して利益を上げて取引することは可能でしょうか。この質問には明確な答えはありませんが、適切なアプローチをとれば、利益を生む取引は十分に可能です。成功の鍵は、このツールを総合的に活用することにあります。

しかし、どんなに注意深く綿密な分析を行ったとしても、リスク管理を忘れてはなりません。これが利益を生む取引の基礎となります。100%の成功を保証する方法はないので、適切な資本とリスク管理が長期的な収益性に大きな役割を果たします。


ギャンアングルベースEA作成の見通し


ギャンアングルに基づいたEA(エキスパートアドバイザー)を作成することは、アルゴリズム取引システムの開発者にとって興味深く有望なタスクです。このようなEAは、ギャンの理論に定められた原則を使用して分析と取引を自動化できます。

このようなEAの基礎は、すでに実装されているギャンアングルインジケーターになります。EAアルゴリズムには、価格とギャンラインの相互作用の分析、これらのラインの交点に基づくエントリーポイントとエグジットポイントの決定、取引量や市場のボラティリティなどの追加要因の考慮などが含まれる場合があります。

ギャンアングルに基づく自動化システムの主な利点の1つは、取引の意思決定プロセスから感情的な要素を排除できることです。EAは、人間のトレーダーの決定にしばしば影響を与える恐怖や貪欲に屈することなく、与えられた戦略に厳密に従うことができます。

ただし、このようなEAの開発には多くの課題が伴います。まず第一に、ギャンアングルによって生成される信号を正確に解釈する必要があります。ギャン理論は主観的な部分が多く、市場に対する深い理解が必要であり、アルゴリズムの形で完全に実装するのは困難です。

もちろん、このようなEAの成功は、開発者によるギャン理論の理解の深さと、この理論を市場分析やリスク管理の最新の方法と効果的に組み合わせる能力に大きく依存します。


最大の課題:スケーリング角度

ギャンアングルに基づいたインジケーターとEAを作成して使用する場合の最も深刻な問題の1つは、スケーリングが難しいことです。この問題は、ギャン法に基づく取引システムの精度と効率に重大な影響を及ぼします。

問題の本質は、ギャンアングルが幾何学的構成であるため、チャートのスケールに大きく依存しているということです。時間軸や価格スケールのスケールを変更すると、角度の視覚的な表現が著しく歪む場合があります。あるスケールでは完璧な1x1(45度)の角度に見えても、スケールを変更するとまったく異なる角度になる場合があります。

これにより、ソフトウェアの実装に重大な困難が生じます。インジケーターまたはEAは、チャートの現在のスケールを常に考慮し、それに応じて角度の計算を調整する必要があります。さらに、ギャンアングルのベースとなる「時間単位は価格単位に等しい」という概念自体が、異なる金融商品や時間枠を扱う場合には曖昧になります。

この問題を解決しようとすると、妥協につながることがよくあります。一部の開発者はスケールを固定しますが、これによりツールの適用範囲が制限されます。他にも、角度を再計算するための複雑なアルゴリズムを導入するものがあり、これによりインジケーターやEAの速度が低下する可能性があります。

さらに、スケーリングの問題により、異なるツールや時間枠間での分析結果の比較が困難になります。ある通貨ペアの日足チャートで効果的に機能する角度が、時間足チャートや他の取引商品ではまったく異なる結果を生み出す可能性があります。

この問題は、自動取引におけるギャンアングルの普遍的な適用性に疑問を投げかけます。開発者は、ギャン理論だけでなく、取引プラットフォームでのチャートの操作の詳細についても深く理解している必要があります。


結論

ギャンアングルは、トレーダーや取引システム開発者から今なお高い注目を集める、独自のテクニカル分析ツールです。本記事のレビューを通じて、MQL5を用いたギャンアングルインジケーターの作成は十分に実現可能であり、提供したコードがさらなる開発のための良い出発点となることが示されました。

しかし、自動取引にギャンアングルを活用する際には、いくつかの重要な課題が伴います。特にスケーリングの問題は大きく、この手法を基に汎用性と信頼性の高い取引EAを構築することは容易ではありません。

それでもなお、市場分析ツールとしてのギャンアングルの可能性は依然として高く、他のテクニカル分析手法や適切なリスク管理と組み合わせることで、トレーダーの武器として有効に活用できるでしょう。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/15556

添付されたファイル |
最後のコメント | ディスカッションに移動 (18)
Bogard_11
Bogard_11 | 15 8月 2024 において 18:56
Eva-oren #:
ガンは優れた貿易商であり、占星術師であり、数秘術師であり、魔法の数字を信じる数学者であった。第一次世界大戦と第二次世界大戦の始まりと終わりを予言した偉大な予言者である。膨大な数の弟子がいたが、彼の信奉者たちが主張するように、彼は誰にも自分の戦略を教えなかった。大金を手にし、その生涯の最後には100,000ドルという ささやかな金額を手にした。ガンの天才的なパーソナリティに関する次の記事を楽しみにしている。

言い忘れたが、彼は当時としては珍しい自家用ジェット機を持っていた。当時のプラス10万 ドルは、今なら10 倍とは言わないまでも、少なくとも1.5倍の緑だ。

追伸:彼はその戦略を伝えた。彼の著作の中で。誰が望んだのか、完全版TCのさまざまな章から集めた。ガンは、誰もタダで手に入れられないように、それをすべてばらまいた。

Ivan Butko
Ivan Butko | 21 8月 2024 において 17:11
グーグルで取引する方法を発見

Maxim Kuznetsov
Maxim Kuznetsov | 22 8月 2024 において 03:16
Ivan Butko #:
グーグル で取引する方法を見つけた。

2枚目の写真、原理がよくわからない。

Bogard_11
Bogard_11 | 22 8月 2024 において 06:58

写真をあげよう。ガンを理解している人なら、コーナーワークの原則、ロングエントリーする場所、ロールオーバーする場所をすぐに理解できるだろう。


Avatar2025
Avatar2025 | 25 6月 2025 において 09:50
免責事項:私はインジケータのMQL5プログラミング構文を知りません。

しかし、角度線のアルゴリズムは正しくないと思います(別のソフトウェアで書いた角度線インジケータを添付しています)。以下はDeepSeekとの対話 です

下面代码是通达信的代码,里面计算斜率的方法才是正确的,请阅读理解后,把上面priceShift 的计算方法改为下列代码正确的范式:

涨周期数:= IF(低点k位置 > 高点k位置, 低点k位置 - 高点k位置 + 1, 低点k位置), NODRAW;
跌周期数:= IF(高点k位置 > 低点k位置, 高点k位置 - 低点k位置 + 1, 高点k位置), NODRAW;

天线:= CONST(IF(高点k位置 = 1, H, REF(H, 高点k位置 - 1))), NODRAW;
地线:= CONST(IF(低点k位置 = 1, L, REF(L, 低点k位置 - 1))), NODRAW;

上涨天数:= IF(ISVALID(地线), BARSLAST(L = 地线), DRAWNULL), NODRAW;
下跌天数:= IF(ISVALID(天线), BARSLAST(H = 天线), DRAWNULL), NODRAW;

上涨高度:= IF(低点k位置 > 高点k位置, 天线 - 地线, HHV(H, 上涨天数) - 地线), NODRAW;
下跌高度:= IF(高点k位置 > 低点k位置, 天线 - 地线, 天线 - LLV(L, 下跌天数)), NODRAW;

上涨斜率:= IF(上涨天数 > 0, ROUND2(上涨高度 / 涨周期数, 4), 0), NODRAW;
下跌斜率:= IF(下跌天数 > 0, ROUND2(下跌高度 / 跌周期数, 4), 0), NODRAW;

しかし、DeepSeekは私には機能しないような修正コードを教えてくれました:
//+------------------------------------------------------------------+
| ベン・ファン・ラインのプロット&nbsp;||ベンファン線をプロットする
//+------------------------------------------------------------------+
void DrawGannFan(double extremum, datetime extremumTime)
{
    // ギャン角度とそれに対応する名前を定義する。
    double angles[] = {82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = {"1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    // 極点から現在のK線までの期間数を取得する
    int extremumBar = iBarShift(_Symbol, PERIOD_CURRENT, extremumTime);
    int currentBar = 0; // 現在のKラインは0
    int barDiff = currentBar - extremumBar; // サイクル番号の違い
    
    // 価格の高低差を計算する
    double priceDiff;
    if(isTrendUp)
    {
        // 上昇トレンド: 最安値から現在の最高値までの高さを計算。
        double currentHigh = iHigh(_Symbol, PERIOD_CURRENT, 0);
        priceDiff = currentHigh - extremum;
    }
    else
    {
        // 下降トレンド:極端な高値から現在の安値までの高さを計算する。
        double currentLow = iLow(_Symbol, PERIOD_CURRENT, 0);
        priceDiff = extremum - currentLow;
    }
    
    // ベースの傾き(1x1直線の傾き)を計算する。
    double baseSlope = (barDiff > 0) ? priceDiff / barDiff : 0;
    
    // 各角度にセクター線を引く
    for(int i = 0; i < ArraySize(angles); i++)
    {
        string label = "GannFan_" + angleNames[i];  // オブジェクト・ラベル
        double angle = angles[i];                  // 現在の角度
        
        // 角度に基づいて勾配倍率を計算する。
        double slopeMultiplier = MathTan(angle * M_PI / 180.0) / MathTan(45 * M_PI / 180.0);
        
        // 価格のオフセットを計算する。
        double priceShift = baseSlope * barDiff * slopeMultiplier * _Point;
        double endPrice;
        
        // トレンド方向に基づく終値の計算
        if(isTrendUp)
        {
            endPrice = extremum + priceShift;
        }
        else
        {
            endPrice = extremum - priceShift;
            angle = -angle; // 下降トレンドの反転角度
        }

        // トレンドラインオブジェクトを作成する
        if(ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, TimeCurrent(), endPrice))
        {
            // トレンドラインのプロパティを設定する
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Gann Fan " + angleNames[i]);
        }
        else
        {
            Print("Failed to create Gann Fan line: ", GetLastError());
        }
    }
}

//+------------------------------------------------------------------+
//|| 逆ギャンファンラインのプロットnbsp; &nbsp; ||
//+------------------------------------------------------------------+
void DrawOppositeGannFan(double extremum, datetime extremumTime)
{
    // ギャン角度とそれに対応する名前を定義する。
    double angles[] = {82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = {"1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    // 極点から現在のK線までの期間数を取得する
    int extremumBar = iBarShift(_Symbol, PERIOD_CURRENT, extremumTime);
    int currentBar = 0; // 現在のKラインは0
    int barDiff = currentBar - extremumBar; // サイクル番号の違い
    
    // 価格の高低差を計算する
    double priceDiff;
    if(!isTrendUp)
    {
        // 極端な安値から現在の最高値までの高さを計算する。
        double currentHigh = iHigh(_Symbol, PERIOD_CURRENT, 0);
        priceDiff = currentHigh - extremum;
    }
    else
    {
        // 逆トレンド(下向き):極端な高値から現在の安値までの高さを計算する。
        double currentLow = iLow(_Symbol, PERIOD_CURRENT, 0);
        priceDiff = extremum - currentLow;
    }
    
    // ベースの傾き(1x1直線の傾き)を計算する。
    double baseSlope = (barDiff > 0) ? priceDiff / barDiff : 0;
    
    // 各角度にセクター線を引く
    for(int i = 0; i < ArraySize(angles); i++)
    {
        string label = "OppositeGannFan_" + angleNames[i];  // オブジェクト・ラベル
        double angle = angles[i];                          // 現在の角度
        
        // 角度に基づいて勾配倍率を計算する。
        double slopeMultiplier = MathTan(angle * M_PI / 180.0) / MathTan(45 * M_PI / 180.0);
        
        // 価格のオフセットを計算する。
        double priceShift = baseSlope * barDiff * slopeMultiplier * _Point;
        double endPrice;
        
        // 逆トレンドの方向に基づく終値の計算
        if(!isTrendUp)
        {
            endPrice = extremum + priceShift;
        }
        else
        {
            endPrice = extremum - priceShift;
            angle = -angle; // 下降トレンドの反転角度
        }

        // トレンドラインオブジェクトを作成する
        if(ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, TimeCurrent(), endPrice))
        {
            // トレンドラインのプロパティを設定する
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Opposite Gann Fan " + angleNames[i]);
        }
        else
        {
            Print("Failed to create Opposite Gann Fan line: ", GetLastError());
        }
    }
}





結局、DeepSeekにソースコードを調整してもらうことになりました(問題なく動作し、自動的に線が引かれます):
#property copyright "Copyright 2024, Evgeniy Shtenco"  // 著作権情報
#property link      "https://www.mql5.com/en/users/koshtenko"  // 著者リンク
#property version   "1.00"  // インジケータのバージョン番号
#property indicator_chart_window  // インジケータはチャート・ウィンドウに表示される。

// 入力パラメータ
input int LookBackBars = 300;      // 分析されたKラインの数
input color GannFanColor = clrBlue; // ヴォーンのファンライン・カラー

// グローバル変数
double extremumPrice;        // 極端なポイント価格
datetime extremumTime;       // 極点時間
double oppositeExtremumPrice; // 逆エクストリーム・ポイント・プライス
datetime oppositeExtremumTime; // 逆極性ポイント時間
bool isTrendUp;              // トレンド方向フラグ(上昇トレンドなら真)

//+------------------------------------------------------------------+
//| カスタムインジケータ初期化関数 &nbsp.||カスタムインジケーター初期機能; ||
//+------------------------------------------------------------------+
int OnInit()
{
    return (INIT_SUCCEEDED);  // 初期化に成功
}

//+------------------------------------------------------------------+
//| カスタムインジケータの再初期化機能 &nbsp.||カスタム指標再初期化機能; ||
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
    {
        // すべてのギャン・セクター・オブジェクトを削除する
        ObjectsDeleteAll(0, "GannFan_");
ObjectsDeleteAll(0, "OppositeGannFan_");
}

//+------------------------------------------------------------------+
//| カスタムインジケータ計算関数|カスタムインジケーター計算機能; | | | | | | | |
//+------------------------------------------------------------------+
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[])            // ポイントスプレッドの配列
{
    if (rates_total < LookBackBars) return (0);  // 十分なデータがない場合はリターンする

    // 以前に描画したオブジェクトをクリアする
    if (prev_calculated == 0) {
        ObjectsDeleteAll(0, "GannFan_");
        ObjectsDeleteAll(0, "OppositeGannFan_");
    }

    // 直近300Kラインの極端点を見つける
    FindExtremums(rates_total, high, low, time);

    // ヴェン・ファン・ラインを描く
    DrawGannFan(extremumPrice, extremumTime);
    DrawOppositeGannFan(oppositeExtremumPrice, oppositeExtremumTime);

    return (rates_total);  // 処理された列の総数を返す。
}

//+------------------------------------------------------------------+
//| 指定されたKライン数内の極端点を見つける。|
//+------------------------------------------------------------------+
void FindExtremums(const int rates_total, const double & high[], const double & low[], const datetime & time[])
{
    int startIndex = rates_total - LookBackBars;  // インデックス作成開始(300K行前)
    int endIndex = rates_total - 1;               // 終了インデックス(最新のK行)

    // 最高点と最低点を見つける
    int highestIndex = ArrayMaximum(high, startIndex, LookBackBars);
    int lowestIndex = ArrayMinimum(low, startIndex, LookBackBars);

    // トレンドの方向性を判断する(高値と安値のタイミングを比較する)
    if (time[highestIndex] > time[lowestIndex]) {
        // 最高点が最低点の後にある場合はダウントレンド。
        extremumPrice = high[highestIndex];
        extremumTime = time[highestIndex];
        oppositeExtremumPrice = low[lowestIndex];
        oppositeExtremumTime = time[lowestIndex];
        isTrendUp = false;
    }
    else {
        // そうでなければ上昇トレンド
        extremumPrice = low[lowestIndex];
        extremumTime = time[lowestIndex];
        oppositeExtremumPrice = high[highestIndex];
        oppositeExtremumTime = time[highestIndex];
        isTrendUp = true;
    }
}

//+------------------------------------------------------------------+
| ベン・ファン・ラインのプロット&nbsp;||ベンファン線をプロットする
//+------------------------------------------------------------------+
void DrawGannFan(double extremum, datetime extremumTime)
{
    // ギャン角度とそれに対応する名前を定義する。
    double angles[] = { 82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = { "1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    // セクターラインの終了時刻を計算する(現在時刻+300サイクル)
    datetime endTime = TimeCurrent();  // 現在時刻を終了時刻として使用する

    // 各角度にセクター線を引く
    for (int i = 0; i < ArraySize(angles); i++)
    {
        string label = "GannFan_" + angleNames[i];  // オブジェクト・ラベル
        double angle = angles[i];                  // 現在の角度

        // 価格のオフセットを計算する(時差に基づく)
        double secondsDiff = endTime - extremumTime;
        double priceShift = MathTan(angle * M_PI / 180.0) * secondsDiff / PeriodSeconds();
        double endPrice;

        // トレンド方向に基づく終値の計算
        if (isTrendUp) {
            endPrice = extremum + priceShift;
        }
        else {
            endPrice = extremum - priceShift;
            angle = -angle; // 下降トレンドの反転角度
        }

        // トレンドラインオブジェクトを作成する
        if (ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, endTime, endPrice)) {
            // トレンドラインのプロパティを設定する
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Gann Fan " + angleNames[i]);
        }
        else {
            Print("Failed to create Gann Fan line: ", GetLastError());
        }
    }
}

//+------------------------------------------------------------------+
//|| 逆ギャンファンラインのプロットnbsp; &nbsp; ||
//+------------------------------------------------------------------+
void DrawOppositeGannFan(double extremum, datetime extremumTime)
{
    // ギャン角度とそれに対応する名前を定義する。
    double angles[] = { 82.5, 75, 71.25, 63.75, 45, 26.25, 18.75, 15, 7.5};
    string angleNames[] = { "1x8", "1x4", "1x3", "1x2", "1x1", "2x1", "3x1", "4x1", "8x1"};

    // セクターラインの終了時刻(現在時刻)を計算する。
    datetime endTime = TimeCurrent();

    // 各角度にセクター線を引く
    for (int i = 0; i < ArraySize(angles); i++)
    {
        string label = "OppositeGannFan_" + angleNames[i];  // オブジェクト・ラベル
        double angle = angles[i];                          // 現在の角度

        // 価格のオフセットを計算する(時差に基づく)
        double secondsDiff = endTime - extremumTime;
        double priceShift = MathTan(angle * M_PI / 180.0) * secondsDiff / PeriodSeconds();
        double endPrice;

        // 逆トレンドの方向に基づいて終了価格を計算する。
        if (!isTrendUp) // 逆トレンド
        {
            endPrice = extremum + priceShift;
        }
        else {
            endPrice = extremum - priceShift;
            angle = -angle; // 下降トレンドの反転角度
        }

        // トレンドラインオブジェクトを作成する
        if (ObjectCreate(0, label, OBJ_TREND, 0, extremumTime, extremum, endTime, endPrice)) {
            // トレンドラインのプロパティを設定する
            ObjectSetInteger(0, label, OBJPROP_COLOR, GannFanColor);
            ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);
            ObjectSetInteger(0, label, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, label, OBJPROP_RAY_RIGHT, true);
            ObjectSetString(0, label, OBJPROP_TOOLTIP, "Opposite Gann Fan " + angleNames[i]);
        }
        else {
            Print("Failed to create Opposite Gann Fan line: ", GetLastError());
        }
    }
}

//+------------------------------------------------------------------+
//| チャートイベントハンドラ機能 &nbspnbsp; & &nbsp;
//+------------------------------------------------------------------+
void OnChartEvent(const int id,                  // イベントID
const long & lparam,            // 長い整数パラメータ
                  const double & dparam,          // 倍精度パラメータ
                  const string & sparam)         // 文字列パラメータ
{
    // チャートの変更時にオブジェクトを再描画する。
    if (id == CHARTEVENT_CHART_CHANGE || id == CHARTEVENT_CLICK) {
        // 両極端を再検索し、ベン・ファン・ラインをプロットする。
        int rates_total = Bars(_Symbol, PERIOD_CURRENT);
        double high[], low[];
        datetime time[];
        ArraySetAsSeries(high, true);
        ArraySetAsSeries(low, true);
        ArraySetAsSeries(time, true);
        CopyHigh(_Symbol, PERIOD_CURRENT, 0, rates_total, high);
        CopyLow(_Symbol, PERIOD_CURRENT, 0, rates_total, low);
        CopyTime(_Symbol, PERIOD_CURRENT, 0, rates_total, time);

        FindExtremums(rates_total, high, low, time);
        DrawGannFan(extremumPrice, extremumTime);
        DrawOppositeGannFan(oppositeExtremumPrice, oppositeExtremumTime);
    }
}
初級から中級へ:演算子 初級から中級へ:演算子
この記事では、主な演算子 について学んでいきます。このトピックは理解しやすいかもしれませんが、コードフォーマットに数式を含める際には非常に重要なポイントがいくつかあります。これらの細部を十分に理解していないと、経験の浅いプログラマーは最終的に自分で解決策を見つけることをあきらめてしまうかもしれません。
動物移動最適化(AMO)アルゴリズム 動物移動最適化(AMO)アルゴリズム
この記事は、生命と繁殖に最適な条件を求めて動物が季節的に移動する様子をモデル化するAMOアルゴリズムについて説明しています。AMOの主な機能には、トポロジカル近傍の使用と確率的更新メカニズムが含まれており、実装が容易で、さまざまな最適化タスクに柔軟に対応できます。
ニューラルネットワークの実践:ニューロンのスケッチ ニューラルネットワークの実践:ニューロンのスケッチ
この記事では、基本的なニューロンを作ります。単純に見えるし、多くの人はこのコードをまったくつまらない無意味なものだと考えるかもしれませんが、このニューロンの単純なスケッチを楽しく勉強してほしいと思います。コードを修正することを恐れず、完全に理解することが目標です。
取引におけるニューラルネットワーク:独立したチャネルへのグローバル情報の注入(InjectTST) 取引におけるニューラルネットワーク:独立したチャネルへのグローバル情報の注入(InjectTST)
最新のマルチモーダル時系列予測方法のほとんどは、独立チャネルアプローチを使用しています。これにより、同じ時系列の異なるチャネルの自然な依存関係が無視されます。2つのアプローチ(独立チャネルと混合チャネル)を賢く使用することが、モデルのパフォーマンスを向上させる鍵となります。