Tick Density Scalper(ティック密度スキャルパー)— 初心者から始めるFXシステムトレード完全ガイド

FX

要点:本記事は、Tick Density Scalper(ティック密度スキャルパー)という、一定時間あたりのティック数(=約定や気配の更新頻度)を軸に相場の「熱量」を数値化し、売買判断に落とし込むFX用システムトレード手法を、初心者でも実装できるレベルまで徹底解説します。裁量の感覚に頼らず、ティック密度=市場参加者の“殺到度合い”をトリガーにして、高速ブレイクアウト静寂リバージョンを狙います。終盤ではMQL4 EAの完全コードを掲載し、すぐにバックテストと運用に移れるよう構成しています。

1. ティック密度とは何か:なぜ機能するのか

ティック密度(Tick Density)は、一定の時間窓に到着したティック数を指します。例えば10秒間に到着したティックが50なら密度は「5ティック/秒」です。密度が急騰している場面は、流動性供給・需要喪失、指値の食い上げ/食い下げ、ニュース未確認の小噴火など、“何かが起きた”サインになりやすく、短期的にトレンド方向への推進が発生しやすい傾向があります。一方、密度が枯れている時間帯は、たわみ(歪み)が発生しやすく、ボラティリティは低いが小幅な均し戻し(ミーンリバージョン)が期待できます。

本手法は、密度スパイク=ブレイク狙い密度ドライ=均し戻し狙いという二面作戦を、時間正規化したルールで実装します。時間足(1分足・5分足)に依存せず、ティック自体をカウントするため、ブローカーや銘柄の違いに依らない標準化が可能です。

2. 環境と通貨ペア:初心者が始めやすい銘柄

初心者が扱いやすいのは、EURUSDUSDJPYです。理由は、流動性が相対的に高く、スプレッドが狭く、ティック密度が学習しやすいパターンを作りやすいからです。ボラティリティが高い時間帯(ロンドン~NYの重複、東京仲値前後など)は密度スパイクが生じやすく、逆にアジアの昼休みやNY引け後は密度が枯れる傾向が観察されます。

3. シグナル設計:コアとなる3つの数値

本手法の中核は以下の3つです。

  1. 短期密度 Dshort:例)10秒のティック数。
  2. 基準密度 Dref:例)5分の指数移動平均(EMA)で平滑化した密度。
  3. 閾値係数 k:スパイク判定の倍率(例:D_short > k × D_ref でブレイク方向の順張り)。

また、スプレッド上限最小ボラ時間フィルタ(取引禁止時間帯の除外)を満たすときのみエントリーします。方向判定はシンプルに、短期の価格変化(例:Bid - MA(価格, n))で上方向・下方向を決めるか、または直近高安の更新で決めます。

4. エントリー・エグジットの具体ルール

4.1 ブレイクアウト(密度スパイク)

条件D_short > k × D_ref かつ Spread <= SpreadMax
方向Bidが短期MAを上回り、高値更新なら買い/下回り、安値更新なら売り。
初期ストップ:直近スイング高安の外側(または固定pips)。
利確時間利確(例:30~90秒)+固定TPのハイブリッド。
その他トレイリングは密度が平常化(D_short < D_ref)したら停止。

4.2 リバージョン(密度ドライ)

条件D_short < d × D_refdは0.5~0.8など)かつ、ATRなどで“最低限の振れ幅”を確認。
方向:直近のミニトレンドと逆向き(短期MA乖離が大きい方に逆張り)。
初期ストップ:直近極値の外側。
利確:平均回帰を想定して固定TP小さめ+時間利確併用。

5. リスク管理:1トレードあたりの損失を固定化する

初心者はまず損失の上限を定め、口座残高に対するリスクを一定に保つことが重要です。例として、1トレード0.3~0.5%の損失上限を推奨します。ロット計算は、ストップ幅(pips)×1pipsあたり価値から逆算します。複数エントリーを行う場合でも、同時保有の総リスクが1%を超えないように制御します。

6. 実践ステップ:導入から検証・運用まで

6.1 準備

MT4(MetaTrader 4)を用意し、デモ口座でEURUSD/USDJPYのティックを十分に取得します。バックテストは「全ティック」モードが望ましいですが、ブローカーの履歴精度に依存するため、フォワードテスト(デモでの実走)を必ず行います。

6.2 パラメータの初期値

  • 短期窓:10秒
  • 参照密度EMA:300秒(=5分)
  • スパイク倍率:k = 2.0
  • ドライ倍率:d = 0.7
  • 時間利確:60秒
  • 固定TP/SL:TP 6~10pips / SL 6~12pips(スプレッドに応じて調整)
  • スプレッド上限:1.2pips 目安(EURUSD)

6.3 検証の観点

