London-New York Dual Session Breakout Trailing Stop Quantitative Trading Strategy

ORB EMA SL TP RRR 交易会话 追踪止损 价格突破 风险管理
Created on: 2025-04-27 11:32:24 Modified on: 2025-04-27 11:32:24
Copy: 2 Number of hits: 334
avatar of ianzeng123 ianzeng123
2
Follow
319
Followers

 London-New York Dual Session Breakout Trailing Stop Quantitative Trading Strategy  London-New York Dual Session Breakout Trailing Stop Quantitative Trading Strategy

Overview

The Dual Session Opening Range Breakout Trailing Stop Quantitative Trading Strategy is a trading system based on price breakouts during the first 15 minutes of the London and New York trading sessions. This strategy captures price momentum at the beginning of these two major financial centers by entering trades when price breaks above or below the high or low levels established during the first 15 minutes. The core feature of this strategy is the implementation of a trailing stop mechanism, which protects profits while allowing them to grow. The strategy also offers an optional moving average filter to improve trade quality.

Strategy Principles

The mechanism of this strategy revolves around two key time periods: London market opening (3:00-3:15 New York time) and New York market opening (9:30-9:45 New York time). The strategy workflow is as follows:

  1. Records the price highs and lows during the first 15 minutes of both London and New York openings, forming “price ranges”
  2. After the price range is formed, the strategy checks if the range size meets the minimum requirement (default 2 points)
  3. If the price breaks above the range high from below and meets the EMA filter condition (if enabled), a long position is opened
  4. If the price breaks below the range low from above and meets the EMA filter condition (if enabled), a short position is opened
  5. Stop loss is set at a distance of one range height beyond the opposite boundary of the price range
  6. Take profit target is set at a distance determined by the risk-reward ratio (default 2.0) multiplied by the range height
  7. A trailing stop is also implemented, defaulted at 8 minimum price movement units, adjusting as price moves favorably

The key logic of the strategy is to capture directional price breakouts during the initial period of trading sessions, which often indicates potential trending movements. By using a trailing stop mechanism, the strategy can protect existing profits while allowing profitable trades to continue running.

Strategy Advantages

After in-depth analysis, this strategy offers the following advantages:

  1. Dual Session Trading Opportunities: By focusing on both London and New York openings, the strategy can capture volatility across two major trading sessions, increasing trading opportunities.
  2. Trailing Stop Mechanism: Compared to fixed take profit levels, the trailing stop can protect profits while allowing winning trades to develop further, effectively increasing average profits.
  3. Robust Risk Control: The strategy employs dynamic stop loss settings based on volatility (range size), making risk management more adaptive to market conditions.
  4. High Customizability: Users can adjust the risk-reward ratio, minimum range size, trailing stop points, and whether to use the EMA filter to adapt to different trading instruments and personal risk preferences.
  5. Technical Indicator Filtering: The optional 5-minute EMA filter helps avoid counter-trend trading, improving trade quality.
  6. One Trade Per Session Limit: Built-in trading flags ensure that at most one trade is executed per session, avoiding frequent trading costs and risks.

Strategy Risks

Despite its well-designed structure, the strategy has the following potential risks:

  1. False Breakout Risk: Prices may briefly break through range boundaries and then immediately reverse, triggering stop losses. To address this risk, consider adding confirmation mechanisms, such as requiring the price to maintain a certain duration or reach a certain magnitude after breakout before entering.
  2. Money Management Issues: The strategy defaults to using a fixed contract quantity, which may not be suitable for all account sizes. Position size should be adjusted according to account size and risk tolerance.
  3. Parameter Optimization Risk: Excessive parameter optimization may lead to curve fitting, resulting in poor performance in future market environments. Robustness testing of parameters should be noted.
  4. Market Environment Dependency: This strategy may frequently trigger stop losses in oscillating or trendless markets. Consider adding market environment filtering conditions.
  5. Time Zone Setting Issues: The code uses New York time zone, and users need to ensure consistency with trading platform time zone settings to avoid misaligned trading signals.
  6. Holiday Effects: Special trading days and holidays may affect strategy performance, and the strategy does not include holiday filtering logic.

