要点:本記事は、Tick Density Scalper(ティック密度スキャルパー)という、一定時間あたりのティック数(=約定や気配の更新頻度)を軸に相場の「熱量」を数値化し、売買判断に落とし込むFX用システムトレード手法を、初心者でも実装できるレベルまで徹底解説します。裁量の感覚に頼らず、ティック密度=市場参加者の“殺到度合い”をトリガーにして、高速ブレイクアウトと静寂リバージョンを狙います。終盤ではMQL4 EAの完全コードを掲載し、すぐにバックテストと運用に移れるよう構成しています。
1. ティック密度とは何か:なぜ機能するのか
ティック密度(Tick Density)は、一定の時間窓に到着したティック数を指します。例えば10秒間に到着したティックが50なら密度は「5ティック/秒」です。密度が急騰している場面は、流動性供給・需要喪失、指値の食い上げ/食い下げ、ニュース未確認の小噴火など、“何かが起きた”サインになりやすく、短期的にトレンド方向への推進が発生しやすい傾向があります。一方、密度が枯れている時間帯は、たわみ(歪み)が発生しやすく、ボラティリティは低いが小幅な均し戻し(ミーンリバージョン)が期待できます。
本手法は、密度スパイク=ブレイク狙い、密度ドライ=均し戻し狙いという二面作戦を、時間正規化したルールで実装します。時間足(1分足・5分足)に依存せず、ティック自体をカウントするため、ブローカーや銘柄の違いに依らない標準化が可能です。
2. 環境と通貨ペア:初心者が始めやすい銘柄
初心者が扱いやすいのは、EURUSDとUSDJPYです。理由は、流動性が相対的に高く、スプレッドが狭く、ティック密度が学習しやすいパターンを作りやすいからです。ボラティリティが高い時間帯(ロンドン~NYの重複、東京仲値前後など)は密度スパイクが生じやすく、逆にアジアの昼休みやNY引け後は密度が枯れる傾向が観察されます。
3. シグナル設計:コアとなる3つの数値
本手法の中核は以下の3つです。
- 短期密度 Dshort:例)
10秒
のティック数。 - 基準密度 Dref:例)
5分
の指数移動平均(EMA)で平滑化した密度。 - 閾値係数 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_ref
(d
は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 検証の観点
以下の切り口で必ず分解して評価します。
- 時間帯別:東京・ロンドン・NYで分布を確認。密度プロファイルは時間帯で性質が異なります。
- スパイク vs ドライ:2戦略の独立採算性と相関。両方を同時に回すか、日替わりで切り替えるか。
- スプレッド耐性:上限を0.8→1.2→1.8pipsと変えてPFの落ち方を確認。
- 環境変化テスト:ニュース直後、金曜引け前、祝日などの除外ルールを比較。
- 執行品質:滑り・約定拒否で実運用成績が変わるため、ブローカーごとの差異を把握。
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. まとめ:ティック密度は“相場の体温計”
価格だけでなく、ティックの到着頻度を計測することは、今この瞬間にどれだけ人が集まっているかを測る行為です。密度スパイクは短距離走、密度ドライは呼吸の整え直し。どちらも抽象的な「勘」ではなく、秒単位のデータで規律化できます。最小ロットでのフォワード運用から始め、リスク一定・再現性重視で小さく積み上げていきましょう。
コメント