以下の切り口で必ず分解して評価します。

  1. 時間帯別:東京・ロンドン・NYで分布を確認。密度プロファイルは時間帯で性質が異なります。
  2. スパイク vs ドライ:2戦略の独立採算性と相関。両方を同時に回すか、日替わりで切り替えるか。
  3. スプレッド耐性:上限を0.8→1.2→1.8pipsと変えてPFの落ち方を確認。
  4. 環境変化テスト:ニュース直後、金曜引け前、祝日などの除外ルールを比較。
  5. 執行品質:滑り・約定拒否で実運用成績が変わるため、ブローカーごとの差異を把握。

7. 運用の型:小ロット→段階的スケール

実弾投入は、最小ロットで2~4週間のフォワードから開始し、損益R(平均利益/平均損失)と命中率、PF(損益合計比)を記録します。指定した最大ドローダウンを超えない範囲で、段階的にロットを引き上げます。週ごとにエクイティカーブのブレを評価し、密度プロファイルの変化(平均密度とスパイク頻度)を月次で点検します。

8. よくある失敗と対策

  • スパイク一発逆走:密度が高い=必ず伸びるではありません。価格方向フィルタ(MA上か下か、直近高安ブレイクか)を必ず併用します。
  • スプレッドの無視:スキャルは取引コスト勝負です。スプレッド上限の厳守と、広がったら即エントリー停止。
  • 過最適化:10~20のパラメータを触るより、3~5に絞る方が再現性は高くなります。
  • ニュース直撃:高インパクト指標の直前直後は除外。密度スパイクは出ても、乱高下で刈られます。

9. MQL4 EA(完全コード):Tick Density Scalper

以下は、ティック密度の短期値と参照値(EMA)を算出し、スパイク順張り+ドライ逆張りの両モードを備えたEAの最小完全実装です。学習用の骨格として用い、ブローカー条件に合わせて調整してください。

//+------------------------------------------------------------------+
//|                                               TickDensityScalper |
//|                                     (c) 2025 for educational use |
//+------------------------------------------------------------------+
#property strict

input string   TradeSymbol        = _Symbol;
input ENUM_TIMEFRAMES RefTF       = PERIOD_M1;
input int      ShortWindowSec     = 10;        // 短期計測窓(秒)
input int      RefEmaSec          = 300;       // 参照密度EMA(秒)
input double   SpikeK             = 2.0;       // スパイク倍率 k
input double   DryD               = 0.7;       // ドライ倍率 d
input int      MinATRp            = 3;         // 最小ATR(pips相当)
input double   SpreadMaxPips      = 1.2;
input int      FastMAPeriod       = 12;        // 方向判定用
input int      SLpips             = 10;
input int      TPpips             = 8;
input int      TimeTPsec          = 60;        // 時間利確(秒)
input double   RiskPerTradePct    = 0.4;       // 口座に対する%(例:0.4%)
input bool     EnableBreakout     = true;      // スパイク順張り
input bool     EnableReversion    = true;      // ドライ逆張り
input int      Magic              = 86421;
input bool     OnePosition        = true;      // 同時保有を1に制限
input int      StartHour          = 7;         // 取引時間帯(サーバ時)
input int      EndHour            = 23;

datetime lastWindowStart = 0;
int      ticksInWindow   = 0;
double   refEma          = 0.0;
datetime lastTradeTime   = 0;

// pip計算補助
double PipValueInPoints() {
   if(_Digits==3 || _Digits==5) return(10);
   return(1);
}
double SpreadInPips() {
   return (MarketInfo(TradeSymbol, MODE_SPREAD) / PipValueInPoints());
}
double ATRpips(int period=14) {
   double atr = iATR(TradeSymbol, RefTF, period, 0);
   double p = (atr / MarketInfo(TradeSymbol, MODE_POINT)) / PipValueInPoints();
   return p;
}
double FastMA() {
   return iMA(TradeSymbol, RefTF, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
}
bool TradingHours() {
   int h = TimeHour(TimeCurrent());
   if(StartHour <= EndHour) return (h>=StartHour && h=StartHour || h=0;i--){
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         if(OrderSymbol()==TradeSymbol && OrderMagicNumber()==Magic) {
            if(OrderType()==OP_BUY)  OrderClose(OrderTicket(), OrderLots(), Bid, 50);
            if(OrderType()==OP_SELL) OrderClose(OrderTicket(), OrderLots(), Ask, 50);
         }
      }
   }
}
double LotsByRisk(double sl_pips) {
   if(sl_pips<=0) return(0.01);
   double riskMoney = AccountBalance() * RiskPerTradePct / 100.0;
   double tickvalue = MarketInfo(TradeSymbol, MODE_TICKVALUE);
   double lotStep   = MarketInfo(TradeSymbol, MODE_LOTSTEP);
   double minLot    = MarketInfo(TradeSymbol, MODE_MINLOT);
   double pipValuePerLot = (tickvalue * PipValueInPoints()) / MarketInfo(TradeSymbol, MODE_TICKSIZE);
   double lots = riskMoney / (sl_pips * pipValuePerLot);
   // 誤差・最小ロット調整
   double steps = MathFloor(lots/lotStep);
   lots = MathMax(minLot, steps*lotStep);
   return NormalizeDouble(lots, 2);
}

