
初心者からエキスパートへ:ローソク足のプログラミング
内容
はじめに
これまでに、私たちは数多くのローソク足パターンの名称を学び、暗記してきました。しかし、それらをチャート上で目視で識別するのは非常に手間がかかり、視差による誤認も発生しやすい作業です。ローソク足パターンのロジックは、視覚的な誤解を招きやすい形で定義されていることが多いため、誤った解釈が生じる可能性が高いのです。
例えば、陽線包み足は、陰線のあとに陽線が続くパターンです。この陽線は、前の陰線の終値よりも下で始まり、始値よりも上で終わり、陰線の実体を完全に包み込みます。このとき、陽線の始値が陰線の終値より下にあるかどうかを正確に判断するのは、目視では難しい場合があります。人間の目は、特に視覚的にチャートを分析する際に、誤認しやすい傾向があります。
さらに、過去のデータに対してこのパターンを手動でバックテストすることを想像してみてください。非常に手間がかかり、ミスも多くなることでしょう。しかし、これらのパターンを検出するアルゴリズムを正しくコードすれば、チャート上に戦略的なマーカーを表示でき、識別やバックテストが格段に容易かつ正確になります。
この記事の目的
この記事では、ローソク足パターンのプログラミング、MQL5におけるその数学的な基礎、そして最終的には既存のものを拡張する形で、ローソク足パターンのライブラリを開発することを目指します。
多くの投資関連のWebサイトでは、ローソク足パターンを自然言語で多数紹介していますが、それらのパターンのアルゴリズム的構造まで掘り下げて解説しているところはほとんどありません。中には「すべてのローソク足パターンはすでに定義されている」と主張するサイトもあります。しかし私は、まだ革新の余地があると考えています。新たなパターンを発見し、名前を付けることは十分に可能です。
この記事では、いくつかの有名なパターンを扱いつつ、チャート上で観察した任意のローソク足パターンを自分でプログラミングし、独自に名前を付ける能力を身につけることを目標とします。理解を深めるために、まずは人気のあるパターンに焦点を当てて進めます。
新しいパターンを実装したり発明したりする作業は地道で時間もかかりますが、その見返りは非常に大きいです。パターン認識を自動化するアルゴリズムを作成できれば、目視分析の繰り返しから解放されるのです。
次のステップ
次のセクションでは、私がまとめた調査結果と主要な概念に基づいて、この解説に構造を与えていきます。読み進めていただければ、大きな学びと価値が得られるはずです。
ローソク足データとその基本的なプログラミング操作について
すでにMQL5コミュニティやさまざまなWebサイト、書籍などを通じて、ローソク足パターンの基礎を学んだことがあると思います。もし復習が必要な場合は、先にこちらなどで背景知識を確認してから読み進めてください。ここでの目的は、「車輪の再発明」ではなく、従来のローソク足分析をMQL5言語を使ってアルゴリズム化する方法を紹介することです。このアプローチは、ローソク足パターンを概念的に理解している方に、より構造化されたアルゴリズム的な思考を身につけてもらうためのものです。そして最終的には、自分自身でMQL5で取引戦略の自動化を始めることが可能になります。
初心者にとっては、シンプルな概念から始めて、徐々にコーディングスキルを高めていくことが重要です。まずは、基本的な比較演算子を使用して、陽線と陰線を定義する方法を学んでください。こうした比較に慣れてきたら、実体のサイズや髭の長さを測る算術演算も組み合わせて、単一ローソク足パターンの検出に取り組みます。単一ローソク足の分析に習熟したら、次は複数のローソク足を使ったパターンに進みます。ここでは、複数のローソク足データを比較するために、インデックスの使い方を学びます。Print関数のような機能で自分のコードをテストすれば、ロジックが期待通りに動作しているかを確認できます。
簡単に振り返ると、ローソク足は、一定期間内における価格の動きを視覚的に示す取引ツールです。たとえば1時間や1日といった期間において、それぞれのローソク足は4つの主要な価格情報で構成されます。つまり、始値(その期間の最初の価格)、高値(期間中の最高価格)、安値(最低価格)、終値(期間の最後の価格)です。ローソク足の「実体」は始値と終値の差を表し、「髭」は実体から高値・安値まで伸びた部分です。この構造により、市場のセンチメントを素早く把握することができます。たとえば、終値が始値より高ければローソク足は陽線とされ、上昇の勢いを示します。逆に、終値が始値より低ければ陰線とされ、下落傾向を示します。
これから、時系列データを扱う上で重要だと私が考えるいくつかの用語をご紹介します。これらの概念は、MQL5でローソク足パターンの認識を実装する際の理解に欠かせない基礎となるものです。私自身の調査に基づいて、できる限り明確かつ実用的な解釈を心がけて説明します。
1. 関係演算子
これらは、高校の数学で学んだ不等式と似た比較演算子ですが、MQL5ではプログラミングロジックの中で異なる視点から応用されます。MQL5ドキュメントでは、他のよく使われる演算子とともに、これらの演算子についても詳しく解説されています。以下は、この記事で取り上げる比較演算子の一覧です。
- < (より小さい)
- > (より大きい)
- ==(等しい)
- !=(等しくない)
- <=(以下)
- >=(以上)
これらの演算子は、ローソク足パターンのプログラミングだけに限定されるものではなく、さまざまな市場データの比較にも使用されます。アルゴリズムによる取引判断の中核を担う重要な役割を果たすものです。
時系列データでは、各ローソク足(またはバー)にはインデックスが割り当てられています。最も新しいバーにはインデックス0が付けられ、それより前のバーには1、2、3…というようにインデックスが増加する形で参照されます。この仕組みを理解することは、過去の価格データを正しく反復処理する上で非常に重要です。
3. 時系列
時系列とは、過去の価格データやインジケーターデータを格納するための特別な配列です。この配列では、インデックスが通常の配列と逆になっている点が特徴です。つまり、最新のデータ(現在または直近のバー)をインデックス0で取得し、古いデータはインデックスが大きくなるにつれてさかのぼって参照されます。
ATRはボラティリティを示すインジケーターで、ローソク足パターンにおける動的な閾値の定義に役立ちます。これにより、異なる市場環境でも柔軟にパターンを検出できるようになります。たとえば、ハンマーパターンを定義する際には、実体がATRの30%未満であり、下髭が実体の少なくとも2倍である、というようにATRを使って条件を定量化することで、銘柄や時間足を問わず検出可能になります。
問題となるのは、「小さい」「長い」「大きい」といった表現をどのように数値として定義するかです。たとえば「小さい実体=10ピップ」と決めても、それがすべての銘柄や市場環境で一貫して意味を持つとは限りません。低ボラティリティのEUR/USD(5分足)では10ピップの動きは大きな意味を持ちますが、ボラティリティの高いGBP/JPY(日足)では取るに足らない値動きかもしれません。ATRの利点はここにあります。資産や時間足に合わせてボラティリティを考慮した動的で相対的な基準を提供してくれるのです。
ATRを活用することで、ローソク足パターンの条件は環境に応じて適応するようになります。
- 高ボラティリティ市場(ATRが高い)では、絶対値としては大きく見える実体でも、相対的には「小さい実体」と見なされることがある
- 低ボラティリティ市場(ATRが低い)では、ごくわずかな価格変動でも相対的には大きな動きと見なされることがある
5. MathAbs
MathAbsは、MQL5における組み込み関数の1つで、数値の絶対値(モジュラス)を計算します。絶対値とは、数値がゼロからどれだけ離れているかを示すもので、常に0以上(正またはゼロ)の値になります。
この文脈での使い方:
- 負の数を渡すと、それを正の数に変換します。たとえば、MathAbs(-5)は5を返します。
- すでに正の数またはゼロの場合は、そのままの値が返されます。たとえば、MathAbs(5)は5、MathAbs(0)は0を返します。
ローソク足パターンにおいては、ローソク足の実体サイズを測定する際にMathAbsが使用されます。実体サイズとは、終値(Close[1])と始値(Open[1])の差(Close[1] - Open[1])です。
MathAbsを使用する理由
1. 実体サイズは、陽線(終値 > 始値)であっても陰線(終値 < 始値)であっても、常に正の値として扱う必要があります。例:
- 陽線:Close[1] = 10、open[1] = 8 → 10 - 8 = 2
- 陰線:Close[1] = 8、open[1] = 10 → 8 - 10 = -2、MathAbs(8 - 10) = 2
2. これにより、ローソク足パターンのルールにおいて一貫した比較が可能になります。ローソク足が陽線か陰線かに関係なく、実体の大きさを同じ基準で扱えるためです。
MQL5の関係演算子を使った価格比較
MQL5では、関係演算子は非常に重要なツールであり、たとえばローソク足の始値と終値を比較することで、パターンを識別する際に不可欠な役割を果たします。前述の<、>、==、!=、<=、>=といった演算子は、true (1)またはfalse (0)を返し、ローソク足が陽線か陰線かを判定する助けとなります。
例:
- 陽線は、close[0] > open[0]という条件が成り立つときに識別されます。ここで[0]は最新のローソク足(現在のバー)を指します。
一方で、
- 陰線はclose[0] < open[0]で示されます。
このような基本的な比較こそが、ローソク足パターン認識の出発点です。これらの比較は、価格に対して「このローソク足は、始値より高く終わったか」というシンプルな質問をしているのだと考えてください。もし答えが「はい」であれば、それは上昇のシグナル(陽線)を意味します。
ローソク足パターン
私の調査に基づくと、ローソク足パターンは大きく分けて単一ローソク足パターンと複数ローソク足パターンの2種類に分類できます。ここまでに説明してきた概念が、いよいよこの分類と結びついてきます。理解を深めるために、この2種類の違いを簡潔に比較してみましょう。違いを明確にするために、2つのテーブルを用意しました。
単一ローソク足パターン
単一ローソク足パターンを扱う際には、算術演算が重要です。ローソク足の実体の大きさ、髭の長さ、全体の値幅などを測定するために必要になります。たとえば「同時線」のようなパターンでは、始値と終値がほぼ同じであることが特徴で、これは市場の迷いや転換点の可能性を示唆します。始値、高値、安値、終値それぞれの価格差を分析することで、こうしたパターンを定量的に識別し、市場の変化を捉える手がかりとすることができます。
同時線
ローソク足名 | 論理的な説明 | 参考画像 |
---|---|---|
同時 | 同時線は、始値と終値が非常に近い、または等しいときに形成されるローソク足パターンであり、市場の迷いを表します。これは、open[1] ≈ close[1]という関係にあり、高値や安値が大きく異なることもあります。同時線には複数の形があり、足長同時線、蜻蛉、墓石線など、髭の位置によって分類されます。// Check for Doji pattern if( MathAbs(Open[1] - Close[1]) < Point * 2 ) // Open and close are almost equal { Print("Doji pattern detected"); } | ![]() |
複数ローソク足パターン
複数ローソク足パターンでは、連続する複数のローソク足の関係性を分析する必要があります。MQL5では、インデックスを使用して過去のローソク足にアクセスします。たとえば、close[1]は1本前のローソク足の終値、close[2]は2本前の終値を意味します。代表的な複数ローソク足パターンのひとつに陽の包み足があります。これは、小さな陰線の後に、それを完全に包み込む大きな陽線が現れるパターンです。
このパターンをMQL5で実装するには、まず前のローソク足が陰線であること(close[1] < open[1])を確認し、次に現在のローソク足が陽線であること(close[0] > open[0])を確認します。そのうえで、現在のローソク足の実体が前のローソク足の実体を完全に覆っているかどうかをチェックします。コード内でこれらの条件を確認することで、パターンが期待される順序とサイズの関係に従っているかどうかを保証します。これは、「陽の包み足」パターンを正確に検出するために非常に重要です。
ローソク足パターン | 論理的な説明 | 参考画像 |
---|---|---|
陽の包み足 | 陽の包み足は、インデックス2のローソク足が陰線(終値が始値より低い、つまりClose[2] < Open[2])であり、インデックス1のローソク足が陽線(終値が始値より高い、つまりClose[1] > Open[1])であるときに識別されます。さらに、インデックス1のローソク足が、インデックス2のローソク足の実体を包み込んでいる必要があります。つまり、インデックス1の始値がインデックス2の終値よりも低く(Open[1] < Close[2])、終値がインデックス2の始値よりも高い(Close[1] > Open[2])という条件を満たす必要があります。// Check for bullish engulfing pattern if( Close[2] < Open[2] && // Candle at index 2 is bearish Close[1] > Open[1] && // Candle at index 1 is bullish Open[1] < Close[2] && // Candle at index 1 opens below candle at index 2 close Close[1] > Open[2] ) // Candle at index 1 closes above candle at index 2 open { Print("Bullish engulfing pattern detected"); } | ![]() |
既知のローソク足パターンの収集と再利用可能なパターン関数ライブラリの構築
作業の効率化を図るために、私は代表的なローソク足パターンをまとめた2つの表を作成しました。これには、パターン名、説明欄、参考画像欄を含む包括的なリファレンステーブルが含まれており、開発中はもちろん、将来的に読む人にとっても貴重な資料となるはずです。この表は、後から新しい発見を加えたり、精度を高めたりして拡張できる柔軟性も持っており、より完成度の高いローソク足パターンライブラリを構築するうえで、強力な基盤となります。
単一ローソク足パターンコレクション
ローソク足パターン | 論理的な説明 | 参考画像 |
---|---|---|
ハンマー | ハンマーは、インデックス1のローソク足が次の条件を満たすときに識別されます。まず、実体が小さいこと(終値と始値の絶対差がATRの0.3倍未満である、つまりMathAbs(Close[1] - Open[1]) < 0.3 * ATR)。次に、長い下髭を持っていること(始値または終値のうち小さい方から安値までの距離が実体の2倍以上である、MathMin(Open[1], Close[1]) - Low[1] >= 2 * MathAbs(Close[1] - Open[1]))。さらに、上髭が短いかほとんどないこと(始値または終値のうち大きい方から高値までの距離が実体の半分以下である、High[1] - MathMax(Open[1], Close[1]) <= 0.5 * MathAbs(Close[1] - Open[1]))。// Check for Hammer pattern if( MathAbs(Close[1] - Open[1]) < 0.3 * ATR[1] && // Small body // Long lower wick (MathMin(Open[1], Close[1]) - Low[1]) >= 2 * MathAbs(Close[1] - Open[1]) && // Small or no upper wick (High[1] - MathMax(Open[1], Close[1]) <= 0.5 * MathAbs(Close[1] - Open[1])) { Print("Hammer pattern detected"); } | ![]() |
シューティングスター | シューティングスターは、インデックス1のローソク足が次の条件を満たすときに識別されます。まず、実体が小さいこと(終値と始値の絶対差がATRの0.3倍未満である、つまりMathAbs(Close[1] - Open[1]) < 0.3 * ATR)。次に、長い上髭を持っていること(始値または終値のうち大きい方から高値までの距離が実体の2倍以上である、High[1] - MathMax(Open[1], Close[1]) >= 2 * MathAbs(Close[1] - Open[1]))。さらに、下髭が短いかほとんどないこと(始値または終値のうち小さい方から安値までの距離が実体の半分以下である、MathMin(Open[1], Close[1]) - Low[1] <= 0.5 * MathAbs(Close[1] - Open[1]))。// Check for Shooting Star pattern if( MathAbs(Close[1] - Open[1]) < 0.3 * ATR[1] && // Small body // Long upper wick (High[1] - MathMax(Open[1], Close[1]) >= 2 * MathAbs(Close[1] - Open[1]) && // Small or no lower wick (MathMin(Open[1], Close[1]) - Low[1]) <= 0.5 * MathAbs(Close[1] - Open[1]) ) { Print("Shooting Star pattern detected"); } | |
同時線 | 同時線は、インデックス1のローソク足が非常に小さな実体を持つときに識別されます。つまり、始値と終値がほぼ等しく、終値と始値の絶対差がATRの0.1倍未満である場合、MathAbs(Close[1] - Open[1]) < 0.1 * ATRという条件を満たします。// Check for Standard Doji pattern if( MathAbs(Close[1] - Open[1]) < 0.1 * ATR[1] ) // Open and close are nearly equal { Print("Standard Doji pattern detected"); } | ![]() |
蜻蛉 | 蜻蛉(トンボ)は、インデックス1のローソク足が次の条件を満たすときに識別されます。まず、実体が非常に小さいこと(終値と始値の絶対差がATRの0.1倍未満、つまりMathAbs(Close[1] - Open[1]) < 0.1 * ATR)。次に、長い下髭を持っていること(始値または終値のうち低い方から安値までの距離がATRの0.5倍を超える、MathMin(Open[1], Close[1]) - Low[1] > 0.5 * ATR)。さらに、上髭がほとんどないか非常に短いこと(始値または終値のうち高い方から高値までの距離がATRの0.1倍未満、High[1] - MathMax(Open[1], Close[1]) < 0.1 * ATR)です。// Check for Dragonfly Doji pattern if( MathAbs(Close[1] - Open[1]) < 0.1 * ATR[1] && // Small body (MathMin(Open[1], Close[1]) - Low[1]) > 0.5 * ATR[1] && // Long lower wick (High[1] - MathMax(Open[1], Close[1]) < 0.1 * ATR[1] ) // Little to no upper wick { Print("Dragonfly Doji pattern detected"); } | ![]() |
墓石線 | 墓石線は、インデックス1のローソク足が次の条件を満たすときに識別されます。まず、実体が非常に小さいこと(終値と始値の絶対差がATRの0.1倍未満、つまりMathAbs(Close[1] - Open[1]) < 0.1 * ATR)。次に、長い上髭を持っていること(始値または終値のうち高い方から高値までの距離がATRの0.5倍を超える、High[1] - MathMax(Open[1], Close[1]) > 0.5 * ATR)。さらに、下髭がほとんどないか非常に短いこと(始値または終値のうち低い方から安値までの距離がATRの0.1倍未満、MathMin(Open[1], Close[1]) - Low[1] < 0.1 * ATR)です。// Check for Gravestone Doji pattern if( MathAbs(Close[1] - Open[1]) < 0.1 * ATR[1] && // Small body (High[1] - MathMax(Open[1], Close[1]) > 0.5 * ATR[1] && // Long upper wick (MathMin(Open[1], Close[1]) - Low[1]) < 0.1 * ATR[1] ) // Little to no lower wick { Print("Gravestone Doji pattern detected"); } | ![]() |
陽の丸坊主 | 陽の丸坊主は、インデックス1のローソク足が強い陽線であるときに識別されます。具体的には、終値が始値より高い(Close[1] > Open[1])ことに加え、ほとんど髭がない状態を示します。つまり、始値が安値に非常に近く(Open[1] - Low[1] < 0.1 * ATR)、終値が高値に非常に近い(High[1] - Close[1] < 0.1 * ATR)ことが条件です。// Check for Bullish Marubozu pattern if( Close[1] > Open[1] && // Bullish candle (High[1] - Close[1]) < 0.1 * ATR[1] && // Close is very close to high (Open[1] - Low[1]) < 0.1 * ATR[1] ) // Open is very close to low { Print("Bullish Marubozu pattern detected"); } | ![]() |
陰の丸坊主 | 陰の丸坊主は、インデックス1のローソク足が強い陰線であるときに識別されます。具体的には、終値が始値より低い(Close[1] < Open[1])ことに加え、ほとんど髭がない状態を示します。つまり、始値が高値に非常に近く(High[1] - Open[1] < 0.1 * ATR)、終値が安値に非常に近い(Close[1] - Low[1] < 0.1 * ATR)ことが条件です。// Check for Bearish Marubozu pattern if( Close[1] < Open[1] && // Bearish candle (High[1] - Open[1]) < 0.1 * ATR[1] && // Open is very close to high (Close[1] - Low[1]) < 0.1 * ATR[1] ) // Close is very close to low { Print("Bearish Marubozu pattern detected"); } | ![]() |
コマ足 | コマ足は、インデックス1のローソク足が次の条件を満たすときに識別されます。まず、実体が小さいこと(終値と始値の絶対差がATRの0.3倍未満、つまりMathAbs(Close[1] - Open[1]) < 0.3 * ATR)。さらに、上下の髭が長いこと(始値または終値のうち高い方から高値までの距離がATRの0.5倍を超え、High[1] - MathMax(Open[1], Close[1]) > 0.5 * ATR、かつ始値または終値のうち低い方から安値までの距離がATRの0.5倍を超える、MathMin(Open[1], Close[1]) - Low[1] > 0.5 * ATR)。// Check for Spinning Top pattern if( MathAbs(Close[1] - Open[1]) < 0.3 * ATR[1] && // Small body (High[1] - MathMax(Open[1], Close[1]) > 0.5 * ATR[1] && // Long upper wick (MathMin(Open[1], Close[1]) - Low[1]) > 0.5 * ATR[1] ) // Long lower wick { Print("Spinning Top pattern detected"); } | ![]() |
複数ローソク足パターンコレクション
ローソク足パターン | 論理的な説明 | 参考画像 |
---|---|---|
明けの明星 | 明けの明星は、インデックス3のローソク足が陰線(Close[3] < Open[3])、インデックス2のローソク足が小さな実体を持つ(終値と始値の絶対差がATRの0.3倍未満、MathAbs(Close[2] - Open[2]) < 0.3 * ATR)、そしてインデックス1のローソク足が陽線(Close[1] > Open[1])であるときに識別されます。さらに、インデックス1の終値はインデックス3のローソク足の中間点を上回っている必要があります(Close[1] > (Open[3] + Close[3]) / 2)。// Check for Morning Star pattern if( Close[3] < Open[3] && // Candle at index 3 is bearish MathAbs(Close[2] - Open[2]) < 0.3 * ATR[1] && // Candle at index 2 has a small body Close[1] > Open[1] && // Candle at index 1 is bullish Close[1] > (Open[3] + Close[3]) / 2 ) // Candle at index 1 closes above midpoint of candle 3 { Print("Morning Star pattern detected"); } | ![]() |
宵の明星 | 宵の明星は、インデックス3のローソク足が陽線(Close[3] > Open[3])、インデックス2のローソク足が小さな実体を持つ(終値と始値の絶対差がATRの0.3倍未満、MathAbs(Close[2] - Open[2]) < 0.3 * ATR)、そしてインデックス1のローソク足が陰線(Close[1] < Open[1])であるときに識別されます。さらに、インデックス1の終値はインデックス3のローソク足の中間点を下回っている必要があります(Close[1] < (Open[3] + Close[3]) / 2)。// Check for Evening Star pattern if( Close[3] > Open[3] && // Candle at index 3 is bullish MathAbs(Close[2] - Open[2]) < 0.3 * ATR[1] && // Candle at index 2 has a small body Close[1] < Open[1] && // Candle at index 1 is bearish Close[1] < (Open[3] + Close[3]) / 2 ) // Candle at index 1 closes below midpoint of candle 3 { Print("Evening Star pattern detected"); } | ![]() |
赤三兵 | 赤三兵は、3本連続の陽線が続くときに識別されます。具体的には、インデックス3のローソク足が陽線(Close[3] > Open[3])、インデックス2のローソク足が陽線(Close[2] > Open[2])、そしてインデックス1のローソク足が陽線(Close[1] > Open[1])である場合です。それぞれのローソク足の実体はATRより大きく(例:Close[3] - Open[3] > ATR)、上髭は小さい(例:High[3] - Close[3] < 0.3 * ATR)必要があります。また、各ローソク足の始値は前のローソク足の実体内にあることが求められます(例:Open[2] > Open[3] && Open[2] < Close[3])。// Check for Three White Soldiers pattern // Candle 3 is bullish with large body and small upper wick if( Close[3] > Open[3] && (Close[3] - Open[3]) > ATR[1] && (High[3] - Close[3]) < 0.3 * ATR[1] && // Candle 2 is bullish with large body and small upper wick Close[2] > Open[2] && (Close[2] - Open[2]) > ATR[1] && (High[2] - Close[2]) < 0.3 * ATR[1] && // Candle 1 is bullish with large body and small upper wick Close[1] > Open[1] && (Close[1] - Open[1]) > ATR[1] && (High[1] - Close[1]) < 0.3 * ATR[1] && // Candle 2 opens within candle 3's body and closes higher Open[2] > Open[3] && Open[2] < Close[3] && Close[2] > Close[3] && // Candle 1 opens within candle 2's body and closes higher Open[1] > Open[2] && Open[1] < Close[2] && Close[1] > Close[2] ) { Print("Three White Soldiers pattern detected"); } | ![]() |
三羽烏(黒三兵) | 三羽烏(黒三兵)は、3本連続の陰線が続くときに識別されます。具体的には、インデックス3、2、1の各ローソク足が陰線である(Close[3] < Open[3]&&Close[2] < Open[2]&&Close[1] < Open[1])ことが条件です。それぞれのローソク足の実体はATRより大きく(例:Open[3] - Close[3] > ATR)、下髭は小さい(例:Open[3] - Low[3] < 0.3 * ATR)必要があります。また、各ローソク足の始値は前のローソク足の実体内にあることが求められます(例:Open[2] < Open[3] && Open[2] > Close[3])。// Check for Three Black Crows pattern // Candle 3 is bearish with large body and small lower wick if( Close[3] < Open[3] && (Open[3] - Close[3]) > ATR[1] && (Open[3] - Low[3]) < 0.3 * ATR[1] && // Candle 2 is bearish with large body and small lower wick Close[2] < Open[2] && (Open[2] - Close[2]) > ATR[1] && (Open[2] - Low[2]) < 0.3 * ATR[1] && // Candle 1 is bearish with large body and small lower wick Close[1] < Open[1] && (Open[1] - Close[1]) > ATR[1] && (Open[1] - Low[1]) < 0.3 * ATR[1] && // Candle 2 opens within candle 3's body and closes lower Open[2] < Open[3] && Open[2] > Close[3] && Close[2] < Close[3] && // Candle 1 opens within candle 2's body and closes lower Open[1] < Open[2] && Open[1] > Close[2] && Close[1] < Close[2] ) { Print("Three Black Crows pattern detected"); } | ![]() |
陽のはらみ線 | 陽のはらみ線は、インデックス2のローソク足が陰線(Close[2] < Open[2])であり、かつ実体がATRより大きい(Open[2] - Close[2] > ATR)ときに識別されます。そして、インデックス1のローソク足が陽線(Close[1] > Open[1])で、その実体が完全にインデックス2のローソク足の実体内に収まっている(Open[1] > Close[2] && Close[1] < Open[2])ことが条件です。// Check for Bullish Harami pattern // Candle 2 is bearish with large body if( Close[2] < Open[2] && (Open[2] - Close[2]) > ATR[1] && // Candle 1 is bullish and within candle 2's body Close[1] > Open[1] && Open[1] > Close[2] && Close[1] < Open[2] ) { Print("Bullish Harami pattern detected"); } | ![]() |
陰のはらみ線 | 陰のはらみ線は、インデックス2のローソク足が陽線(Close[2] > Open[2])であり、かつ実体がATRより大きい(Close[2] - Open[2] > ATR)ときに識別されます。そして、インデックス1のローソク足が陰線(Close[1] < Open[1])で、その実体が完全にインデックス2のローソク足の実体内に収まっている(Open[1] < Close[2] && Close[1] > Open[2])ことが条件です。// Check for Bearish Harami pattern // Candle 2 is bullish with large body if( Close[2] > Open[2] && (Close[2] - Open[2]) > ATR[1] && // Candle 1 is bearish and within candle 2's body Close[1] < Open[1] && Open[1] < Close[2] && Close[1] > Open[2] ) { Print("Bearish Harami pattern detected"); } | ![]() |
陽の包み足 | 陽の包み足は、インデックス2のローソク足が陰線(終値が始値より低い、つまりClose[2] < Open[2])であり、インデックス1のローソク足が陽線(終値が始値より高い、つまりClose[1] > Open[1])であるときに識別されます。さらに、インデックス1のローソク足が、インデックス2のローソク足の実体を包み込んでいる必要があります。つまり、インデックス1の始値がインデックス2の終値よりも低く(Open[1] < Close[2])、終値がインデックス2の始値よりも高い(Close[1] > Open[2])という条件を満たす必要があります。// Check for Bullish Engulfing pattern if( Close[2] < Open[2] && // Candle at index 2 is bearish Close[1] > Open[1] && // Candle at index 1 is bullish Open[1] < Close[2] && // Candle at index 1 opens below candle at index 2's close Close[1] > Open[2] ) // Candle at index 1 closes above candle at index 2's open { Print("Bullish Engulfing pattern detected"); } | ![]() |
陰の包み足 | 陰の包み足は、インデックス2のローソク足が陽線(終値が始値より高い、Close[2] > Open[2])であり、インデックス1のローソク足が陰線(Close[1] < Open[1])であるときに識別されます。さらに、インデックス1のローソク足はインデックス2のローソク足の実体を完全に包み込む必要があり、具体的には始値がインデックス2の終値より高く(Open[1] > Close[2])、終値がインデックス2の始値より低い(Close[1] < Open[2])ことが条件です。// Check for Bearish Engulfing pattern if( Close[2] > Open[2] && // Candle at index 2 is bullish Close[1] < Open[1] && // Candle at index 1 is bearish Open[1] > Close[2] && // Candle at index 1 opens above candle at index 2's close Close[1] < Open[2] ) // Candle at index 1 closes below candle at index 2's open { Print("Bearish Engulfing pattern detected"); } | ![]() |
スリー・インサイド・アップ | スリー・インサイド・アップは、インデックス3のローソク足が陰線(Close[3] < Open[3])であり、かつ実体がATRより大きい(Open[3] - Close[3] > ATR)ときに識別されます。インデックス2のローソク足は陽線(Close[2] > Open[2])で、インデックス3の実体内に収まっている(Open[2] > Close[3] && Close[2] < Open[3])ことが条件です。さらに、インデックス1のローソク足も陽線(Close[1] > Open[1])であり、インデックス2の高値を上回って終わる(Close[1] > High[2])必要があります。// Check for Three Inside Up pattern // Candle 3 is bearish with large body if( Close[3] < Open[3] && (Open[3] - Close[3]) > ATR[1] && // Candle 2 is bullish and within candle 3's body Close[2] > Open[2] && Open[2] > Close[3] && Close[2] < Open[3] && // Candle 1 is bullish and closes above candle 2's high Close[1] > Open[1] && Close[1] > High[2] ) { Print("Three Inside Up pattern detected"); } | ![]() |
スリー・インサイド・ダウン | スリー・インサイド・ダウンは、インデックス3のローソク足が陽線(終値が始値より高い、Close[3] > Open[3])であり、かつ実体がATRより大きい(Close[3] - Open[3] > ATR)ときに識別されます。インデックス2のローソク足は陰線(Close[2] < Open[2])で、インデックス3の実体内に収まっている(Open[2] < Close[3] && Close[2] > Open[3])ことが条件です。さらに、インデックス1のローソク足も陰線(Close[1] < Open[1])であり、インデックス2の安値を下回って終わる (Close[1] < Low[2])必要があります。// Check for Three Inside Down pattern // Candle 3 is bullish with large body if( Close[3] > Open[3] && (Close[3] - Open[3]) > ATR[1] && // Candle 2 is bearish and within candle 3's body Close[2] < Open[2] && Open[2] < Close[3] && Close[2] > Open[3] && // Candle 1 is bearish and closes below candle 2's low Close[1] < Open[1] && Close[1] < Low[2] ) { Print("Three Inside Down pattern detected"); } | ![]() |
毛抜き底 | 毛抜き底は、インデックス2のローソク足が陰線(Close[2] < Open[2])、インデックス1のローソク足が陽線(Close[1] > Open[1])であるときに識別されます。また、両方のローソク足の安値がほぼ同じであることが条件で、その差の絶対値がATRの0.1倍未満である場合(MathAbs(Low[2] - Low[1]) < 0.1 * ATR)に成立します。// Check for Tweezer Bottom pattern if( Close[2] < Open[2] && // Candle at index 2 is bearish Close[1] > Open[1] && // Candle at index 1 is bullish // Lows of both candles are nearly equal MathAbs(Low[2] - Low[1]) < 0.1 * ATR[1] ) { Print("Tweezer Bottom pattern detected"); } | ![]() |
毛抜き天井 | 毛抜き天井は、インデックス2のローソク足が陽線(Close[2] > Open[2])、インデックス1のローソク足が陰線(Close[1] < Open[1])であるときに識別されます。さらに、両ローソク足の高値がほぼ同じであることが条件で、その差の絶対値がATRの0.1倍未満である(MathAbs(High[2] - High[1]) < 0.1 * ATR)場合に成立します。// Check for Tweezer Top pattern if( Close[2] > Open[2] && // Candle at index 2 is bullish Close[1] < Open[1] && // Candle at index 1 is bearish // Highs of both candles are nearly equal MathAbs(High[2] - High[1]) < 0.1 * ATR[1] ) { Print("Tweezer Top pattern detected"); } | ![]() |
強気のキッカー | 強気のキッカーは、インデックス2のローソク足が陰線(Close[2] < Open[2])であり、続くインデックス1のローソク足が陽線(Close[1] > Open[1])である場合に識別されます。さらに、インデックス1の始値がインデックス2の始値よりも高く始まっていること(Open[1] > Open[2])が条件です。// Check for Bullish Kicker pattern if( Close[2] < Open[2] && // Candle at index 2 is bearish // Candle at index 1 is bullish Close[1] > Open[1] && // Candle at index 1 opens above candle at index 2's open Open[1] > Open[2] ) { Print("Bullish Kicker pattern detected"); } | ![]() |
弱気のキッカー | 弱気のキッカーは、インデックス2のローソク足が陽線(Close[2] > Open[2])であり、続くインデックス1のローソク足が陰線(Close[1] < Open[1])である場合に識別されます。さらに、インデックス1の始値がインデックス2の始値よりも下から始まっていること(Open[1] < Open[2])が条件です。// Check for Bearish Kicker pattern // Candle at index 2 is bullish if( Close[2] > Open[2] && // Candle at index 1 is bearish Close[1] < Open[1] && // Candle at index 1 opens below candle at index 2's open Open[1] < Open[2] { Print("Bearish Kicker pattern detected"); } | ![]() |
これらのパターンをまとめた表は、理論上いくらでも拡張可能です。実際、ここで紹介しきれていないローソク足パターンはまだ多く存在します。しかし、議論を簡潔に保つために、ここからはこれらの戦略をひとつの実用的なプログラムとして実装する方向へと話題を移します。最終的な目標は、包括的なローソク足パターンライブラリを構築することです。
私自身、MQL5のコードベースを調査し、10年以上前にアルゴリズム取引の先駆者たちによって開発された非常に優れたソースコードを見つけました。より詳細なアプローチを求める場合は、それらの作品を参照するのも良いでしょう。とはいえ、このディスカッションでは初心者にもわかりやすいシンプルな形を目指して進めてきました。その方針に従い、今後は独自のローソク足パターンライブラリの構築に取り組んでいきます。
再利用可能なローソク足パターンのヘッダーファイルの構築
ここからは、ローソク足パターンを集約した関数ライブラリの作成方法を紹介します。これは複数の再利用可能なパターン検出関数をひとつにまとめたものであり、ライブラリと呼ばれるのは、この仕組みが複数のプロジェクトで使い回しできることを意味します。一度開発すれば、このライブラリをインクルードし、必要に応じて関数を呼び出すだけで他のプロジェクトにも簡単に統合できます。
この種のファイルの正式な呼び名は「ヘッダーファイル」であり、今回はその拡張性にちなんでinfinity_candlestick_pattern.mqhと名付けます。今後さらに多くのパターンを追加していける構造となっています。このファイルはテンプレートとして構成しており、後ほどインジケーターに組み込んで、その実用例を示します。
添付資料では、このヘッダーファイルのより包括的なバージョンを共有しています。そこには、先ほどのリファレンステーブルに記載されたパターンに対応する関数が含まれており、コード内にあるコメント付きのガイドラインに従えば、さらなる拡張も可能です。
このファイルには、IsHammerとIsShootingStarという2つの主要な関数が含まれています。これらは価格データの配列と、それに付随する平均的なボラティリティ指標であるATRを使って、特定のローソク足が該当するパターン条件を満たしているかどうかを判定します。各関数では、指定されたインデックスが有効であるかどうかをチェックし、ローソク足の実体サイズを計算し、さらに髭の長さを実体サイズやATRと比較して評価します。このような慎重なアプローチにより、視覚的に認識されていた取引パターンを、明確な数式に基づいたロジックに変換し、市場のボラティリティに適応する堅牢なパターン認識を可能にします。また、patternATRパラメータを参照渡しで受け渡すことで、後にインジケーター内でATRの値を利用する際の競合や警告を回避し、渡される値の一貫性を確保しています。
これらの関数を他のプロジェクトに統合するには、#includeディレクティブを使ってこのヘッダーファイルをソースコードにインクルードするだけで済みます。インクルードした後は、適切な配列とインデックスを渡すことで、IsHammer関数やIsShootingStar関数を呼び出すことができます。
//+------------------------------------------------------------------+ //| infinity_candlestick_pattern.mqh (Template) | //| Copyright 2025, Metaquotes Ltd | //| https://www.mql5.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Metaquotes Ltd" #property link "https://www.mql5.com/" #ifndef INFINITY_CANDLESTICK_PATTERNS_MQH #define INFINITY_CANDLESTICK_PATTERNS_MQH //+------------------------------------------------------------------+ //| Single-Candlestick Pattern Functions | //+------------------------------------------------------------------+ // Hammer Pattern bool IsHammer(double &open[], double &high[], double &low[], double &close[], double &patternATR[], int index) { if (index < 0) return false; // Ensure the index is valid // Calculate the body size (absolute difference between close and open) double body = MathAbs(close[index] - open[index]); // Check if the body is small relative to ATR (less than 30% of ATR) if (body >= 0.3 * patternATR[index]) return false; // Calculate wick lengths double upperWick = high[index] - MathMax(open[index], close[index]); double lowerWick = MathMin(open[index], close[index]) - low[index]; // Hammer conditions: long lower wick (2x body), small upper wick (≤0.5x body) if (lowerWick >= 2 * body && upperWick <= 0.5 * body) return true; return false; } // Shooting Star Pattern bool IsShootingStar(double &open[], double &high[], double &low[], double &close[], double &patternATR[], int index) { if (index < 0) return false; // Ensure the index is valid // Calculate the body size (absolute difference between close and open) double body = MathAbs(close[index] - open[index]); // Check if the body is small relative to ATR (less than 30% of ATR) if (body >= 0.3 * patternATR[index]) return false; // Calculate wick lengths double upperWick = high[index] - MathMax(open[index], close[index]); double lowerWick = MathMin(open[index], close[index]) - low[index]; // Shooting Star conditions: long upper wick (2x body), small lower wick (≤0.5x body) if (upperWick >= 2 * body && lowerWick <= 0.5 * body) return true; return false; } //+------------------------------------------------------------------+ //| How to Expand the Library | //+------------------------------------------------------------------+ // To add more patterns: // 1. Create a new function, e.g., IsDoji, IsEngulfing, etc. // 2. Use the same inputs: open[], high[], low[], close[], patternATR[], index // 3. Define the pattern’s conditions (e.g., for Doji, check if open ≈ close) // 4. Return true if the pattern matches, false otherwise // 5. For multi-candle patterns, adjust the index check (e.g., index < 1 for 2 candles) // 6. Use patternATR to adapt to volatility (optional) // 7. Add comments to explain your logic #endif //+------------------------------------------------------------------+
次に進めて、先ほど作成したヘッダーファイルをどのように適用するかを示すインジケーターを開発していきます。このインジケーターにはHammer&ShootingStarという名前を付けました。これは、私たちのライブラリを使って、これら2つのローソク足パターンをチャート上に検出・可視化するものです。これにより、再利用可能な関数が実際の取引環境でどのように活用できるのかを示す実用的な例となります。インジケーターの冒頭でライブラリをインクルードすることで、IsHammerやIsShootingStarといったローソク足パターン認識関数にすぐアクセスできるようになります。このモジュール設計によって、インジケーター本体は市場データの収集と処理に集中でき、パターンの評価ロジックはライブラリに任せることで、処理の一貫性が保たれ、保守性も向上します。
初期化フェーズ(OnInit)では、インジケーターがバッファやチャートのプロパティを設定します。ここでは、検出されたパターンを視覚的に表示するための2つの矢印プロットを定義します。また、市場のボラティリティデータを取得するためにATRのハンドルを作成します。これはライブラリ関数が必要とする情報です。計算フェーズ(OnCalculate)では、インジケーターは価格データとATR値を取得し、価格の時系列をループ処理します。各ローソク足に対して、ライブラリ関数を呼び出し、そのローソク足がハンマー(買いシグナル)またはシューティングスター(売りシグナル)の条件を満たしているかどうかを確認します。該当する場合には、該当するバッファに価格レベルを格納し、矢印を描画する準備をします。
さらに、このインジケーターの設計は将来的な拡張にも対応しています。たとえば、ライブラリに新しいパターン認識関数を追加した際には、それに対応するバッファを簡単に追加することができます。この柔軟なアプローチにより、パターンライブラリの拡張がしやすくなるだけでなく、インジケーター本体のロジックとパターン検出アルゴリズムとの間に明確な役割分担を保つことができます。より多くのコーディング経験を積みたい場合には、添付ライブラリの関数を活用しながら、さらに多くのバッファを組み込んでみてください。
//+------------------------------------------------------------------+ //| Hammer&ShootingStar.mq5 | //| Copyright 2025, Metaquotes Ltd | //| https://www.mql5.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Metaquotes Ltd" #property link "https://www.mql5.com/" #property version "1.00" #property indicator_chart_window //--- Include the library #include <infinity_candlestick pattern.mqh> //--- Indicator settings #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_color1 0x0000FF #property indicator_label1 "Sell " #property indicator_type2 DRAW_ARROW #property indicator_color2 0xFF0000 #property indicator_label2 "Buy " //--- Indicator buffers and variables double Buffer1[]; double Buffer2[]; double Open[]; double High[]; double Low[]; double Close[]; double atr[]; int atrHandle; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_ARROW, 242); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_ARROW, 241); // Create ATR handle atrHandle = iATR(_Symbol, _Period, 14); if (atrHandle == INVALID_HANDLE) { Print("Failed to create ATR handle"); return(INIT_FAILED); } 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[]) { // Copy price data and ATR if (CopyOpen(Symbol(), PERIOD_CURRENT, 0, rates_total, Open) <= 0) return(rates_total); ArraySetAsSeries(Open, true); if (CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); if (CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if (CopyClose(Symbol(), PERIOD_CURRENT, 0, rates_total, Close) <= 0) return(rates_total); ArraySetAsSeries(Close, true); if (CopyBuffer(atrHandle, 0, 0, rates_total, atr) <= 0) return(rates_total); ArraySetAsSeries(atr, true); ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); // Main loop for (int i = rates_total-2; i >= 0; i--) { // Sell Supply (Shooting Star) if (IsShootingStar(Open, High, Low, Close, atr, i)) Buffer1[i] = High[i]; // Arrow at high else Buffer1[i] = EMPTY_VALUE; // Buy Supply (Hammer) if (IsHammer(Open, High, Low, Close, atr, i)) Buffer2[i] = Low[i]; // Arrow at low else Buffer2[i] = EMPTY_VALUE; } return(rates_total); }
テスト
すべてが正しく統合されたことで、Hammer&ShootingStarインジケーターをMetaTrader 5のチャート上で実行することができ、素晴らしい結果を確認することができました。このインジケーターはローソク足パターンを的確に検出し、チャート上でしっかりとハイライトしてくれました。これにより、私たちのライブラリが実際の市場環境においても高い精度と実用性を発揮することが証明されました。
Volatility 75 (1s) Index.0,5 :Hammer&ShootingStarテスト
結論
ここまでの内容は非常にボリュームのある議論となりましたが、今後、学習や参照のために何度も振り返る価値のある重要なトピックとなるでしょう。今回アルゴリズムを構築したことで、ローソク足パターンを目視で探すという課題を解決できました。 このプロセスは完全に自動化でき、チャート上に視覚的なインジケーターを表示することなく戦略を管理できるようになります。アルゴリズムがATR値を含むすべての計算を担うため、効率的かつ正確な処理が実現されています。
このディスカッションでは、ローソク足パターンのプログラミングやマルチバッファインジケーターの構築に役立つ多くの概念と手法を取り上げました。今回はローソク足パターンに焦点を当てましたが、それらをアルゴリズム的に解析・活用するアプローチを紹介し、特にトレーディング戦略の自動化を目指す初心者にとって有益な内容となっています。ただし、ローソク足パターンから生成されるシグナルは、実際の取引において信頼性の高いエントリーサインとするためには、追加のフィルターや条件が必要になる場合があります。そうした高度な機能や精度向上を目指す場合には、MQL5のコードベースドキュメントが非常に参考になります。
もし今回の添付コードを使って何か成果が得られたら、ぜひコメント欄で共有していただけるとうれしいです。時間が許せば、今回の内容をさらに発展させる形で、今後このテーマを再訪し、より高度な内容にも取り組んでいきたいと考えています。ファイル名 | 説明 |
---|---|
infinity_candlestick_pattern.mqh | 最も人気のあるローソク足パターンのブール関数のコレクションを含むヘッダーファイル。他のプロジェクトで呼び出すことができます。 |
Hammer&ShootingStar.mq5 | infinity_candlestick_pattern.mqhライブラリを統合したサンプルインジケーター |
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/17525
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索
をご覧ください:Từ người mới bắt đầu đến chuyên gia:Lập trình biểu đồ .
Tác giả:クレマンス・ベンジャミン