疑似オーダーフロー・スキャルピング:CVD×スプレッド回帰×時間帯で狙う初心者向け実践ガイド
本稿は、FXのようにレベル2板(ビッド・アスクの厚み)が見えにくい環境でも、
ローソク足の値動きとティック出来高から疑似オーダーフロー(CVD: Cumulative Volume Delta)を推定し、
さらにスプレッドの一時的拡大→正常化の回帰と時間帯の流動性特性を重ねて狙う、初心者向けの現実的なスキャルピング手法を解説します。
一般論ではなく、売買ルール、検証フロー、リスク管理、EAコード(MQL4)まで一本化して提示します。
1. 戦略コンセプト
多くの初心者は「順張りか逆張りか」で迷います。本戦略は、ミクロ逆張りに分類されます。
狙うのは「短時間での売り買いの偏りが出尽くして、価格が中値(ミッド)へ回帰しやすい瞬間」です。
根拠は次の3点です。
- 疑似CVDの極端値:直近数本のバーで「売り(または買い)が出過ぎた」痕跡。
- スプレッドの急拡大→平常化:板が薄い瞬間の成行集中は一過性になりやすい。
- 時間帯フィルタ:流動性が戻りやすい時間帯(例:ロンドン前後)に限定。
これらを同時に満たすときだけエントリーし、短い滞在時間で素早く撤退します。
2. 疑似CVDとは何か(初心者向け)
本来のオーダーフローデータ(約定価格ごとの買い/売り成立量)がない場合、
「バーの方向とティック出来高」から押し引きを推測します。
単純化した式は次の通りです。
疑似Δ(デルタ) = (Close - Open) / Point × sqrt(TickVolume)
CVD = 直近L本の疑似Δの合計
バーが陽線かつ出来高が多ければ「買い優勢」、陰線×出来高なら「売り優勢」とみなします。
CVDが極端なマイナス→反発余地、極端なプラス→反落余地、という読み筋です。
実データではないため完璧ではありませんが、「偏りの行き過ぎ」を検知するには十分です。
3. フルルール(最初の完成版)
通貨:EURUSD/USDJPY。時間足:M1またはM5。スキャル対象。
- 時間帯フィルタ:ブローカーサーバ時刻で開始H〜終了Hのみ取引。
例:開始 07:00、終了 20:00(サーバ時刻)。流動の谷は避けます。 - CVD条件:直近L本のCVDが閾値(±T)を超える極端値。
・ロング仮説:CVD ≤ -T(売り偏りが出尽くし)
・ショート仮説:CVD ≥ +T(買い偏りが出尽くし) - スプレッド回帰:直近数ティックでスプレッドが一時的に拡大→現在は平常比1.2倍以内に戻る。
- バンド確認(過度なトレンド回避):ボリンジャーバンド(期間20、2σ)。
ロングは下バンドの外側クローズ直後は見送り、ショートは上バンド外側直後は見送り。 - エントリー:条件一致で成行。
・ロング:BidでBuy。
・ショート:AskでSell。 - 損切り/利確:初期SL=直近スイング±αポイント。TP=RR×SL(RRは1.2〜2.0で調整)。
トレーリングは不要。滞在時間が延びたら時間切れクローズ(例:5〜10分)を優先。 - 同時ポジ制御:通貨ペアごとに1ポジまで。
- ニュース回避(任意):重要指標前後±15分は休止。
まずは保守的なパラメータで始め、週次で最小限のチューニングを行います。
4. 推奨初期パラメータ
項目 | 初期値 | 意図 |
---|---|---|
L(CVD計算本数) | 20 | 過去20本のミクロ偏りを集約 |
T(CVD閾値) | ±60 | 過度な偏りのみ対象(通貨で要調整) |
SpreadWiden | 平常比1.8倍 | 一時的な板薄/成行集中を検知 |
SpreadNow | 平常比1.2倍以下 | 回帰が始まったことを確認 |
RR(利確/損切り比) | 1.5 | 勝率55〜60%を狙う設計 |
TimeExit | 8分 | 粘らず撤退。回転重視 |
Lot | 口座残高の0.5〜1%リスク | 資金保全を最優先 |
5. 実装の全手順(MT4)
- 通貨ペア(EURUSD/USDJPY)を開く。時間足はM1またはM5。
- ヒストリーセンターで十分なデータをダウンロード。
- 本稿のEA(MQL4)を貼り付け、コンパイル。
- 戦略テスターで「毎ティック」モードを選択し、スプレッドは「現在値」か「固定1.5倍平常値」。
- 期間は直近3〜12か月から開始。最初はオーバーフィットを避ける。
- 最適化は最小限(L、T、RR、TimeExit)だけ触る。1変数ずつ。
- フォワード(直近未使用期間)で確認。エクイティの形が崩れたらやり直し。
6. 完全自動売買EA(MQL4)
以下は教育目的のシンプル実装です。ブローカー仕様差・約定品質・スプレッド変動で結果は変わります。
//+------------------------------------------------------------------+
//| Pseudo Orderflow Scalper (CVD x Spread Revert) |
//| Timeframe: M1/M5, Symbols: EURUSD / USDJPY |
//| Note: Educational sample. Use at your own risk. |
//+------------------------------------------------------------------+
#property strict
input double Lots = 0.10;
input int Magic = 240906;
input int CVD_Len = 20; // L
input double CVD_Thr = 60; // T (points-weighted)
input double RR = 1.5; // TP = RR * SL
input int MaxMinutesHold = 8; // TimeExit (minutes)
input int StartHour = 7; // Broker server time
input int EndHour = 20; // Broker server time
input int Slip = 3; // slippage (points)
input int LookbackSwing = 5; // swing window for SL
input double SpreadWideMul = 1.8; // SpreadWiden
input double SpreadNowMul = 1.2; // SpreadNow
datetime lastBarTime = 0;
double avgSpread = 0;
int spreadSamples = 0;
bool NewBar()
{
datetime ct = iTime(Symbol(), Period(), 0);
if(ct != lastBarTime){ lastBarTime = ct; return true; }
return false;
}
double GetSpreadPoints(){ return (Ask - Bid) / Point; }
double GetAvgSpread()
{
if(spreadSamples <= 0) return GetSpreadPoints();
return avgSpread / spreadSamples;
}
void UpdateSpreadAvg()
{
double sp = GetSpreadPoints();
avgSpread += sp;
spreadSamples++;
if(spreadSamples > 5000){ avgSpread /= 2.0; spreadSamples /= 2; } // prevent overflow
}
// Pseudo delta = (Close-Open)/Point * sqrt(TickVolume)
double BarPseudoDelta(int shift)
{
double op = iOpen(Symbol(), Period(), shift);
double cl = iClose(Symbol(), Period(), shift);
double tv = iVolume(Symbol(), Period(), shift); // tick volume
return (cl - op) / Point * MathSqrt(MathMax(tv,1));
}
double CalcCVD(int len)
{
double sum = 0;
for(int i=1; i<=len; i++) sum += BarPseudoDelta(i);
return sum;
}
bool TimeFilter()
{
int h = TimeHour(TimeCurrent());
if(StartHour <= EndHour) return (h >= StartHour && h < EndHour);
// overnight case
return (h >= StartHour || h < EndHour);
}
int CountPositions(int dir)
{
int c=0;
for(int i=0;i<OrdersTotal();i++)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol()!=Symbol()) continue;
if(OrderMagicNumber()!=Magic) continue;
if(dir==0 || (dir>0 && OrderType()==OP_BUY) || (dir<0 && OrderType()==OP_SELL)) c++;
}
return c;
}
double SwingLowSLPoints()
{
int w = LookbackSwing;
double low = High[1]; // init high to ensure replacement
for(int i=1;i<=w;i++) if(Low[i]<low) low=Low[i];
double sl = (Bid - low)/Point;
return MathMax(sl, 5); // safety min
}
double SwingHighSLPoints()
{
int w = LookbackSwing;
double high = Low[1];
for(int i=1;i<=w;i++) if(High[i]>high) high=High[i];
double sl = (high - Ask)/Point;
return MathMax(sl, 5);
}
void CloseByTime()
{
for(int i=0;i<OrdersTotal();i++)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol()!=Symbol() || OrderMagicNumber()!=Magic) continue;
datetime opent = OrderOpenTime();
if((TimeCurrent() - opent) >= MaxMinutesHold*60)
{
if(OrderType()==OP_BUY) OrderClose(OrderTicket(), OrderLots(), Bid, Slip, clrNONE);
if(OrderType()==OP_SELL) OrderClose(OrderTicket(), OrderLots(), Ask, Slip, clrNONE);
}
}
}
int OnInit(){ return(INIT_SUCCEEDED); }
void OnDeinit(const int reason){}
void OnTick()
{
UpdateSpreadAvg();
CloseByTime();
if(!TimeFilter()) return;
if(CountPositions(0)>=1) return;
// Evaluate on new bar to reduce noise
if(!NewBar()) return;
double cvd = CalcCVD(CVD_Len);
double sp = GetSpreadPoints();
double spAvg = GetAvgSpread();
bool spreadWasWide = (sp >= spAvg * SpreadWideMul);
bool spreadIsOk = (sp <= spAvg * SpreadNowMul);
// Use last bar info for band filter
double bbMid = iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 1);
double bbStd = iStdDev(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 1);
double bbUp = bbMid + 2*bbStd;
double bbLo = bbMid - 2*bbStd;
double prevClose = iClose(Symbol(), Period(), 1);
// Long setup
if(cvd <= -CVD_Thr && spreadIsOk)
{
if(prevClose > bbLo) // avoid fresh band break
{
double slPts = SwingLowSLPoints();
double tpPts = slPts * RR;
double sl = Bid - slPts*Point;
double tp = Bid + tpPts*Point;
int tk = OrderSend(Symbol(), OP_BUY, Lots, Ask, Slip, sl, tp, "CVD Long", Magic, 0, clrNONE);
}
}
// Short setup
if(cvd >= CVD_Thr && spreadIsOk)
{
if(prevClose < bbUp)
{
double slPts = SwingHighSLPoints();
double tpPts = slPts * RR;
double sl = Ask + slPts*Point;
double tp = Ask - tpPts*Point;
int tk = OrderSend(Symbol(), OP_SELL, Lots, Bid, Slip, sl, tp, "CVD Short", Magic, 0, clrNONE);
}
}
}
//+------------------------------------------------------------------+
7. 初心者向けの検証チェックリスト
- 相場が一方向に走るトレンド局面では、エントリー頻度が落ちる設計になっているか。
- 平均スプレッドの推定が安定しているか(初期数千ティックは学習期間)。
- 通貨ごとのCVD閾値Tを適切化したか(USDJPYは狭く、GBP系は広め)。
- 勝率とRRのバランス:勝率55%・RR1.5でPF>1.2をまず目標。
- 8分ルールでの時間切れクローズが機能しているか。
8. 具体的なトレード例(イメージ)
東京後場の薄い時間に一時的な売りが重なり、M1でCVDが-85まで沈む。
直後にスプレッドが平常比2.0倍→1.15倍へ縮小。ボリンジャー下沿いから内側へ復帰。
条件一致でロング、SLは直近安値-0.6pips、TPはRR1.5で+0.9pips。
約6分で利確。以後は同方向の再エントリーを避け、回転の質を担保します。
9. リスク管理とよくある失敗
- オーバートレード:時間帯と同時ポジ制限でコントロールします。
- ニュース突発:重大指標は休む。EAにニュース回避機能を後付け可。
- 過剰最適化:パラメータを絞り、外部期間で必ずフォワード確認。
- スプレッド常時広めのブローカー:本戦略は不利。口座選定は重要。
- Lot過大:1トレードの損失が口座残高の1%超にならない範囲に。
10. 投資用語の簡易解説
- ティック出来高:ティック更新回数の近似出来高。実出来高の代替。
- CVD:買い/売りの優勢を累積した指標。本稿は疑似版。
- スプレッド:Ask−Bid。拡大は板薄や成行集中のサイン。
- RR(リスクリワード):利確幅/損切り幅の比率。
- PF(プロフィットファクター):総利益/総損失。1超で優位性。
11. 国内FX口座の一般的な開設手順(要約)
- 金融商品取引業者(第一種)の公式サイトから申込。
- 氏名・住所・職業・年収・投資経験などを入力。
- 本人確認書類(運転免許証など)とマイナンバー送付。
- リスク・重要事項の確認と同意。
- 審査通過後、ログイン情報が届き、入金方法を設定。
- MT4/MT5の接続情報を設定して動作確認。
スプレッド、約定力、サポート、出金手続きは口座選びの重要比較軸です。
12. 運用オペレーション(デイリー/ウィークリー)
- デイリー:ログ点検、約定履歴の異常検知、スリッページ監視。
- ウィークリー:パラメータの微調整(±1段階まで)、損益の偏り要因の洗い出し。
- マンスリー:ブローカー品質の見直し、通貨ペアの入替検討。
13. まとめ(実務観点)
板が見えなくても、疑似CVD×スプレッド回帰×時間帯を重ねるだけで、
初心者が取り組める再現性の高いスキャル土台は作れます。重要なのは、
小さく素早く・淡々と・再現可能の3点です。EAで機械化し、
過度な裁量と感情を排除することで、学習速度と資金保全の両立を図れます。
本記事では、具体的な売買ルール、検証手順、MQL4コードを提示しました。各自の環境に合わせて微調整し、必ずデモ検証を経てから実運用に移行してください。
コメント