プライスアクションとは?FXでのEAシグナル化・MQL5実装ガイド
Photo by Maxim Hopman on Unsplash
最終更新: 2026年07月13日
FXのプライスアクションをEAでシグナル化するには、ピンバー・エングルフィングなどのローソク足パターンをMQL5の条件式に変換し、バックテストで優位性を確認する。まず形状を条件式で定義し、バックテストで検証する——その実装コードとフィルター設計の知見を以下に記す。
プライスアクションは「感覚だから自動化できない」と言われる。確かに、熟練トレーダーの読み取りをそのまま機械化するのは不可能に近い。しかし「ヒゲの比率が本体の2倍を超えるか」「前のローソク足を完全に包んでいるか」という構造的条件は、コードとして厳密に定義できる。EAが「必ず勝てる自動化」ではなく「再現可能な仮説検証ツール」であるという前提で読み進めてほしい。
免責事項: 本記事はプログラミング・バックテスト手法の教育を目的としています。FXトレードは元本保証のない金融商品であり、金融庁も「差し入れた証拠金以上の多額の損失が生じるおそれのある非常にリスクの高い商品」と明示しています。本記事の実装コードや検証結果を実口座で使用する場合、損失リスクを十分理解したうえで自己責任で判断してください。
プライスアクション(Price Action)とは何か
プライスアクションとは、移動平均線やRSIなどのインジケーターに頼らず、ローソク足の形状や値動きそのものから相場の勢いや転換点を読み取る分析手法です。ピンバー・エングルフィングなどのローソク足パターンが代表的な判断材料になります。
プライスアクションの本質は「値動きが語る情報」を読むことにあります。裁量トレードの世界では感覚的な判断とされがちですが、本記事ではこの分析手法をMQL5のEA(自動売買プログラム)としてどう実装するかを、判定条件のコードとバックテスト結果とともに解説します。
プライスアクションをEAでシグナル化する意義と限界
主観を数式で置き換えることの価値
プライスアクション分析の最大の弱点は再現性にある。同じチャートを10人のトレーダーに見せても、「これはピンバーだ」「いや、ヒゲが短すぎる」という判断が分かれる。この主観性こそが、バックテストを不可能にし、ドローダウン後の感情的判断ミスを生む温床になる。
EA化の本質的なメリットは「利益率の最大化」ではなく「判断基準の客観化」にある。「ヒゲが本体の2倍以上、かつ反対側のヒゲが本体の0.5倍未満」という条件は、10年前のデータにも昨日のデータにも同じ基準で適用される。「このパターンはXX通貨ペアのYY時間足で過去5年間に何回発生し、平均損益はZZpipsだった」——こういう問いが初めて立てられる。それだけで実装する価値はある。
EA化が難しい部分
正直に言う。プライスアクションの本質的な強さは「なぜここか」という文脈読みにある。水平線という支持帯の真上に出たピンバーと、何もない空白に出たピンバーでは意味がまったく違う。後者をコードで定義するのは難しい。
EA化できる部分とできない部分を分けると、こうなる。
コードで定義可能な部分
- ローソク足のヒゲ比率・本体比率による形状判定
- 前後のバーとの大小関係
- 移動平均線・ATR・RSIなどの数値フィルター
- サポート/レジスタンスを水平線リストとして外部入力した場合の近接判定
人間判断が残る部分(または高度な機械学習が必要な部分)
- 水平線の「重要度」の評価(何度反発したか、過去の押し安値かどうか等)
- チャートパターン全体の文脈(トレンドの波動構造上の位置)
- 経済指標発表前後の特殊な値動き
EA化は「完全な自動化」ではなく「判断の一部を機械に委ねること」だという認識が、実装後の失望を防ぐ。
Claudeと会話しながらインジケータが作れるhedgrow-fxはこちら
コード化できるプライスアクションパターン
Photo by Nick Chong on Unsplash
OHLC(Open, High, Low, Close)の4値から判定条件を構築する。以下に主要パターンを示す。
ピンバー(Pin Bar)
ピンバーの本質は「一方向への試しが失敗した証拠」だ。下ヒゲの長い陽線ピンバーなら、売り圧力が強まったが最終的に買いが押し戻したことを意味する。
判定条件の閾値には複数の流派がある。「下ヒゲ > 本体 × 1.5」「下ヒゲ > レンジの60%以上」など複数の定義が存在する。筆者が複数の閾値でバックテストを比較したところ、「本体倍率2.0以上 + 反対側ヒゲ0.5以下 + 本体がレンジの10%以上」の組み合わせが、シグナル数と精度のバランスとして安定していた。
エングルフィング(Engulfing)
前バーを「包む」形状。陽線エングルフィングは「前バーの実体全体を上回る陽線が出た」ことを示し、買い圧力の急激な増加を意味する。
インサイドバー(Inside Bar)
前バーの高値・安値の範囲内に完全に収まるバー。相場の膠着・エネルギー蓄積を示す。ブレイクアウト戦略のトリガーとして使われることが多い。
ハンマー足・流れ星
ハンマー足は陽線ピンバーの別名として使われることが多いが、厳密には実体の色を問わない場合もある。TA-Libでは CDLHAMMER と CDLINVERTEDHAMMER として区別されており、実体が下部にあるか上部にあるかで分類される。
ダブルトップ・ダブルボトムの簡易検出
ローカル高値・安値を複数バー遡って検索し、「直近N本以内に同水準の高値が2回出現している」という条件でシンプルに検出できる。ただし「同水準」の許容幅の設定が難しく、誤検出が多いため、フィルターなしでは使い物にならないケースが多い。
MQL5でのピンバーEA実装コード(核心)
MQL5 EAの基本構造(OnInit/OnTick/OnDeinit関数の役割・インジケーターハンドルの管理など)については、MQL5でEAを作る方法・移動平均クロスEAを一から実装するに詳細を整理している。以下はパターン判定のコアだけを抜き出したものだ。
ローソク足データの取得
MQL5では CopyRates 関数でMqlRates構造体の配列にOHLCデータを取得する。ArraySetAsSeries(rates, true) で添字0が最新バーになるよう逆順設定しておくのが定石だ。
MqlRates rates[];
ArraySetAsSeries(rates, true);
int copied = CopyRates(Symbol(), 0, 0, 100, rates);
if(copied <= 0) return;
CopyRates の完全なシグネチャは以下の通り。
int CopyRates(string symbol_name, ENUM_TIMEFRAMES timeframe,
int start_pos, int count, MqlRates rates_array[]);
MqlRates構造体が持つフィールドは time, open, high, low, close, tick_volume だ。rates[0] が現在の確定していないバー、rates[1] が最後に確定したバーとなる。シグナル判定には必ず rates[1](確定バー)を使うこと。rates[0] を使うとティクごとにシグナルが変化する不安定な挙動になる。
ピンバー判定アルゴリズム
double body = MathAbs(rates[1].close - rates[1].open);
double range = rates[1].high - rates[1].low;
double lowerWick = MathMin(rates[1].open, rates[1].close) - rates[1].low;
double upperWick = rates[1].high - MathMax(rates[1].open, rates[1].close);
// 陽線ピンバー(買いシグナル候補)
bool bullPinBar = (rates[1].close > rates[1].open)
&& (lowerWick > body * 2.0)
&& (upperWick < body * 0.5)
&& (body > range * 0.1);
// 陰線ピンバー(売りシグナル候補)
bool bearPinBar = (rates[1].close < rates[1].open)
&& (upperWick > body * 2.0)
&& (lowerWick < body * 0.5)
&& (body > range * 0.1);
body > range * 0.1 の条件は「十字線」を除外するためのものだ。本体がほぼゼロのローソク足はピンバーとして扱わない、という判断で、これがないと静かな相場でのスプレッドノイズを大量に拾う。
エングルフィング判定
// 陽線エングルフィング(買いシグナル候補)
bool bullEngulf = (rates[1].close > rates[1].open)
&& (rates[1].open < rates[2].close)
&& (rates[1].close > rates[2].open);
// 陰線エングルフィング(売りシグナル候補)
bool bearEngulf = (rates[1].close < rates[1].open)
&& (rates[1].open > rates[2].close)
&& (rates[1].close < rates[2].open);
インサイドバー判定
bool isInsideBar = (rates[1].high < rates[2].high) && (rates[1].low > rates[2].low);
一行で書けるシンプルな条件だが、インサイドバーは単独ではエントリー方向を示さない。ブレイクアウト確認のロジックを別途組み合わせる必要がある。
エントリーとストップロスの自動計算
ピンバーでのエントリーは「確定後の次のバーの始値」または「ピンバー高値/安値への逆指値」が一般的だ。ストップロスはピンバーのヒゲ先端の数ピップス外側に置くのがセオリー。
if(bullPinBar)
{
double entryPrice = rates[0].open;
double stopLoss = rates[1].low - 5 * Point();
double takeProfit = entryPrice + (entryPrice - stopLoss) * 2.0;
MqlTradeRequest request = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = Symbol();
request.volume = 0.01;
request.type = ORDER_TYPE_BUY;
request.price = entryPrice;
request.sl = stopLoss;
request.tp = takeProfit;
request.deviation = 10;
request.magic = 12345;
MqlTradeResult result = {};
OrderSend(request, result);
}
リスク注意: プライスアクションEAはバックテスト上でシグナルを検証できますが、実口座での損益はバックテスト結果と乖離することが常態です。
ピンバーEAのバックテスト手順と検証結果
Photo by Anne Nygård on Unsplash
有効な通貨ペアと時間足
ピンバーは「ボラティリティがあり、かつ定期的に転換が起こる」相場で機能しやすい。実際のところ、主要ペア(EURUSD, GBPUSD, USDJPY)の日足・4時間足が比較基準として安定している。バックテスト事例が最も多いからだ。
スキャルピングでの1分足・5分足への適用は可能だが、スプレッドがシグナルのエッジを相殺しやすく、バックテスト結果が実運用から大きく乖離するリスクが高い。ea-bank.comのEA審査基準では、バックテスト期間は直近10年以上であることが要件とされており、短い時間足ほどこの条件を満たすのが難しくなる。
パターン単独では勝てない現実
ある開発者の実装ログでは、フィルターなしのローソク足パターンEA(インサイドバー検出版)の勝率は約40%程度だったという記録がある(note.com/yakinbo「スキャルピングEA開発沼 第3回」より)。これはランダムエントリーとほぼ同等の水準だ。「形状を判定できる」ことと「利益が出る」ことの間には大きな溝がある。
直感的には「正確に検出できれば勝てるはず」と思えるが、数理的には「パターンの出現確率」と「パターン後の価格変動の期待値」は独立した問題だ。形状が正しく検出できても、それが上昇予測として有効かどうかは別の話であり、「文脈(サポート・トレンド・ボラティリティ)」との組み合わせで初めて優位性が生まれる。
長期安定EAのプロフィットファクター基準は経験則で1.3〜1.5以上。フィルターなしのパターン単独でこの水準に達することはほとんどない。プロフィットファクターの評価基準と合格ラインの考え方についてはFXバックテストのプロフィットファクター基準:合格ラインの考え方で詳しく解説している。
プライスアクションEAにフィルターを追加
移動平均線によるトレンドフィルター
int maHandle = iMA(Symbol(), PERIOD_CURRENT, 200, 0, MODE_EMA, PRICE_CLOSE);
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
CopyBuffer(maHandle, 0, 0, 3, maBuffer);
double ma200 = maBuffer[0];
bool trendFilterBull = (rates[1].close > ma200);
bool trendFilterBear = (rates[1].close < ma200);
ATRボラティリティフィルター
int atrHandle = iATR(Symbol(), PERIOD_CURRENT, 14);
double atrBuffer[];
ArraySetAsSeries(atrBuffer, true);
CopyBuffer(atrHandle, 0, 0, 3, atrBuffer);
double currentATR = atrBuffer[0];
double minATR = 0.0010;
bool volatilityFilter = (currentATR > minATR);
フィルター追加の効果
先述の実装ログによれば、水平線フィルター追加後の勝率は約55%(サンプル数15〜20トレード)、ATRフィルター追加後には約60%まで改善したという記録がある。ただし、ATRフィルター版のサンプル数は5〜10トレードに過ぎず、統計的意味はほぼない。「母数が少ないほど勝率は信頼できない」という原則を、この数値そのものが体現している。フィルターを追加するとトレード回数が減少するため、フィルター強化とサンプル数のバランスを常に確認すること。
プライスアクションとインジケーターの融合
ピンバー + RSI逆張りの組み合わせ
int rsiHandle = iRSI(Symbol(), PERIOD_CURRENT, 14, PRICE_CLOSE);
double rsiBuffer[];
ArraySetAsSeries(rsiBuffer, true);
CopyBuffer(rsiHandle, 0, 0, 3, rsiBuffer);
double rsi = rsiBuffer[1];
bool rsiOversold = (rsi < 30.0);
bool rsiOverbought = (rsi > 70.0);
bool buySignal = bullPinBar && rsiOversold && trendFilterBull && volatilityFilter;
bool sellSignal = bearPinBar && rsiOverbought && trendFilterBear && volatilityFilter;
複合シグナルEAのコード構造
void OnTick()
{
MqlRates rates[];
ArraySetAsSeries(rates, true);
if(CopyRates(Symbol(), 0, 0, 100, rates) <= 0) return;
double ma200[], atrVal[], rsiVal[];
ArraySetAsSeries(ma200, true); ArraySetAsSeries(atrVal, true);
ArraySetAsSeries(rsiVal, true);
CopyBuffer(maHandle, 0, 0, 3, ma200);
CopyBuffer(atrHandle, 0, 0, 3, atrVal);
CopyBuffer(rsiHandle, 0, 0, 3, rsiVal);
double body = MathAbs(rates[1].close - rates[1].open);
double range = rates[1].high - rates[1].low;
double lowerWick = MathMin(rates[1].open, rates[1].close) - rates[1].low;
double upperWick = rates[1].high - MathMax(rates[1].open, rates[1].close);
bool bullPinBar = (rates[1].close > rates[1].open)
&& (lowerWick > body * 2.0)
&& (upperWick < body * 0.5)
&& (body > range * 0.1);
bool trendOK = (rates[1].close > ma200[1]);
bool volatilOK = (atrVal[1] > 0.0010);
bool rsiOK = (rsiVal[1] < 30.0);
if(bullPinBar && trendOK && volatilOK && rsiOK)
{
// エントリーロジック
}
}
免責事項: インジケーターの組み合わせや閾値の最適化は過剰適合リスクがあります。ウォークフォワードテストやモンテカルロシミュレーションによる堅牢性検証を必ず実施してください。
機械学習とプライスアクションの次世代アプローチ
特徴量エンジニアリングとしてのPA指標化
ルールベースEAと機械学習の接点として、プライスアクションパターンを特徴量に変換するアプローチがある。ピンバー判定結果や下ヒゲ比率の連続値を特徴量として扱い、勝敗ラベルと対応させる。
PythonでのTA-Libによるパターン検出
import talib
import pandas as pd
df['pin_bar'] = talib.CDLHAMMER(df.Open, df.High, df.Low, df.Close)
df['engulfing'] = talib.CDLENGULFING(df.Open, df.High, df.Low, df.Close)
df['inside_bar'] = talib.CDLHARAMI(df.Open, df.High, df.Low, df.Close)
df['shooting_star'] = talib.CDLSHOOTINGSTAR(df.Open, df.High, df.Low, df.Close)
df['pin_bar_norm'] = df['pin_bar'] / 100
MQL5からPythonモデルを呼び出す
string url = "http://127.0.0.1:5000/predict";
string headers = "Content-Type: application/json\r\n";
string body = StringFormat(
"{\"close\":%.5f,\"pin_bar\":%d,\"rsi\":%.2f}",
rates[1].close, bullPinBar ? 1 : 0, rsiVal[1]
);
char postData[], resultData[];
StringToCharArray(body, postData);
int res = WebRequest("POST", url, headers, 5000, postData, resultData, response);
Claudeと会話しながらインジケータが作れるhedgrow-fxはこちら
よくある質問(FAQ)
Q: ピンバーのヒゲ比率「2倍以上」という条件は絶対ですか? A: 絶対ではありません。「下ヒゲ > 本体 × 1.5」「下ヒゲ > レンジの60%以上」など複数の定義が存在します。採用した定義を一貫して使い、バックテストで検証することが重要です。
Q: MQL4からMQL5に移行するときの主な変更点は?
A: 最大の変更点は価格取得方法です。MQL4では iOpen(), iClose() で直接取得していましたが、MQL5では CopyRates() でMqlRates配列に一括取得します。インジケーター値も CopyBuffer() を使うため、OnInit() でハンドルを取得する手順が必要です。
Q: バックテストでPF2.0のEAが実口座で動かない理由は? A: ①スプレッドの過小評価、②スリッページ、③カーブフィッティングの3つが主因です。
Q: サポート/レジスタンスをどうコード化すれば良いですか? A: 「直近N本の高値・安値リストを保持し、現在価格がその±X%以内に入っていれば近傍と判定する」方法が最もシンプルです。水平線の重要度評価は難度が高く、手動入力パラメータが実用的なケースが多いです。
Q: プライスアクションEAは初心者でも運用できますか? A: バックテスト解釈・リスク管理には相応の知識が必要です。実口座使用前に必ずデモ口座での検証期間を設けてください。
Q: プライスアクションをEAでシグナル化するには何から始めればいいですか? A: まずピンバーの判定条件(下ヒゲ > 本体 × 2.0 など)をMQL5の条件式として実装し、MT5のストラテジーテスターでシグナル可視化から始めるのが最短ルートです。シグナル数・勝率・プロフィットファクターの3指標を確認してから、EMA200などのトレンドフィルター追加に移行してください。
Q: プライスアクションEAのシグナルが出過ぎる場合、最初に追加すべきフィルターは? A: EMA200によるトレンドフィルターが最もシンプルで効果が安定しています。「価格がEMA200より上にある場合のみ買いシグナルを有効にする」という1条件だけでも、逆張りノイズを大幅に削減できます。ATRフィルターと合わせて段階的に適用するのが実装上の定石です。
Claudeと会話しながらインジケータが作れるhedgrow-fxはこちら
免責事項: 本記事のコードおよびバックテスト数値はいかなる投資収益も保証しません。FX取引は元本保証のない金融商品です。実口座での運用は自己責任で行ってください。
著者情報: FX quantトレーダー / MQL5開発者(プロフィール追記予定)