Strategy Optimization Directions

Based on the strategy analysis, here are possible optimization directions:

  1. Add Confirmation Mechanisms: Consider adding additional confirmation conditions after price breakouts, such as volume breakouts or requiring multiple consecutive price bars to maintain the breakout direction, reducing losses from false breakouts.
  2. Dynamic Money Management: Dynamically adjust position size based on market volatility and account size to optimize risk-reward ratio.
  3. Market Environment Filtering: Introduce volatility indicators or trend strength indicators to pause trading in market environments unsuitable for breakout strategies.
  4. Multi-Timeframe Confirmation: Combine with trend direction from longer timeframes, only trading in directions consistent with the larger trend.
  5. Optimize Entry Timing: Consider entering on price pullbacks to key support/resistance levels, rather than directly at breakout points, to obtain better entry prices.
  6. Add Time Filtering: Analyze historical performance during different trading days and time periods to avoid underperforming times.
  7. Multi-Instrument Correlation Analysis: Consider correlations between different trading instruments to avoid simultaneously holding multiple highly correlated positions.

Summary

The Dual Session Opening Range Breakout Trailing Stop Quantitative Trading Strategy is a breakout trading system designed for the London and New York financial center opening sessions. By capturing opening momentum and direction, combined with a trailing stop mechanism, this strategy can maximize profit potential while controlling risk. Although there are risks such as false breakouts and market environment dependencies, the stability and profitability of the strategy can be further enhanced through reasonable parameter settings and additional filtering conditions. This strategy is particularly suitable for markets with higher volatility and ample liquidity. Traders should make appropriate adjustments based on their risk tolerance and trading objectives when using this strategy.

Strategy source code
/*backtest
start: 2024-04-27 00:00:00
end: 2025-04-25 08:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"SOL_USDT"}]
*/

//@version=6
strategy("ORB-LD-NY-Trail Strategy", overlay=true,
     default_qty_type=strategy.fixed, default_qty_value=1,
     calc_on_order_fills=true, calc_on_every_tick=true)

// =========================
// USER INPUTS
// =========================
riskReward      = input.float(2.0, "Risk-Reward Ratio", minval=1.0)
minBoxSize      = input.float(2.0, "Minimum Box Size (points)")
trailStopTicks  = input.int(8, "Trailing Stop (ticks)", minval=1)
useEmaFilter    = input.bool(false, "Use 5-min EMA Filter?")

tickSize        = syminfo.mintick         // auto-detect min tick for symbol
trailStopOffset = trailStopTicks * tickSize
emaSource       = request.security(syminfo.tickerid, "5", ta.ema(close, 200))  // 5-min chart EMA

// =========================
// SESSION TIMES
// =========================
londonStart = timestamp("America/New_York", year, month, dayofmonth, 3, 0)
londonEnd   = timestamp("America/New_York", year, month, dayofmonth, 3, 15)
nyStart     = timestamp("America/New_York", year, month, dayofmonth, 9, 30)
nyEnd       = timestamp("America/New_York", year, month, dayofmonth, 9, 45)

inLondon = time >= londonStart and time <= londonEnd
inNY     = time >= nyStart and time <= nyEnd

// =========================
// ONE TRADE PER SESSION FLAGS
// =========================
var bool londonTraded = false
var bool nyTraded     = false

// =========================
// LONDON BOX
// =========================
var float londonHigh    = na
var float londonLow     = na
var float londonBoxHigh = na
var float londonBoxLow  = na

if inLondon
    if na(londonHigh)
        londonBoxHigh := na
        londonBoxLow  := na
        londonTraded  := false
    londonHigh := na(londonHigh) ? high : math.max(londonHigh, high)
    londonLow  := na(londonLow)  ? low  : math.min(londonLow,  low)

