プライスアクション分析ツールキットの開発(第32回):Python Candlestick Recognitionエンジン(II) - Ta-Libを用いた検出
内容
はじめに
前回の記事では、Pythonを用いたローソク足パターン検出の方法を紹介しました。最初の段階では、各ローソク足パターンを明示的にコード化する手動検出の手法を採用しました。このアプローチでは、MQL5からPythonへ送信される始値、終値、高値、安値(OHLC)、タイムスタンプなどのデータを基に、Python側で計算をおこない、パターンを特定していました。
本記事では、この手法をさらに発展させ、TA-LibのPythonライブラリを統合します。TA-Libは、60種類以上のローソク足パターンを自動的に検出できる強力なツールです。さらに、mplfinanceおよびmatplotlibと組み合わせることで、検出結果を視覚的に表示するローソク足チャートの描画もおこないます。
使用される主要なライブラリの概要は次のとおりです。
from flask import Flask, reque st, jsonify, send_file import numpy as np import pandas as pd import talib import json import matplotlib.pyplot as plt import mplfinance as mpf
以下、各部分を明確にしていきましょう
Flask
from flask import Flask, request, jsonify, send_file
- PythonでWebアプリケーションやAPIを構築するための軽量なWebフレームワーク
- Flaskアプリケーションのインスタンスを作成するためのメインクラス
jsonify:Pythonのデータ構造をJSON形式に変換し、レスポンスとして返すために使用します。
send_file:サーバー上のファイルをクライアントへ送信するために使用します。生成された画像やレポートのダウンロードなどに便利です。
import numpy as np
- NumPy:Pythonで数値計算を行うための基礎的なライブラリ
- np:NumPyの一般的なエイリアスとして使用
配列演算、数学関数、データ操作を効率的に処理することができます。
import pandas as pd
- Pandas:強力なデータ操作ライブラリ
- pd:標準エイリアス
ローソク足データなどの時系列データの処理に最適なDataFramesなどのデータ構造に使われます。
import talib
- TA-Lib:Pythonのテクニカル分析ライブラリ
幅広いテクニカル指標とローソク足パターン認識アルゴリズムを自動的に計算する機能を提供します。
import json
- Pythonに標準搭載されているJSONデータ処理ライブラリ
リクエストから送信されたJSONデータを解析したり、PythonオブジェクトをJSON形式に変換してレスポンスとして返す際に使用します。
import matplotlib.pyplot as plt
- Matplotlib:プロットライブラリ
- pyplot:MATLABのような操作感でプロットを作成できるインターフェースを提供するMatplotlibモジュール
- plt:標準エイリアス
- 静的、アニメーション、インタラクティブなローソク足チャートなどの作成に使用
import mplfinance as mpf
- mplfinance:金融データの可視化に特化したライブラリ。特にローソク足チャートやOHLCチャートの描画を簡単に行うことができます。
- mpf:利便性のために使用される一般的なエイリアス
- 豊富なカスタマイズオプションにより、金融チャートを簡潔かつ柔軟に描画
TA-Libを使用したパターン検出の利点は以下の通りです。
| 利点 | 詳細 |
|---|---|
| 自動化 | 60種類以上のローソク足パターンを手動コーディングなしで自動検出できます。 |
| 効率性 | 高速なパターン認識が可能で、リアルタイム分析にも適しています。 |
| 精度 | 実績あるアルゴリズムを利用しており、信頼性の高いパターン検出を実現します。 |
| 互換性 | Pythonの他の分析・可視化ライブラリと容易に統合できます。 |
| 使いやすさ | シンプルな関数呼び出しで容易に実装できます。 |
前回の議論を踏まえて
前回も述べたように、以前のシステムではPythonを用いて手動でローソク足パターンを認識する仕組みを構築していました。そのシステムの概要を確認しましょう。
- MetaTrader 5エキスパートアドバイザー(EA)(「チャートサイドオーケストレーター」)
MetaTrader 5上のEAは、新しいバー(ローソク足)が生成されるたびに監視をおこない、直近31本分のローソク足データ(OHLC値、タイムスタンプ)を即座に取得します。これらのデータはコンパクトなJSON形式にまとめられ、WebRequestを通じてローカルのパターン検出サービス(Pythonサーバー)に送信されます。サーバーからローソク足パターン名の配列が返されると、EAは以下のように動作します。
MQL5 EA ➔ (OHLC JSON POST) ➔ Python Server
EAは、検出された各パターン名を対応するバーの高値位置にラベルとして自動描画します。フォントサイズや色はユーザーの設定に従います。有効なパターンが検出された際にはMetaTrader 5のアラートを発生させます。また、ティックごとに古いラベルを削除してチャートを常にクリーンな状態に保ち、EAが削除される際には関連するすべてのオブジェクトを解放して、不要な残留を防ぎます。
MQL5 EA draws labels & fires alerts
- Python Flaskサーバー:パターン検出エンジン
バックエンドでは、「/patterns」エンドポイントを提供するFlaskアプリケーションを構築しました。このサーバーは、EAから送信されたOHLCデータのJSON配列を受け取り、UNIXタイムスタンプをUTCの日時形式に変換します。その後、pandasのDataFrameを生成して堅牢なインデックス管理を行います。データが整ったら、独自に定義したクラシックなローソク足パターンのルール群を適用します。たとえば、十字線、ハンマー、包み足、はらみ足、明けの明星/宵の明星などのパターンを、すべて純粋なPythonロジックで判定します。各パターンはテスト可能な関数として明確に定義されています。
def detect_patterns(df): pats = ["None"]*len(df) for i in range(len(df)): o,h,l,c = df.iloc[i][["OPEN","HIGH","LOW","CLOSE"]] body = abs(c-o); rng = max(h-l,1e-6) lower = min(o,c)-l; upper = h-max(o,c) # doji if body/rng <= 0.1: pats[i] = "doji"; continue # hammer if lower>=2*body and upper<=body: pats[i] = "hammer"; continue # shooting star if upper>=2*body and lower<=body: pats[i] = "shootingstar"; continue # bullish engulfing if i>0: po,pc = df.iloc[i-1][["OPEN","CLOSE"]] if pc<po and c>o and o<=pc and c>=po: pats[i] = "bullishengulfing"; continue # bearish engulfing if i>0: po,pc = df.iloc[i-1][["OPEN","CLOSE"]] if pc>po and c<o and o>=pc and c<=po: pats[i] = "bearishengulfing"; continue # harami if i>0: po,pc = df.iloc[i-1][["OPEN","CLOSE"]] if pc<po and o<c and o>pc and c<po: pats[i] = "bullishharami"; continue if pc>po and o>c and o<pc and c>po: pats[i] = "bearishharami"; continue # morning star if i>1: o1,c1 = df.iloc[i-2][["OPEN","CLOSE"]] o2,c2 = df.iloc[i-1][["OPEN","CLOSE"]] if c1<o1 and abs(c2-o2)<(df.iloc[i-1]["HIGH"]-df.iloc[i-1]["LOW"])*0.3 \ and c>o2 and c>(o1+c1)/2: pats[i] = "morningstar"; continue # evening star if i>1: o1,c1 = df.iloc[i-2][["OPEN","CLOSE"]] o2,c2 = df.iloc[i-1][["OPEN","CLOSE"]] if c1>o1 and abs(c2-o2)<(df.iloc[i-1]["HIGH"]-df.iloc[i-1]["LOW"])*0.3 \ and c<o2 and c<(o1+c1)/2: pats[i] = "eveningstar"; continue return pats
すべてのバーにタグを付けた後、「None」以外の出現数を集計し、簡単なログサマリーにまとめ、処理時間をミリ秒単位で測定します。最後に、バーごとのパターン名の完全なリストとログを含むJSONオブジェクトを返します。この分離により、重いデータ処理は保守と拡張が容易なPython側でおこなわれ、MetaTrader 5はチャートの入出力と可視化に専念することができます。
Python Server ➔ (patterns & log JSON) ➔ MQL5 EATa-Libの理解
TA-Lib (Technical Analysis Library)は、トレーダー、投資家、アナリストによって広く利用されているオープンソースのライブラリで、複雑なテクニカル計算や取引戦略の開発に使われます。もともとはMario Fortierによって開発され、ANSI Cで実装されています。TA-Libは200以上のテクニカル指標(ADX、MACD、RSI、ストキャスティクス、ボリンジャーバンドなど)を網羅しており、さらに60種類以上のローソク足パターンを認識する機能も備えていますそのC/C++コアはAPIを提供しており、Pythonからも利用可能です。これにより、さまざまなアプリケーションへのシームレスな統合が可能になります。2001年にBSDライセンスのもとで初公開されて以来、TA-Libは安定性と信頼性の高いツールとして確立されており、そのアルゴリズムは長年にわたり検証され、現在でもオープンソースおよび商用の両方の分野で広く使用されています。
本システムでは、TA-Libの豊富なパターン認識機能をPythonベースの分析パイプラインへ統合し、ローソク足パターン検出を自動化しています。TA-Lib内のすべての関連パターン関数を動的に読み込み、受信したマーケットデータ内で60種類以上のパターンを検出できるようになります。また、TA-Libの信頼性の高いアルゴリズムとカスタムフィルタリングロジックを組み合わせることで、強気や弱気のシグナルを正確に検出します。検出されたシグナルは、mplfinanceを使用してローソク足チャート上に視覚的に重ねて表示されます。全体の処理はFlask Webサービスで実装されており、リアルタイムでのデータ処理、パターン検出、可視化を可能にしています。この構成は、TA-Libの包括的なライブラリを最新のPythonツールと組み合わせ、MQL5戦略を補完する高度な自動取引分析システムを構築できることを示します。
以下はTA-Libをコンピュータにインストールする方法のステップバイステップガイドです。
手順1:TA-Lib.whlをダウンロードしてインストールする
- Windowsの場合
信頼できるソースから事前コンパイル済みのバイナリをダウンロードします。例:Python 3.9(64ビットWindows)の場合、TA_Lib‑0.4.0‑cp39‑cp39‑win_amd64.whlをダウンロードします。自分のPythonバージョンとシステムアーキテクチャに一致するファイルを選択することが重要です。
pip経由でインストールします。
pip install path\to\your\downloaded\file.whl
- macOSの場合
Homebrewを使用してTA-Lib Cライブラリをインストールします。
brew install ta-lib
- Linux (Debian/Ubuntu)の場合
apt経由で依存関係をインストールします
sudo apt-get update sudo apt-get install libta-lib0-dev
手順2:TA-Lib用のPythonラッパーをインストールする
Cライブラリがインストールされたら、Pythonラッパーをインストールします。
pip install ta-lib
手順3:インストールを確認する
Pythonシェルを開いて以下を実行します。
import talib print(talib.__version__)
エラーが発生せず、バージョンが印刷された場合、インストールは成功しています。
インストールしたTA-Libライブラリで利用可能なローソク足を見てみましょう。
CDL2CROWS CDL3BLACKCROWS CDL3INSIDE CDL3LINESTRIKE CDL3OUTSIDE CDL3STARSINSOUTH CDL3WHITESOLDIERS CDLABANDONEDBABY CDLADVANCEBLOCK CDLBELTHOLD CDLBREAKAWAY CDLCLOSINGMARUBOZU CDLCONCEALBABYSWALL CDLCOUNTERATTACK CDLDARKCLOUDCOVER CDLDOJI CDLDOJISTAR CDLDRAGONFLYDOJI CDLENGULFING CDLEVENINGDOJISTAR CDLEVENINGSTAR CDLGAPSIDESIDEWHITE CDLGRAVESTONEDOJI CDLHAMMER CDLHANGINGMAN CDLHARAMI CDLHARAMICROSS CDLHIGHWAVE CDLHIKKAKE CDLHIKKAKEMOD CDLHOMINGPIGEON CDLIDENTICAL3CROWS CDLINNECK CDLINVERTEDHAMMER CDLKICKING CDLKICKINGBYLENGTH CDLLADDERBOTTOM CDLLONGLEGGEDDOJI CDLLONGLINE CDLMARUBOZU CDLMATCHINGLOW CDLMATHOLD CDLMORNINGDOJISTAR CDLMORNINGSTAR CDLONNECK CDLPIERCING CDLRICKSHAWMAN CDLRISEFALL3METHODS CDLSEPARATINGLINES CDLSHOOTINGSTAR CDLSHORTLINE CDLSPINNINGTOP CDLSTALLEDPATTERN CDLSTICKSANDWICH CDLTAKURI CDLTASUKIGAP CDLTHRUSTING CDLTRISTAR CDLUNIQUE3RIVER CDLUPSIDEGAP2CROWS CDLXSIDEGAP3METHODS
多くのトレーダーは十字線や包み足といった代表的なパターンをよく知っていますが、一方で、市場心理の微妙な変化を示す、あまり知られていないパターンも存在します。捨て子線は珍しい三本構成の反転パターンです。十字線が前のローソク足からギャップを空けて出現し、さらにその次のローソク足が反対方向にギャップを空けることで、すべてのバーが「取り残された」ような形になります。これは多くの場合、トレンドの明確な転換を示唆します。スティックサンドイッチは、同色の強いローソク足2本が、間に小さな反対色のローソク足を挟む形で現れます。最後のバーが最初のバーと同じ、または非常に近い終値で引けるのが特徴です。この「サンドイッチ」パターンは、一時的な逆行があっても元のモメンタムが維持されていることを示します。上放れタスキ線は、トレンド方向へのギャップが発生し、その後3本目のローソク足によって部分的に埋められる(ただし完全には埋まらない)三本構成の継続パターンです。この未解消のギャップは、市場がそのギャップを維持しようとする姿勢を示し、トレンドの強さを確認するサインとなります。
さらに、ひっかけとBelt Holdという2つの難解なパターンもあります。「ひっかけ」(「罠」)は、インサイドバーで始まり、フェイクブレイクアウトによって一方向にトレーダーを誘い込み、その後逆方向へ反転して反対側のレンジを抜けるパターンです。誤った方向にポジションを取ったトレーダーを「罠」にかけ、トレンドの勢いを加速させる特徴があります。一方、Belt Hold(ベルトホールド)は単一の決定的なローソク足で構成されるパターンです。強気のベルトホールドは下降トレンド中に安値付近で始まり、力強く上昇して引けます。弱気のベルトホールドは上昇トレンド中に高値付近で始まり、急激に下落して引けます。このパターンは、前のローソク足を「包み込む」必要がなく、1本のローソク足の中で支配権が急転換する点が特徴です。そのため、主要なサポートまたはレジスタンス付近で発生した場合、明確で強力な反転シグナルとして機能します。
TA-Libでは、各ローソク足パターン関数は「CDL-」という接頭辞で始まります。これはCandleを意味し、それぞれの関数がCDLDOJI、CDLENGULFING、CDLHAMMERなど、古典的なローソク足パターンのアルゴリズムを実装していることを示します。これらのCDL*関数にOpen、High、Low、Close (OHLC)の配列を渡すと、各パターンの存在を示す整数の系列が返されます。0以外の値がそのパターンの出現を示し、値の符号(プラスまたはマイナス)が方向性(強気/弱気)を表します。
システムワークフローの概要
このセクションでは、MQL5とPythonの両方のスクリプトについて、システムの動作を詳しく説明します。本システムの中心には、密接に連携したリクエスト–レスポンスループがあります。新しいローソク足が確定するたびに、MQL5 EAが直近60本分のローソク足データ(OHLC値、タイムスタンプ)を取得し、それらをコンパクトなJSONペイロードにまとめて、ローカルのFlaskサービス「/patterns」へPOSTします。
EAはサーバーからのレスポンスを待機します。このレスポンスには、長さ60の2つの並列配列(1つはパターン名、もう1つはシグナル「bullish」または「bearish」)が含まれています。EAは受信したJSONを即座に解析し、MetaTrader 5上で既存のラベルを削除した後、新たに検出されたパターンの各バーの高値位置にテキストオブジェクトを再生成します。強気シグナルの場合はライム色、弱気シグナルの場合は赤色で表示し、Alert()を呼び出して説明付きのアラートを発します。
一方、Flaskエンドポイントでは、受信したJSONをpandasのDataFrameに正規化し、TA-Libの60種類以上のパターン検出関数を適用して各バーをタグ付けします。その後、強気/弱気バイアスを判定し、両方の配列に加えて簡単なログと処理時間のメトリクスを返します。この明確な役割分担(MQL5はチャートの入出力とアラート、Pythonはデータ正規化とパターンロジック)は、両者をそれぞれ集中・効率的・拡張しやすい構成に保ちます。

