Ý tưởng cốt lõi của chiến lược này là theo dõi xu hướng bằng cách phát hiện sự đột phá của các đường trung bình động trên các khung thời gian cao hơn. Khi giá phá vỡ trên hoặc phá vỡ dưới đường trung bình động trên một khung thời gian cao hơn, nó báo hiệu sự khởi đầu tiềm năng của một xu hướng mới, cho phép các nhà giao dịch có vị trí phù hợp.
Chiến lược được phát triển trong Pine Script và bao gồm các thành phần chính sau:
Các đầu vào
Định nghĩa thời gian tham số đầu vào là thời gian trung bình động, mặc định là 200; và khung thời gian là khung thời gian thanh, mặc định là D (các thanh hàng ngày).
Trung bình di chuyển
Tính toán trung bình động theo cấp số nhân (EMA) bằng cách sử dụng hàm ta.ema.
Khám phá đột phá
Xác định sự cố và sự cố bằng cách sử dụng các hàm ta.crossover và ta.crossunder.
Kế hoạch tín hiệu
Định hướng mũi tên lên và xuống trên các thanh khi xảy ra sự đột phá.
Nhập và xuất thương
Tham gia giao dịch trên tín hiệu đột phá và ra khỏi khi giá đạt khoảng cách dừng lỗ 2x.
Chiến lược này chủ yếu tận dụng khả năng theo dõi xu hướng của đường trung bình động trên các khung thời gian cao hơn. Nó thực hiện logic đột phá đơn giản cho giao dịch xu hướng, làm cho nó trở thành một chiến lược đột phá thông thường.
Những lợi thế chính của chiến lược này bao gồm:
Logic đơn giản, dễ hiểu và thành thạo.
Chỉ phụ thuộc vào một chỉ số, với điều chỉnh tham số tối thiểu.
Các tín hiệu đột phá có xu hướng phù hợp với xu hướng, tránh giao dịch quá mức.
Các khung thời gian cao hơn thể hiện rõ các xu hướng chính mà không gây ồn.
Kết hợp khung thời gian linh hoạt phục vụ các sản phẩm khác nhau.
Dễ dàng mở rộng trên các sản phẩm, tránh rút đồng thời.
Những rủi ro tiềm ẩn là:
Các tín hiệu đột phá có thể trở thành tín hiệu sai, không thể lọc tiếng ồn thị trường hiệu quả.
Không thể tận dụng các cơ hội ngắn hạn.
Mất rất nhiều nếu xu hướng lớn sai.
Sự không phù hợp khung thời gian giữa đường trung bình động và khung thời gian giao dịch có thể dẫn đến giao dịch quá mức hoặc mất lợi nhuận.
Thiếu stop loss thời gian thực có thể dẫn đến tổn thất phóng đại.
Các giải pháp có thể bao gồm kết hợp với các chỉ số theo xu hướng, thêm các bộ lọc, rút ngắn thời gian giữ, thực hiện stop loss động v.v.
Chiến lược có thể được cải thiện trong các khía cạnh sau:
Thêm các chỉ số theo xu hướng như MACD, KD để tăng độ tin cậy đột phá.
Thêm các bộ lọc dựa trên khối lượng hoặc Bollinger Bands để tránh đột phá sai.
Tối ưu hóa điều chỉnh tham số để phù hợp với thời gian giữ với chu kỳ xu hướng.
Tích hợp stop loss thời gian thực để kiểm soát lỗ giao dịch duy nhất.
Khám phá các kỹ thuật học máy để tối ưu hóa tham số động.
Kiểm tra các kết hợp phân bổ tài sản khác nhau để tăng cường sự ổn định tổng thể.
Tóm lại, đây là một chiến lược đơn giản và thực tế để theo dõi xu hướng thông qua các đột phá trung bình động. Nó dễ hiểu và thực hiện, phục vụ như một chiến lược giới thiệu tốt cho giao dịch algo. Nhưng nó cũng có một số lỗ hổng cần phải được giải quyết thông qua sự kết hợp của các chỉ số, điều chỉnh tham số, dừng mất động v.v. Vẫn còn nhiều chỗ cho cải tiến và mở rộng.
/*backtest start: 2023-09-29 00:00:00 end: 2023-10-29 00:00:00 period: 1h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ // @version=5 // Open-Range-Breakout strategy // No license. Free and Open Source. strategy('Strategy: ORB', shorttitle="ORB", overlay=true , currency=currency.NONE, initial_capital=100000) // Inputs period = input.int(defval=15, title="TimeRange", tooltip="The range in minutes (default: 15m)") sessionInput = input(defval="0915-0930", title="Time Range", group="ORB settings", tooltip='What is the timeperiod (default 9:15AM to 9:30AM, exchange timezone') hide = input.bool(defval = false, title="Hide ORB Range", group="ORB setting", tooltip = 'Hide the ORB range drawing') // SL Related slAtrLen = input.int(defval=14, title="ATR Period for placing SL", group="StopLoss settings") showSLLines = input.bool(defval=false, title="Show SL lines in chart", tooltip="Show SL lines also as dotted lines in chart. Note: chart may look untidy.", group="StopLoss settings") // Further Filtering ignoreMementumVolume = input.bool(defval=false, title="Ignore Momentum & Volume", tooltip="Ignore Momentum & Volume to find out trades", group="Strengh Settings") rsiLen = input.int(defval=14, title="Momentum Period", group="Strengh Settings", tooltip = 'To determine the momentum, RSI period is set default to 100') rsiBullish = input.int(defval=50, step=1, title="Bullish Momentum", group="Strengh Settings", tooltip = 'Bullish Momentum, default set to RSI as 50') rsiBearish = input.int(defval=50, step=1, title="Bearish Momentum", group="Strengh Settings", tooltip = 'Bearish Momentum, default set to RSI as 50') volAvg = input.int(defval=20, step=1, title="Volume Average Period", group="Strengh Settings", tooltip = 'To calculate average volume, how many historical bars are considered. Default: 20.') volThreshold = input.float(defval=1, step=0.1, title="Volume Strengh", group="Strengh Settings", tooltip = 'Multiplier: How big the current bar volume compared to average of last 20') trendPeriod = input.int(defval=200, step=1, title="Trend Period", group="Trend Settings", tooltip = 'To calculate trend, what period is considered. Default: 200.') hideTrend = input.bool(defval = false, title="Hide the trend line", group="Trend Settings", tooltip = 'Hide the trend') hidePDHCL = input.bool(defval = false, title="Hide the PDHCL (prev day High Close Low range)", tooltip = 'Hide the Previous Day High, Close, Low lines') hideTable = input.bool(defval = false, title="Hide the Summary Table", tooltip = 'Hide the summary table.') // Trade related rrRatio = input.float(title='Risk:Reward', step=0.1, defval=2.0, group="Trade settings") endOfDay = input.int(defval=1500, title="Close all trades, default is 3:00 PM, 1500 hours (integer)", group="Trade settings") mktAlwaysOn = input.bool(defval=true, title="Markets that never closed (Crypto, Forex, Commodity)", tooltip="Some markers never closes. For those cases, make this checked.", group="Trade settings") lotSize = input.int(title='Lot Size', step=1, defval=1, group="Trade settings") // Util method is_newbar(res) => timeframe.change(time(res)) != 0 // print table printTable(txt) => var table t = table.new(position.bottom_right, 1, 1) table.cell(t, 0, 0, txt, text_halign = text.align_left, bgcolor = color.lime) // globals t = time(timeframe.period, sessionInput + ":1234567") // everyday in_session = not na(t) is_first = in_session and not in_session[1] is_end_session = in_session[1] and not in_session green(open, close) => close > open ? true : false red(open, close) => close < open ? true : false var float orb_high = na var float orb_low = na if is_first orb_high := high orb_low := low else orb_high := orb_high[1] orb_low := orb_low[1] if high > orb_high and in_session orb_high := high if low < orb_low and in_session orb_low := low plot(hide ? na : orb_high, style=plot.style_line, color=orb_high[1] != orb_high ? na : color.green, title="ORB High", linewidth=2) plot(hide ? na : orb_low, style=plot.style_line, color=orb_low[1] != orb_low ? na : color.red, title="ORB Low", linewidth=2) // PDHCL (Previous Day High Close Low) [dh,dl,dc] = request.security(syminfo.ticker, "D", [high[1],low[1], close[1]], lookahead=barmerge.lookahead_on) plot(hidePDHCL ? na : dh, title="Prev High", color=color.red, linewidth=2, trackprice=true, show_last = 1) plot(hidePDHCL ? na : dl, title="Prev Low", color=color.green, linewidth=2, trackprice=true, show_last = 1) plot(hidePDHCL ? na : dc, title="Prev Close", color=color.black, linewidth=2, trackprice=true, show_last = 1) plot(hidePDHCL ? na : ta.vwap(close), title="Prev VWAP", color=color.fuchsia, linewidth=2, trackprice=true, show_last = 1) var l1 = label.new(bar_index, hidePDHCL ? na : dh, 'PDH', style=label.style_label_right) // Previous Day WWAP // For SL calculation atr = ta.atr(slAtrLen) highestHigh = ta.highest(high, 7) lowestLow = ta.lowest(low, 7) longStop = showSLLines ? lowestLow - (atr * 1) : na shortStop = showSLLines ? highestHigh + (atr * 1) : na plot(longStop, title="Buy SL", color=color.green, style=plot.style_cross) plot(shortStop, title="Sell SL", color=color.red, style=plot.style_cross) // Momentum: rsi rsi = ta.rsi(close, rsiLen) // trend: EMA200 ema = ta.ema(close, trendPeriod) plot(hideTrend ? na : ema, "EMA Trend", color=close > ema ? color.green : color.red, linewidth = 1) // Volume-Weighed Moving Average calculation vwmaAvg = ta.vwma(close, volAvg) vwma_latest = volume // plotshape((barstate.isconfirmed and (vwma_latest > (vwmaAvg * volThreshold))), title='VolumeData', text='', location=location.abovebar, style=shape.diamond, color=color.gray, textcolor=color.gray, size=size.tiny) // Trade signals longCond = barstate.isconfirmed and (ta.crossover(close, orb_high) or ta.crossover(close, dh)) and green(open, close) and (ignoreMementumVolume ? true : rsi > rsiBullish and (vwma_latest > (vwmaAvg * volThreshold))) shortCond = barstate.isconfirmed and (ta.crossunder(close, orb_low) or ta.crossunder(close, dl)) and red(open, close) and (ignoreMementumVolume ? true : rsi < rsiBearish and (vwma_latest > (vwmaAvg * volThreshold))) plotshape(longCond, title='Breakout', text='BO', location=location.belowbar, style=shape.triangleup, color=color.green, textcolor=color.green) plotshape(shortCond, title='Breakout', text='BD', location=location.abovebar, style=shape.triangledown, color=color.red, textcolor=color.red) // Trade execute h = hour(time('1'), syminfo.timezone) m = minute(time('1'), syminfo.timezone) hourVal = h * 100 + m totalTrades = strategy.opentrades + strategy.closedtrades if (mktAlwaysOn or (hourVal < endOfDay)) // Entry var float sl = na var float target = na if (longCond) strategy.entry("enter long", strategy.long, lotSize, limit=na, stop=na, comment="Enter Long") sl := longStop target := close + ((close - longStop) * rrRatio) alert('Buy:' + syminfo.ticker + ' ,SL:' + str.tostring(math.floor(sl)) + ', Target:' + str.tostring(target), alert.freq_once_per_bar) if (shortCond) strategy.entry("enter short", strategy.short, lotSize, limit=na, stop=na, comment="Enter Short") sl := shortStop target := close - ((shortStop - close) * rrRatio) alert('Sell:' + syminfo.ticker + ' ,SL:' + str.tostring(math.floor(sl)) + ', Target:' + str.tostring(target), alert.freq_once_per_bar) // Exit: target or SL if ((close >= target) or (close <= sl)) strategy.close("enter long", comment=close < sl ? "Long SL hit" : "Long target hit") if ((close <= target) or (close >= sl)) strategy.close("enter short", comment=close > sl ? "Short SL hit" : "Short target hit") else if (not mktAlwaysOn) // Close all open position at the end if Day strategy.close_all(comment = "Close all entries at end of day.") // Plotting table if (not hideTable and is_end_session) message = syminfo.ticker + " :\n\nORB Upper: " + str.tostring(math.round(orb_high)) + "\nORB Lower: " + str.tostring(math.round(orb_low)) + "\nPDH: " + str.tostring(math.round(dh)) + "\nPDC: " + str.tostring(math.round(dc)) + "\nPDL: " + str.tostring(math.round(dl)) + "\nVWAP: " + str.tostring(math.round(ta.vwap(close))) printTable(message) alert(message, alert.freq_once_per_bar_close)