if not inLondon and na(londonBoxHigh) and not na(londonHigh) and not na(londonLow)
    londonBoxHigh := londonHigh
    londonBoxLow  := londonLow
    londonHigh    := na
    londonLow     := na

if time > londonEnd and not na(londonBoxHigh) and not londonTraded
    boxRange = londonBoxHigh - londonBoxLow
    if boxRange >= minBoxSize
        // Standard SL/TP logic
        longSL  = londonBoxHigh - boxRange
        longTP  = londonBoxHigh + boxRange * riskReward
        shortSL = londonBoxLow  + boxRange
        shortTP = londonBoxLow  - boxRange * riskReward

        // === LONDON LONG ===
        condLong1 = close[1] <= londonBoxHigh
        condLong2 = close > londonBoxHigh
        condLong3 = (not useEmaFilter) or (close > emaSource)

        if condLong1 and condLong2 and condLong3
            strategy.entry("London Long", strategy.long)
            strategy.exit("Exit London Long", from_entry="London Long",
                          stop=longSL, limit=longTP,
                          trail_points=trailStopOffset)
            londonTraded := true

        // === LONDON SHORT ===
        condShort1 = close[1] >= londonBoxLow
        condShort2 = close < londonBoxLow
        condShort3 = (not useEmaFilter) or (close < emaSource)

        if not londonTraded and condShort1 and condShort2 and condShort3
            strategy.entry("London Short", strategy.short)
            strategy.exit("Exit London Short", from_entry="London Short",
                          stop=shortSL, limit=shortTP,
                          trail_points=trailStopOffset)
            londonTraded := true

// =========================
// NY BOX
// =========================
var float nyHigh    = na
var float nyLow     = na
var float nyBoxHigh = na
var float nyBoxLow  = na

if inNY
    if na(nyHigh)
        nyBoxHigh := na
        nyBoxLow  := na
        nyTraded  := false
    nyHigh := na(nyHigh) ? high : math.max(nyHigh, high)
    nyLow  := na(nyLow)  ? low  : math.min(nyLow,  low)

if not inNY and na(nyBoxHigh) and not na(nyHigh) and not na(nyLow)
    nyBoxHigh := nyHigh
    nyBoxLow  := nyLow
    nyHigh    := na
    nyLow     := na

if time > nyEnd and not na(nyBoxHigh) and not nyTraded
    boxRange = nyBoxHigh - nyBoxLow
    if boxRange >= minBoxSize
        longSL  = nyBoxHigh - boxRange
        longTP  = nyBoxHigh + boxRange * riskReward
        shortSL = nyBoxLow  + boxRange
        shortTP = nyBoxLow  - boxRange * riskReward

        // === NY LONG ===
        condNYLong1 = close[1] <= nyBoxHigh
        condNYLong2 = close > nyBoxHigh
        condNYLong3 = (not useEmaFilter) or (close > emaSource)

        if condNYLong1 and condNYLong2 and condNYLong3
            strategy.entry("NY Long", strategy.long)
            strategy.exit("Exit NY Long", from_entry="NY Long",
                          stop=longSL, limit=longTP,
                          trail_points=trailStopOffset)
            nyTraded := true

        // === NY SHORT ===
        condNYShort1 = close[1] >= nyBoxLow
        condNYShort2 = close < nyBoxLow
        condNYShort3 = (not useEmaFilter) or (close < emaSource)

        if not nyTraded and condNYShort1 and condNYShort2 and condNYShort3
            strategy.entry("NY Short", strategy.short)
            strategy.exit("Exit NY Short", from_entry="NY Short",
                          stop=shortSL, limit=shortTP,
                          trail_points=trailStopOffset)
            nyTraded := true

// Visual session background
bgcolor(inLondon ? color.new(color.fuchsia, 85) : na)
bgcolor(inNY     ? color.new(color.green,   85) : na)