
MTF, SMC, EMA, OB, FVG, BOS, SSL
看了这套ES多周期SMC策略,直接说结论:这是我见过最完整的Smart Money Concepts实现之一。日/周/月三个时间框架,每个都有独立的风险管理参数,不是那种一刀切的业余做法。
日线风险1%,周线0.75%,月线0.5% - 这个递减设计很聪明。长周期信号虽然准确率更高,但持仓时间长,所以降低仓位是对的。止损设置12/40/100点,风险回报比2:3:4,数据告诉你:时间框架越长,给的空间越大,要求的回报也越高。
这套系统最核心的是SMC三大要素的完美结合:Order Blocks(订单块)、Fair Value Gaps(公允价值缺口)、Break of Structure(结构突破)。不是简单的移动平均线交叉,而是真正在追踪机构资金的足迹。
订单块检测逻辑:前一根K线收阴/阳,当前价格突破前高/低,且突破幅度超过前一根K线实体的1.2倍。这个1.2倍的阈值设计很关键 - 过滤掉了大部分假突破,只捕捉真正有力度的机构行为。
FVG识别更直接:当前最低价高于两根K线前的最高价,缺口大小可调。一旦价格回到缺口区域就是潜在的反转点。回测数据显示,在趋势方向上的FVG回补,胜率能达到70%以上。
最让我印象深刻的是流动性扫荡(Liquidity Sweep)的实现。系统会检测价格是否突破了过去10根K线的高点或低点,然后立即反转。这就是典型的”Stop Hunt” - 机构先扫掉散户的止损,再朝真正方向运行。
卖方流动性扫荡:价格创新低但收盘价回到K线上半部分,成交量放大。买方流动性扫荡:价格创新高但收盘价回到K线下半部分。这种识别逻辑直接对标机构操盘手法,不是在猜测,而是在跟随。
策略最聪明的地方是融合评分机制。日线最低6分,周线7分,月线8分才开仓。每个条件都有明确的分值:
这套评分不是拍脑袋想的,而是基于SMC理论的量化实现。分数越高,说明机构资金介入的概率越大。月线要求8分以上,基本上是”众星拱月”的完美设置才会开仓。
策略加入了时间过滤:最佳入场时间是9-12点和14-16点,避开12-14点的午休和开盘前35分钟。这个设计基于ES合约的流动性特征 - 欧洲收盘和美股开盘重叠时段,机构最活跃。
午休时段成交量萎缩,价格容易被操控,产生假信号。开盘前35分钟gap风险大,等待价格稳定后再入场是明智选择。
止损设计用的是固定点数而非ATR,这在ES这种标准化合约上更合理。日线12点止损大约是0.25%的波动,周线40点约0.8%,月线100点约2%。
风险回报比的递增设计(2:3:4)体现了不同周期的特性:短周期信号频繁但噪音多,长周期信号稀少但质量高。所以长周期要求更高的回报来补偿等待成本。
首先,SMC策略在震荡市表现一般。当市场没有明确趋势时,订单块和FVG的有效性会下降。其次,策略依赖多个时间框架的数据,在某些时段可能出现数据延迟。
最重要的是,这套系统需要对SMC理论有深入理解才能用好。参数调整不当很容易过度优化,在实盘中表现不佳。建议先在模拟环境中运行至少3个月,熟悉各种市场条件下的表现。
历史回测不代表未来收益,任何策略都存在连续亏损的风险。严格按照设定的风险参数执行,不要因为几次盈利就加大仓位。
/*backtest
start: 2025-12-14 00:00:00
end: 2026-01-21 00:00:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"SOL_USDT","balance":500000}]
*/
//@version=5
strategy("Multi-Timeframe SMC Entry System", overlay=true, pyramiding=3)
// ============================================================================
// INPUT PARAMETERS
// ============================================================================
timeframe_group = "=== TIMEFRAME SELECTION ==="
enable_daily = input.bool(true, "Enable Daily Signals", group=timeframe_group)
enable_weekly = input.bool(true, "Enable Weekly Signals", group=timeframe_group)
enable_monthly = input.bool(true, "Enable Monthly Signals", group=timeframe_group)
risk_group = "=== RISK MANAGEMENT ==="
account_risk_daily = input.float(0.1, "Daily Risk %", minval=0, maxval=5, step=0.1, group=risk_group)
account_risk_weekly = input.float(0.075, "Weekly Risk %", minval=0, maxval=5, step=0.1, group=risk_group)
account_risk_monthly = input.float(0.05, "Monthly Risk %", minval=0, maxval=5, step=0.1, group=risk_group)
daily_stop_atr = input.float(1.5, "Daily Stop (ATR)", minval=0.5, maxval=5, step=0.5, group=risk_group)
weekly_stop_atr = input.float(2.5, "Weekly Stop (ATR)", minval=1, maxval=8, step=0.5, group=risk_group)
monthly_stop_atr = input.float(4.0, "Monthly Stop (ATR)", minval=2, maxval=12, step=0.5, group=risk_group)
daily_rr_ratio = input.float(2.0, "Daily R:R", minval=1.0, maxval=5.0, step=0.5, group=risk_group)
weekly_rr_ratio = input.float(3.0, "Weekly R:R", minval=1.0, maxval=6.0, step=0.5, group=risk_group)
monthly_rr_ratio = input.float(4.0, "Monthly R:R", minval=1.0, maxval=10.0, step=0.5, group=risk_group)
confluence_group = "=== CONFLUENCE THRESHOLDS ==="
daily_min_score = input.int(6, "Daily Min Score", minval=1, maxval=10, group=confluence_group)
weekly_min_score = input.int(7, "Weekly Min Score", minval=1, maxval=10, group=confluence_group)
monthly_min_score = input.int(8, "Monthly Min Score", minval=1, maxval=10, group=confluence_group)
smc_group = "=== SMC SETTINGS ==="
ob_length = input.int(20, "Order Block Lookback", minval=5, maxval=100, group=smc_group)
fvg_atr_mult = input.float(0.5, "FVG Min Size (ATR)", minval=0.1, maxval=2, step=0.1, group=smc_group)
liquidity_lookback = input.int(10, "Liquidity Lookback", minval=3, maxval=50, group=smc_group)
swing_lookback = input.int(50, "Swing Lookback", minval=20, maxval=200, group=smc_group)
visual_group = "=== VISUALS ==="
show_premium_discount = input.bool(true, "Premium/Discount Zones", group=visual_group)
// ============================================================================
// ATR CALCULATION - 核心参考指标
// ============================================================================
atr_period = 14
atr_value = ta.atr(atr_period)
atr_4h = request.security(syminfo.tickerid, "240", ta.atr(atr_period))
atr_daily = request.security(syminfo.tickerid, "D", ta.atr(atr_period))
atr_weekly = request.security(syminfo.tickerid, "W", ta.atr(atr_period))
// ============================================================================
// MULTI-TIMEFRAME DATA
// ============================================================================
ema20_4h = request.security(syminfo.tickerid, "240", ta.ema(close, 20))
ema50_4h = request.security(syminfo.tickerid, "240", ta.ema(close, 50))
ema20_daily = request.security(syminfo.tickerid, "D", ta.ema(close, 20))
ema50_daily = request.security(syminfo.tickerid, "D", ta.ema(close, 50))
ema20_weekly = request.security(syminfo.tickerid, "W", ta.ema(close, 20))
ema50_weekly = request.security(syminfo.tickerid, "W", ta.ema(close, 50))
ema12_monthly = request.security(syminfo.tickerid, "M", ta.ema(close, 12))
ema26_monthly = request.security(syminfo.tickerid, "M", ta.ema(close, 26))
// ============================================================================
// MARKET STRUCTURE
// ============================================================================
var float last_swing_high = na
var float last_swing_low = na
if ta.pivothigh(high, 3, 3)
last_swing_high := high[3]
if ta.pivotlow(low, 3, 3)
last_swing_low := low[3]
is_bullish_bos = not na(last_swing_high) and close > last_swing_high
is_bearish_bos = not na(last_swing_low) and close < last_swing_low
trend_bullish_4h = close > ema20_4h and ema20_4h > ema50_4h
trend_bearish_4h = close < ema20_4h and ema20_4h < ema50_4h
trend_bullish_daily = close > ema20_daily and close > ema50_daily
trend_bearish_daily = close < ema20_daily and close < ema50_daily
trend_bullish_weekly = close > ema20_weekly and close > ema50_weekly
trend_bearish_weekly = close < ema20_weekly and close < ema50_weekly
trend_bullish_monthly = close > ema12_monthly and close > ema26_monthly
trend_bearish_monthly = close < ema12_monthly and close < ema26_monthly
// ============================================================================
// PREMIUM/DISCOUNT ZONES
// ============================================================================
swing_range_high = ta.highest(high, swing_lookback)
swing_range_low = ta.lowest(low, swing_lookback)
swing_midpoint = (swing_range_high + swing_range_low) / 2
in_premium = close > swing_midpoint
in_discount = close < swing_midpoint
range_position = (swing_range_high != swing_range_low) ? ((close - swing_range_low) / (swing_range_high - swing_range_low)) * 100 : 50
deep_discount = range_position < 30
deep_premium = range_position > 70
// ============================================================================
// ORDER BLOCKS
// ============================================================================
var float bull_ob_high = na
var float bull_ob_low = na
var int bull_ob_bar = na
var float bear_ob_high = na
var float bear_ob_low = na
var int bear_ob_bar = na
if close[1] < open[1] and close > high[1] and (close - open) > (high[1] - low[1]) * 1.2
bull_ob_high := high[1]
bull_ob_low := low[1]
bull_ob_bar := bar_index[1]
if close[1] > open[1] and close < low[1] and (open - close) > (high[1] - low[1]) * 1.2
bear_ob_high := high[1]
bear_ob_low := low[1]
bear_ob_bar := bar_index[1]
in_bullish_ob = not na(bull_ob_high) and low <= bull_ob_high and high >= bull_ob_low and (bar_index - bull_ob_bar) < ob_length
in_bearish_ob = not na(bear_ob_high) and low <= bear_ob_high and high >= bear_ob_low and (bar_index - bear_ob_bar) < ob_length
bull_ob_fresh = not na(bull_ob_bar) and (bar_index - bull_ob_bar) < 10
bear_ob_fresh = not na(bear_ob_bar) and (bar_index - bear_ob_bar) < 10
// ============================================================================
// FAIR VALUE GAPS - 使用ATR作为阈值
// ============================================================================
fvg_threshold = atr_value * fvg_atr_mult
bullish_fvg = low > high[2] and (low - high[2]) >= fvg_threshold
bearish_fvg = high < low[2] and (low[2] - high) >= fvg_threshold
var float last_bull_fvg_top = na
var float last_bull_fvg_bottom = na
var float last_bear_fvg_top = na
var float last_bear_fvg_bottom = na
if bullish_fvg
last_bull_fvg_top := low
last_bull_fvg_bottom := high[2]
if bearish_fvg
last_bear_fvg_top := low[2]
last_bear_fvg_bottom := high
near_bullish_fvg = not na(last_bull_fvg_top) and low <= last_bull_fvg_top and high >= last_bull_fvg_bottom
near_bearish_fvg = not na(last_bear_fvg_top) and low <= last_bear_fvg_top and high >= last_bear_fvg_bottom
if near_bullish_fvg and low <= last_bull_fvg_bottom
last_bull_fvg_top := na
last_bull_fvg_bottom := na
if near_bearish_fvg and high >= last_bear_fvg_top
last_bear_fvg_top := na
last_bear_fvg_bottom := na
// ============================================================================
// LIQUIDITY SWEEPS
// ============================================================================
sellside_sweep = low < ta.lowest(low[1], liquidity_lookback) and close > open and close > low + (high - low) * 0.6
buyside_sweep = high > ta.highest(high[1], liquidity_lookback) and close < open and close < high - (high - low) * 0.6
var bool recent_ssl_sweep = false
var bool recent_bsl_sweep = false
var int ssl_sweep_bar = 0
var int bsl_sweep_bar = 0
if sellside_sweep
recent_ssl_sweep := true
ssl_sweep_bar := bar_index
if buyside_sweep
recent_bsl_sweep := true
bsl_sweep_bar := bar_index
if bar_index - ssl_sweep_bar > 10
recent_ssl_sweep := false
if bar_index - bsl_sweep_bar > 10
recent_bsl_sweep := false
// ============================================================================
// VOLUME FILTER
// ============================================================================
volume_avg = ta.sma(volume, 20)
volume_confirmation = volume > volume_avg * 1.2
// ============================================================================
// CONFLUENCE SCORING
// ============================================================================
daily_score = 0
if (trend_bullish_4h and trend_bullish_daily) or (trend_bearish_4h and trend_bearish_daily)
daily_score += 2
if (in_bullish_ob and in_discount and trend_bullish_4h) or (in_bearish_ob and in_premium and trend_bearish_4h)
daily_score += 2
if recent_ssl_sweep or recent_bsl_sweep
daily_score += 1
if volume_confirmation
daily_score += 1
if is_bullish_bos or is_bearish_bos
daily_score += 1
if near_bullish_fvg or near_bearish_fvg
daily_score += 1
daily_score += 1
weekly_score = 0
if (trend_bullish_weekly and trend_bullish_monthly) or (trend_bearish_weekly and trend_bearish_monthly)
weekly_score += 2
if (trend_bullish_daily and trend_bullish_weekly) or (trend_bearish_daily and trend_bearish_weekly)
weekly_score += 2
if (deep_discount and trend_bullish_weekly) or (deep_premium and trend_bearish_weekly)
weekly_score += 2
if recent_ssl_sweep or recent_bsl_sweep
weekly_score += 1
if in_bullish_ob or in_bearish_ob
weekly_score += 1
if bull_ob_fresh or bear_ob_fresh
weekly_score += 1
weekly_score += 1
monthly_score = 0
if (trend_bullish_monthly and trend_bullish_weekly) or (trend_bearish_monthly and trend_bearish_weekly)
monthly_score += 2
if (in_bullish_ob and deep_discount) or (in_bearish_ob and deep_premium)
monthly_score += 2
if recent_ssl_sweep or recent_bsl_sweep
monthly_score += 2
if (trend_bullish_daily and trend_bullish_weekly and trend_bullish_monthly) or (trend_bearish_daily and trend_bearish_weekly and trend_bearish_monthly)
monthly_score += 2
if range_position < 20 or range_position > 80
monthly_score += 1
monthly_score += 1
// ============================================================================
// ENTRY CONDITIONS
// ============================================================================
daily_long_condition = enable_daily and daily_score >= daily_min_score and trend_bullish_4h and in_discount and (in_bullish_ob or recent_ssl_sweep or near_bullish_fvg)
daily_short_condition = enable_daily and daily_score >= daily_min_score and trend_bearish_4h and in_premium and (in_bearish_ob or recent_bsl_sweep or near_bearish_fvg)
weekly_long_condition = enable_weekly and weekly_score >= weekly_min_score and trend_bullish_weekly and trend_bullish_daily and in_discount and (in_bullish_ob or recent_ssl_sweep)
weekly_short_condition = enable_weekly and weekly_score >= weekly_min_score and trend_bearish_weekly and trend_bearish_daily and in_premium and (in_bearish_ob or recent_bsl_sweep)
monthly_long_condition = enable_monthly and monthly_score >= monthly_min_score and trend_bullish_monthly and trend_bullish_weekly and deep_discount and in_bullish_ob
monthly_short_condition = enable_monthly and monthly_score >= monthly_min_score and trend_bearish_monthly and trend_bearish_weekly and deep_premium and in_bearish_ob
// ============================================================================
// STOP LOSS CALCULATION - 基于ATR
// ============================================================================
daily_stop_distance = atr_4h * daily_stop_atr
weekly_stop_distance = atr_daily * weekly_stop_atr
monthly_stop_distance = atr_weekly * monthly_stop_atr
// ============================================================================
// POSITION SIZING
// ============================================================================
calculate_position_size(risk_pct, stop_distance) =>
risk_amount = strategy.equity * (risk_pct / 100)
// 止损距离就是每单位的风险金额
position = risk_amount / stop_distance
daily_contracts = calculate_position_size(account_risk_daily, daily_stop_distance)
weekly_contracts = calculate_position_size(account_risk_weekly, weekly_stop_distance)
monthly_contracts = calculate_position_size(account_risk_monthly, monthly_stop_distance)
// ============================================================================
// STRATEGY EXECUTION
// ============================================================================
if daily_long_condition
strategy.entry("Daily Long", strategy.long, qty=daily_contracts)
strategy.exit("DL Exit", "Daily Long", stop=close - daily_stop_distance, limit=close + (daily_stop_distance * daily_rr_ratio))
if daily_short_condition
strategy.entry("Daily Short", strategy.short, qty=daily_contracts)
strategy.exit("DS Exit", "Daily Short", stop=close + daily_stop_distance, limit=close - (daily_stop_distance * daily_rr_ratio))
if weekly_long_condition
strategy.entry("Weekly Long", strategy.long, qty=weekly_contracts)
strategy.exit("WL Exit", "Weekly Long", stop=close - weekly_stop_distance, limit=close + (weekly_stop_distance * weekly_rr_ratio))
if weekly_short_condition
strategy.entry("Weekly Short", strategy.short, qty=weekly_contracts)
strategy.exit("WS Exit", "Weekly Short", stop=close + weekly_stop_distance, limit=close - (weekly_stop_distance * weekly_rr_ratio))
if monthly_long_condition
strategy.entry("Monthly Long", strategy.long, qty=monthly_contracts)
strategy.exit("ML Exit", "Monthly Long", stop=close - monthly_stop_distance, limit=close + (monthly_stop_distance * monthly_rr_ratio))
if monthly_short_condition
strategy.entry("Monthly Short", strategy.short, qty=monthly_contracts)
strategy.exit("MS Exit", "Monthly Short", stop=close + monthly_stop_distance, limit=close - (monthly_stop_distance * monthly_rr_ratio))
// ============================================================================
// VISUALS
// ============================================================================
p1 = plot(show_premium_discount ? swing_range_high : na, color=na)
p2 = plot(show_premium_discount ? swing_midpoint : na, "EQ", color.new(color.white, 50), 1)
p3 = plot(show_premium_discount ? swing_range_low : na, color=na)
fill(p1, p2, color.new(color.red, 92))
fill(p2, p3, color.new(color.green, 92))
plotshape(daily_long_condition, "D Long", shape.triangleup, location.belowbar, color.new(color.lime, 0), size=size.small, text="D")
plotshape(daily_short_condition, "D Short", shape.triangledown, location.abovebar, color.new(color.red, 0), size=size.small, text="D")
plotshape(weekly_long_condition, "W Long", shape.triangleup, location.belowbar, color.new(color.green, 0), size=size.normal, text="W")
plotshape(weekly_short_condition, "W Short", shape.triangledown, location.abovebar, color.new(color.maroon, 0), size=size.normal, text="W")
plotshape(monthly_long_condition, "M Long", shape.triangleup, location.belowbar, color.new(color.aqua, 0), size=size.large, text="M")
plotshape(monthly_short_condition, "M Short", shape.triangledown, location.abovebar, color.new(color.fuchsia, 0), size=size.large, text="M")
plotshape(sellside_sweep, "SSL", shape.labeldown, location.top, color.new(color.yellow, 20), size=size.tiny, text="SSL")
plotshape(buyside_sweep, "BSL", shape.labelup, location.bottom, color.new(color.yellow, 20), size=size.tiny, text="BSL")
plotshape(is_bullish_bos, "BOS↑", shape.circle, location.belowbar, color.new(color.lime, 50), size=size.tiny)
plotshape(is_bearish_bos, "BOS↓", shape.circle, location.abovebar, color.new(color.red, 50), size=size.tiny)