English Deutsch
preview
プライスアクション分析ツールキットの開発(第32回):Python Candlestick Recognitionエンジン(II) - Ta-Libを用いた検出

プライスアクション分析ツールキットの開発(第32回):Python Candlestick Recognitionエンジン(II) - Ta-Libを用いた検出

MetaTrader 5トレーディングシステム |
111 0
Christian Benjamin
Christian Benjamin

内容



はじめに

前回の記事では、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アプリケーションのインスタンスを作成するためのメインクラス
request:POSTやGETなどで送信されたリクエストデータへアクセスするために使用します。

jsonify:Pythonのデータ構造をJSON形式に変換し、レスポンスとして返すために使用します。

send_file:サーバー上のファイルをクライアントへ送信するために使用します。生成された画像やレポートのダウンロードなどに便利です。

import numpy as np

  •  NumPy:Pythonで数値計算を行うための基礎的なライブラリ
  • npNumPyの一般的なエイリアスとして使用

配列演算、数学関数、データ操作を効率的に処理することができます。

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 EA


Ta-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ライブラリの両方の力を活用し、手動でのチャート読解を自動化された精度重視のワークフローへと変換できます。





  
ChartProjector
Analytical Comment
Analytics Master
Analytics Forecaster 
Volatility Navigator
Mean Reversion Signal Reaper
Signal Pulse 
Metrics Board 
External Flow
VWAP
Heikin Ashi  FibVWAP  
RSI DIVERGENCE
Parabolic Stop and Reverse (PSAR) 
Quarters Drawerスクリプト
Intrusion Detector
TrendLoom Tool Quarters Board 
ZigZag Analyzer Correlation Pathfinder Market Structure Flip Detector Tool
Correlation Dashboard  Currency Strength Meter 
PAQ Analysis Tool 
Dual EMA Fractal Breaker
Pin bar, Engulfing and RSI divergence
Liquidity SweepOpening Range Breakout ToolBoom and Crash InterceptorCCI Zer-Line EA
Candlestick RecognitionCandlestick Detection (TA-Lib)    

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/18824

添付されたファイル |
candlesticks.py (6.76 KB)
取引におけるニューラルネットワーク:ウェーブレット変換とマルチタスクアテンションを用いたモデル(最終回) 取引におけるニューラルネットワーク:ウェーブレット変換とマルチタスクアテンションを用いたモデル(最終回)
前回の記事では、Multitask-Stockformerフレームワークを検討しました。このフレームワークは、ウェーブレット変換とマルチタスク自己アテンション(Self-Attention)モデルを組み合わせたものです。本記事では、このフレームワークのアルゴリズムをさらに実装し、実際の過去データを用いてその有効性を評価していきます。
取引における多項式モデル 取引における多項式モデル
本記事では、直交多項式について説明します。直交多項式を活用することで、より正確で効果的な市場分析が可能になり、トレーダーはより多くの情報に基づいた意思決定をおこなうことができるようになります。
取引におけるニューラルネットワーク:層状メモリを持つエージェント 取引におけるニューラルネットワーク:層状メモリを持つエージェント
層状メモリアプローチは、人間の認知プロセスを模倣することで、複雑な金融データの処理や新しいシグナルへの適応を可能にし、動的な市場における投資判断の有効性を向上させます。
ビッグバンビッグクランチ(BBBC)アルゴリズム ビッグバンビッグクランチ(BBBC)アルゴリズム
本記事では、ビッグバンビッグクランチ(BBBC)法について紹介します。本手法は2つの主要な段階から構成されます。すなわち、ランダムな点を周期的に生成する段階と、それらを最適解へ圧縮する段階です。本アプローチは探索と精緻化を組み合わせることで、段階的により良好な解を導出し、新たな最適化の可能性を開くことが可能です。