- MQL5 EAの概要
EAが初めて読み込まれると、起動メッセージを出力し、MetaTrader 5のEA設定でFlaskエンドポイントを許可リストに登録するように案内します。この初回設定をおこなうことで、ローカルのパターン検出サービスへのHTTP呼び出しを許可し、実行時のサイレントエラーを防止できます。
int OnInit() { Log("EA started – allow WebRequest to: " + InpURL); return INIT_SUCCEEDED; }
すべてのティック受信時に、EAは現在の(インデックス0の)ローソク足のタイムスタンプを、最後に処理したバーのタイムスタンプと比較します。前回のチェック以降に新しいバーが確定していない場合は、そのまま処理を終了します。これにより、不要な重複処理を回避し、パターン分析が確定したローソク足ごとに一度だけ実行されるようにしています。
void OnTick() { datetime bar = iTime(_Symbol, InpTF, 0); if(bar == 0 || bar == g_lastBar) return; g_lastBar = bar; // … (continue processing) }
新しいバーが確定すると、EAは直近60本のローソク足を逆順にループ処理し、各バーのOHLC値とUNIXタイムスタンプを抽出します。これらの値は固定サイズの配列に一時的に格納され、その後、通貨ペア、時間足、60本分のOHLCデータとタイムスタンプを含むコンパクトなJSONオブジェクトとしてシリアライズされます。
double o[BARS], h[BARS], l[BARS], c[BARS]; long t[BARS]; for(int i = 0; i < BARS; i++) { int sh = i + 1; o[i] = iOpen(_Symbol, InpTF, sh); h[i] = iHigh(_Symbol, InpTF, sh); l[i] = iLow(_Symbol, InpTF, sh); c[i] = iClose(_Symbol, InpTF, sh); t[i] = (long)iTime(_Symbol, InpTF, sh); } string json = StringFormat( "{\"symbol\":\"%s\",\"timeframe\":%d,\"time\":[%s],\"open\":[%s],\"high\":[%s],\"low\":[%s],\"close\":[%s]}", _Symbol, InpTF, CSVInt(t), CSV(o), CSV(h), CSV(l), CSV(c) ); Log("JSON-OUT: " + json);
JSONペイロードが作成されると、EAは設定されたFlaskのURLへPOSTリクエストを送信し、指定されたタイムアウト時間まで待機します。ネットワークや権限に関するエラーが発生した場合は詳細なメッセージをログに記録し、それ以外の場合はサーバーから返されたJSONレスポンスをテキスト文字列として受け取り、後続の処理に使用します。
char body[]; StringToCharArray(json, body, 0, StringLen(json)); char reply[]; string hdr = "Content-Type: application/json\r\n", respHdr; int code = WebRequest("POST", InpURL, hdr, InpTimeout, body, reply, respHdr); if(code == -1) { Log("WebRequest failed: " + IntegerToString(GetLastError())); return; } string resp = CharArrayToString(reply, 0, -1, CP_UTF8); Log("HTTP " + IntegerToString(code) + " RESP: " + resp);
HTTPリクエストのレスポンスを受け取ると、EAはレスポンス内で「patterns」と「signals」という2つの配列を探します。単純な文字列検索と分割処理を用いて、それらのJSON配列をMQL5の文字列配列に変換します。処理を進める前に、各配列が正確に60要素を含んでいることを確認します。
string patTxt, sigTxt, patt[], sigs[]; if(!ExtractArray(resp, "patterns", patTxt) || !ExtractArray(resp, "signals", sigTxt) || !ParseArray(patTxt, patt) || !ParseArray(sigTxt, sigs) || ArraySize(patt) != BARS || ArraySize(sigs) != BARS) { Log("Malformed patterns or signals"); return; }
60本の各バーについて、EAは対応するパターンとシグナルのエントリを確認します。実際のパターンが検出された場合(「None」でない場合)、ローソク足のシフトを計算し、古い注釈を削除した上でバーの高値に新しいテキストラベルを作成します。ラベルは色分けされており、強気シグナルはライム、弱気シグナルは赤で表示されます。さらに、各ラベルは通貨ペア、時間足、方向、パターン名、タイムスタンプを含む説明付きのMetaTrader 5アラートを発動します。
for(int i = 0; i < BARS; i++) { string pat = patt[i], sig = sigs[i]; if(pat == "" || pat == "None") continue; int shift = BARS - i; datetime tm = iTime(_Symbol, InpTF, shift); double y = iHigh(_Symbol, InpTF, shift); string obj = PREFIX + IntegerToString(shift); ObjectCreate(0, obj, OBJ_TEXT, 0, tm, y); ObjectSetString(0, obj, OBJPROP_TEXT, pat); color col = (sig == "bullish" ? clrLime : clrRed); ObjectSetInteger(0, obj, OBJPROP_COLOR, col); ObjectSetInteger(0, obj, OBJPROP_FONTSIZE, InpFontSize); ObjectSetInteger(0, obj, OBJPROP_SELECTABLE, false); Alert(StringFormat("%s %s %s pattern '%s' at %s", _Symbol, EnumToString(InpTF), sig, pat, TimeToString(tm, TIME_DATE|TIME_MINUTES))); }
EAが削除されるか、MetaTrader 5が終了すると、初期化解除処理が実行されます。この処理では、EAのラベルタグで始まるすべてのチャートオブジェクトを順に削除します。これにより、EAが非アクティブになった後も古いラベルがチャート上に残ることなく、作業環境をきれいに保つことができます。
void OnDeinit(const int reason) { for(int i = ObjectsTotal(0,0,-1)-1; i >= 0; i--) { string n = ObjectName(0, i, 0, -1); if(StringFind(n, PREFIX) == 0) ObjectDelete(0, n); } Log("EA removed"); }
- Python Flaskサーバーの概要
Flaskサービスが起動すると、INFOレベルのログ設定を行い、受信するすべてのリクエストや内部イベントをコンソールとローテーティングログファイルの両方に記録します。その直後、スクリプトはTA-Libライブラリを検査し、「CDL」接頭辞のついたすべてのローソク足パターン関数をメモリ内の辞書に動的に収集します。この動的な探索により、サービスは既存および将来のTA-Libパターンを手動操作なしで自動的にサポートします。TA-Libに新しいパターンが追加されても、ライブラリを更新するだけでシステム内で利用可能になります。
app = Flask(__name__) logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s') app.logger.setLevel(logging.INFO) # load all TA‑Lib candlestick functions CDL_FUNCS = { name: getattr(talib, name) for name in talib.get_functions() if name.startswith("CDL") }
EAが「/patterns」エンドポイントへPOSTを送信するたびに、サーバーは生のリクエストペイロードを読み取り、MetaTrader 5が付加する可能性のあるヌルバイトを削除した上で、JSONとしてデコードを試みます。解析に失敗した場合や、必要な配列(open、high、low、close、time)のいずれかが欠落している場合、サーバーは即座にHTTP 400エラーを返し、説明付きのメッセージを提供します。ペイロードを最初に検証することで、不正または不完全なデータが分析パイプラインに流れ込み、下流で不明瞭なエラーを引き起こすことを防ぎます。
@app.route('/patterns', methods=['POST']) def patterns(): app.logger.info("Received /patterns request") try: raw = request.data if b'\x00' in raw: raw = raw.split(b'\x00', 1)[0] data = json.loads(raw.decode('utf-8')) except Exception as e: return jsonify(error="Invalid JSON", details=str(e)), 400
JSONが検証を通過すると、サーバーは5つの主要な配列(タイムスタンプと4つの価格系列)を抽出し、インデックス0が最も古いバーになるよう順序を逆にします。その後、UNIXタイムスタンプのリストをpandasのDatetimeIndexに変換し、以降の処理が時間情報に対応できるようにします。配列の長さが異なる場合や数値以外の要素が含まれている場合は、サービスは直ちに不一致を検知してエラーを返します。これにより、完全に整列され、正しい型のデータのみが検出ロジックに渡されることが保証されます。
try: symbol = data.get('symbol', 'Instrument') ts = data.get('time', []) open_ = np.array(data['open'][::-1], dtype=float) high = np.array(data['high'][::-1], dtype=float) low = np.array(data['low'][::-1], dtype=float) close = np.array(data['close'][::-1], dtype=float) idx = pd.to_datetime(np.array(ts[::-1], dtype='int64'), unit='s') app.logger.info(f"Loaded {len(open_)} bars for {symbol}") except KeyError as ke: return jsonify(error=f"Missing field {ke}"), 400 except Exception as e: return jsonify(error="Bad field format", details=str(e)), 400
クリーンなNumPy配列を準備した後、サービスは各TA-Libローソク足関数を順に取り出し、シリーズ全体に適用します。非ゼロの結果は、候補パターンの出現として記録されます。さらに、2つの補助ルーチン(はらみ足の検証用と包み足パターンの精緻化用)が、リクエストフラグに応じて条件付きで適用され、必要に応じてより厳密な判定基準を課します。各TA-Lib呼び出しをtry/exceptブロックで囲むことで、単一の関数や予期せぬデータ形状によってサービス全体が停止することはありません。 問題がある場合はその関数をスキップし、残りの処理を継続します。
n = len(open_) all_hits = [[] for _ in range(n)] for name, func in CDL_FUNCS.items(): try: res = func(open_, high, low, close) except Exception: continue for i, v in enumerate(res): if v == 0: continue if name == "CDLHARAMI" and fh and not is_manual_harami(open_, close, i, tol=HARAMI_TOL): continue if name == "CDLENGULFING" and fe and not is_manual_engulfing(open_, close, i, tol=ENGULF_TOL): continue all_hits[i].append((name, v))
同じバーに複数のパターンが検出される場合、サービスは小規模で設定可能な優先リストを使用します。たとえば、包み足をはらみ足より優先し、はらみ足を十字線より優先することで、競合が発生した場合に支配的なパターンを選択します。優先パターンが存在しない場合は、絶対値が最も大きいTA-Lib出力を持つパターンを選びます。選択された出力の符号は「bullish」または「bearish」のラベルにマッピングされます。このバーごとに1つのパターンを決定する手法により、各ローソク足に明確なシグナルが1つだけ付与され、チャート上の描画やアラート処理が簡潔になります。
PRIORITY = ["CDLENGULFING", "CDLHARAMI", "CDLDOJI"] detected = [None] * n signals = [None] * n for i, hits in enumerate(all_hits): if not hits: continue pick = next(((nm, val) for pat in PRIORITY for nm, val in hits if nm == pat), None) if pick is None: pick = max(hits, key=lambda x: abs(x[1])) nm, val = pick detected[i] = nm signals[i] = "bullish" if val > 0 else "bearish"
次に、スクリプトは4つの価格配列と日時インデックスからpandasのDataFrameを作成し、2つの新しい列を追加します。1つは検出されたパターン名、もう1つはその強気/弱気シグナル用です。視覚的注釈の準備として、全体の価格レンジに基づく小さなオフセットを計算し、散布図オーバーレイのリストを作成します。強気シグナルの場合はバーの安値のすぐ下に緑色の上向き矢印、弱気シグナルの場合はバーの高値のすぐ上に赤色の下向き矢印を配置します。マーカー位置をチャートの動的レンジに対して固定することで、視覚的な混雑を避けつつ、異なる銘柄や時間足でも表示の一貫性を保つことができます。
df = pd.DataFrame({"Open": open_, "High": high, "Low": low, "Close": close}, index=idx)
df["Pattern"] = pd.Series(detected, index=idx).fillna("None")
df["Signal"] = pd.Series(signals, index=idx).fillna("")
df.sort_index(inplace=True)
adds = []
price_rng = df["High"].max() - df["Low"].min()
for tstamp, row in df.iterrows():
if row["Pattern"] == "None":
continue
if row["Signal"] == "bullish":
y, marker, color = row["Low"] - price_rng*0.005, "^", "green"
else:
y, marker, color = row["High"] + price_rng*0.005, "v", "red"
adds.append(mpf.make_addplot(
[y if i == tstamp else np.nan for i in df.index],
type="scatter", marker=marker, markersize=80, color=color
))最後に、サービスはカスタムのローソク足カラー設定(例:上昇バーは緑、下降バーは赤)を定義し、mplfinanceを用いて完全なローソク足チャートを描画します。この際、前もって準備した散布図マーカーも組み込みます。チャートには凡例を追加し、ローソク足の方向とパターンマーカーをわかりやすく表示します。図は視認性を最適化するサイズにリサイズされ、サーバー内のユニークなPNGファイルとして保存され、描画後はメモリ解放のために閉じられます。JSONレスポンスには、反転済みのパターン配列とシグナル配列(インデックス0が最新バー)、オプションのログサマリー、保存されたチャートのファイル名が含まれ、EAや他の分析ツールで即座に利用可能です。
mc = make_marketcolors(up='green', down='red', edge='inherit', wick='inherit') style = make_mpf_style(marketcolors=mc, base_mpf_style='default') fig, axes = mpf.plot(df, type="candle", style=style, title=f"{symbol} Patterns", addplot=adds, volume=False, returnfig=True, tight_layout=True) axes[0].legend(handles=[ Line2D([0],[0],color='green',lw=4,label='Buy Candle'), Line2D([0],[0],color='red',lw=4,label='Sell Candle'), Line2D([0],[0],marker='^',linestyle='None',color='green',markersize=12,label='Buy Signal'), Line2D([0],[0],marker='v',linestyle='None',color='red',markersize=12,label='Sell Signal') ], loc='upper left', frameon=True) fname = f"pattern_chart_{uuid.uuid4().hex[:8]}.png" fig.savefig(path := os.path.join(os.path.dirname(__file__), fname), dpi=100) plt.close(fig) app.logger.info(f"Chart saved: {fname}") return jsonify( patterns=[p or "None" for p in detected[::-1]], signals =[s or "none" for s in signals [::-1]], log=[], chart=fname )
テストと結果
以下にテスト結果の概要を示します。
Step Indexでのテスト
MQL5ログ
MQL5の[エキスパート]タブには、Pythonへ送信されたデータ、受信したパターン、現在検出されている各バーの名前が表示されます。この情報は、新しいバーが確定するたびに更新され、この情報は、新しいバーが確定するたびに更新され、アラートとともに通知されます。
2025.07.15 22:56:50.294 Candlestick Label 2 (Step Index,M15) [CSLAB] JSON-OUT: {"symbol":"Step Index","timeframe":0,"time":[1752558300,1752559200, 1752560100,1752561000,1752561900,1752562800,1752563700,1752564600,1752565500,1752566400,1752567300,1752568200, 1752569100,1752570000,1752570900,1752571800,1752572700,1752573600,1752574500,1752575400,1752576300,1752577200,1752578100,1752579000, 1752579900,1752580800,1752581700,1752582600,1752583500,1752584400,1752585300,1752586200,1752587100,1752588000,1752588900,1752589800, 1752590700,1752591600,1752592500,1752593400,17525943 2025.07.15 22:56:50.804 Candlestick Label 2 (Step Index,M15) [CSLAB] HTTP 200 RESP: {"chart":"pattern_chart_e06f7a61.png","log":[],"patterns": ["CDLENGULFING","CDLHARAMI","None","CDLCLOSINGMARUBOZU","CDLHARAMI","CDLHIKKAKE","CDLENGULFING","CDLHIGHWAVE","None","CDLLONGLINE", "CDLHIGHWAVE","CDLSHORTLINE","CDLSHORTLINE","CDLHIKKAKE","CDLHARAMI","CDLENGULFING","CDLDOJI","None","None","None","CDLCLOSINGMARUBOZU", "None","CDLBELTHOLD","None","CDLHARAMI","CDLBELTHOLD","CDLHIKKAKE","CDLENGULFING","CDLHIKKAKE","CDLHIKKAKE","None","CDLDOJI","CDLHAMMER", "CDLHARAMI","CDLENGULFING" 2025.07.15 22:56:50.804 Candlestick Label 2 (Step Index,M15) 2025.07.15 22:56:50.804 Candlestick Label 2 (Step Index,M15) Alert: Step Index PERIOD_CURRENT bullish pattern 'CDLENGULFING' at 2025.07.15 05:45
コマンドプロンプトログ
- POST /patterns:クライアント(MQL5 EA)が「/patterns」エンドポイントにHTTP POSTリクエストを発行
- HTTP/1.1:リクエストにはHTTP 1.1プロトコルが使用された
- 200:サーバーはステータスコード200(「OK」)で応答した。つまり、エンドポイントはリクエストを正常に処理した。
2025-07-15 22:54:52,246 INFO Received /patterns request 2025-07-15 22:54:52,250 INFO Loaded 60 bars for Step Index 2025-07-15 22:54:52,808 INFO Chart saved: pattern_chart_a77f2eec.png 2025-07-15 22:54:52,810 INFO 127.0.0.1 - - [15/Jul/2025 22:54:52] "POST /patterns HTTP/1.1" 200 - 2025-07-15 22:55:00,040 INFO Received /patterns request
以下は、同じパターンを検出したチャートの例で、「Step Index」の推移を示しています。チャートはMatplotlib、TA-Lib、mplfinanceを使用して作成され、価格バーとシステムで検出されたローソク足シグナルの両方を表示しています。
ローソク足
- 実体が緑色のローソク足は、終値が始値より高い期間(強気バー)を示す
- 実体が赤色のローソク足は、終値が始値より低い期間(弱気バー)を示す
シグナル
- バーの下にある緑色のマーカーは、買いシグナル(強気パターン)を示す
- バーの上にある赤色のマーカーは、売りシグナル(弱気パターン)を示す

Crash 1000 Indexでのテスト

MQL5ログ
2025.07.15 23:30:00.299 Candlestick Label 2 (Crash 1000 Index,M15) [CSLAB] JSON-OUT: {"symbol":"Crash 1000 Index","timeframe":0,"time":[1752561000,1752561900,
1752562800,1752563700,1752564600,1752565500,1752566400,1752567300,1752568200,1752569100,1752570000,1752570900,1752571800,1752572700,1752573600,1752574500,1752575400
,1752576300,1752577200,1752578100,1752579000,1752579900,1752580800,1752581700,1752582600,1752583500,1752584400,1752585300,1752586200,1752587100,1752588000,1752588900,
1752589800,1752590700,1752591600,1752592500,1752593400,1752594300,1752595200,1752596100,17
2025.07.15 23:30:02.749 Candlestick Label 2 (Crash 1000 Index,M15) [CSLAB] HTTP 200 RESP: {"chart":"pattern_chart_ebd72b47.png","log":[],"patterns":
["CDLCLOSINGMARUBOZU","CDLBELTHOLD","CDLBELTHOLD","None","CDLBELTHOLD","CDLHIKKAKE","CDLENGULFING","CDLBELTHOLD","CDLHARAMI","CDLENGULFING","None","CDLBELTHOLD",
"None","CDLBELTHOLD","CDLBELTHOLD","CDLBELTHOLD","None","CDLBELTHOLD","CDLBELTHOLD","None","CDLBELTHOLD","CDLBELTHOLD","CDLBELTHOLD","CDLDOJI","CDLBELTHOLD","None",
"CDLSHORTLINE","CDLSHORTLINE","None","CDLENGULFING","CDLHARAMI","CDLCLOSINGMARUBOZU","None","CDLMATCHINGL
2025.07.15 23:30:02.749 Candlestick Label 2 (Crash 1000 Index,M15)
2025.07.15 23:30:02.769 Candlestick Label 2 (Crash 1000 Index,M15) Alert: Crash 1000 Index PERIOD_CURRENT bearish pattern 'CDLCLOSINGMARUBOZU' at 2025.07.15 06:30
コマンドプロンプトログ
2025-07-15 23:30:02,719 INFO Chart saved: pattern_chart_ebd72b47.png 2025-07-15 23:30:02,735 INFO 127.0.0.1 - - [15/Jul/2025 23:30:02] "POST /patterns HTTP/1.1" 200 -
Pythonのローソク足パターンプロット
このプロットにより、各検出パターンがどのようなシグナルを示し、その後に何が起こるかを明確に確認できます。

結論
本アーキテクチャでは、MetaTrader 5はリアルタイム市場データの取得、チャートオブジェクト管理、ネイティブアラートといった強みを維持しつつ、軽量なFlaskサービスがTA-Libとmplfinanceを活用してローソク足パターンの計算および高品質な可視化を担当します。EAは60本分のOHLCデータとタイムスタンプをJSONとして送信することで、自身の負荷を増やすことなくサブ秒レベルの分析を実現し、Pythonバックエンドは詳細なパターンラベルと完全な注釈付きチャートを生成して、レビューや配布にそのまま使用できます。
この明確な責務分離により、真にモジュール化されたシステムが実現します。パターン検出ルールの精緻化、シグナルフィルターの調整、EAのアラートロジック拡張を、互いに干渉することなく独立しておこなうことができます。また、FlaskサービスをDockerコンテナ化したり、認証付きAPIゲートウェイの背後に配置することで、移植性とセキュリティも向上します。
このフレームワークをお好みの銘柄に適用し、カスタム指標のオーバーレイを試したり、生成されたチャートを広範な分析プラットフォームへ統合することを推奨します。このハイブリッドアプローチにより、MQL5と最新Pythonライブラリの両方の力を活用し、手動でのチャート読解を自動化された精度重視のワークフローへと変換できます。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/18824
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
取引におけるニューラルネットワーク:ウェーブレット変換とマルチタスクアテンションを用いたモデル(最終回)
取引における多項式モデル
取引におけるニューラルネットワーク:層状メモリを持つエージェント
ビッグバンビッグクランチ(BBBC)アルゴリズム
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索