int OnInit(){
   lastWindowStart = TimeCurrent();
   ticksInWindow = 0;
   refEma = 0.0;
   return(INIT_SUCCEEDED);
}

void OnTick(){
   if(Symbol()!=TradeSymbol) return;
   if(!TradingHours()) return;

   // スプレッド・ATR フィルタ
   if(SpreadInPips() > SpreadMaxPips) return;
   if(ATRpips() < MinATRp) return;

   datetime now = TimeCurrent();
   // 窓更新
   if(lastWindowStart==0) lastWindowStart = now;
   if((now - lastWindowStart) >= ShortWindowSec) {
      // 窓の密度
      double d_short = (double)ticksInWindow / (double)ShortWindowSec; // ticks/sec
      // 参照EMA更新(時定数=RefEmaSec)
      double alpha = (ShortWindowSec>0) ? (double)ShortWindowSec / (double)RefEmaSec : 0.1;
      if(alpha>1) alpha = 1;
      if(refEma<=0) refEma = d_short;
      else refEma = refEma + alpha*(d_short - refEma);

      // 売買判定
      double ma = FastMA();
      double price = Bid;
      bool higher = (price > ma);
      bool lower  = (price < ma);
      bool spike  = (d_short > SpikeK * refEma);
      bool dry    = (d_short < DryD   * refEma);

      // ポジション制御
      if(OnePosition && PositionsCount()>0) {
         // 時間利確
         for(int i=0;i= TimeTPsec) {
                     if(OrderType()==OP_BUY)  OrderClose(OrderTicket(), OrderLots(), Bid, 50);
                     if(OrderType()==OP_SELL) OrderClose(OrderTicket(), OrderLots(), Ask, 50);
                  }
               }
            }
         }
      } else {
         // エントリー
         if(EnableBreakout && spike) {
            if(higher) OpenOrder(OP_BUY);
            else if(lower) OpenOrder(OP_SELL);
         } else if(EnableReversion && dry) {
            if(higher) OpenOrder(OP_SELL);  // 逆張り
            else if(lower) OpenOrder(OP_BUY);
         }
      }

      // 次窓へ
      ticksInWindow = 0;
      lastWindowStart = now;
   }
   ticksInWindow++;
}

void OpenOrder(int type){
   double sl = 0, tp = 0;
   double sl_points = SLpips * PipValueInPoints() * MarketInfo(TradeSymbol, MODE_POINT);
   double tp_points = TPpips * PipValueInPoints() * MarketInfo(TradeSymbol, MODE_POINT);
   double lots = LotsByRisk(SLpips);
   if(lots <= 0) return;

   int ticket;
   if(type==OP_BUY){
      sl = Bid - sl_points;
      tp = Bid + tp_points;
      ticket = OrderSend(TradeSymbol, OP_BUY, lots, Ask, 50, sl, tp, "TDS", Magic, 0, clrNONE);
   } else if(type==OP_SELL){
      sl = Ask + sl_points;
      tp = Ask - tp_points;
      ticket = OrderSend(TradeSymbol, OP_SELL, lots, Bid, 50, sl, tp, "TDS", Magic, 0, clrNONE);
   }
}

コードの使い方

MT4の「ファイル」→「データフォルダを開く」→MQL4/Expertsに上記コードを保存し、エディタでコンパイルします。ストラテジーテスターでEURUSD/USDJPYを選び、モデルは「全ティック」、期間は十分に長く設定します。パラメータは小刻みに動かし、過最適化の兆候(テスト期間を変えた途端に崩れる)に注意します。

10. 実運用チェックリスト

  • 実スプレッドが上限を超えたら自動停止するか(VPS含む実地で確認)。
  • 滑り耐性:約定履歴から平均滑り(pips)を週次で記録。
  • ニュース除外:指標カレンダーに合わせて運用時間を調整。
  • 資金曲線:週次でPF, 勝率, 期待値, 最大DDをダッシュボード化。

11. まとめ:ティック密度は“相場の体温計”

価格だけでなく、ティックの到着頻度を計測することは、今この瞬間にどれだけ人が集まっているかを測る行為です。密度スパイクは短距離走、密度ドライは呼吸の整え直し。どちらも抽象的な「勘」ではなく、秒単位のデータで規律化できます。最小ロットでのフォワード運用から始め、リスク一定・再現性重視で小さく積み上げていきましょう。

コメント

タイトルとURLをコピーしました