Chiến lược giao dịch MACD đa khung thời gian

Tác giả:ChaoZhang, Ngày: 2024-01-30 17:44:36
Tags:

img

Tổng quan

Chiến lược này dựa trên chỉ số MACD cổ điển, kết hợp với các chỉ số đánh giá xu hướng, phương pháp dừng lỗ và phương pháp lấy lợi nhuận để tạo thành một chiến lược giao dịch theo dõi xu hướng tương đối hoàn chỉnh. Nó có thể được sử dụng cho cả giao dịch tiền điện tử, ngoại hối và chứng khoán.

Logic giao dịch

  1. Chỉ số MACD

    • Sự khác biệt giữa FASTLENGTH EMA và SLOWLENGTH EMA tạo thành biểu đồ MACD
    • MACDLENGTH thời gian EMA làm mịn biểu đồ MACD để tạo thành đường MACD
    • Biểu đồ MACD băng qua trục 0 hình thành tín hiệu giao dịch
  2. Bộ lọc xu hướng

    • ADX: Chỉ số hướng trung bình, để đánh giá liệu có xu hướng nào
    • MA: Đường trung bình động, giá trên và dưới MA tạo thành xu hướng
    • SAR: SAR Parabolic, SAR di chuyển trên và dưới giá cho thấy xu hướng
  3. Dừng Loss

    • Các khoản được tính theo mục 3 của mục 1 của mục 1 của mục 1 của mục 1 của mục 2 của mục 1 của mục 2 của mục 1 của mục 1 của mục 2 của mục 1 của mục 2 của mục 2 của mục 2 của mục 2 của mục 2 của mục 2 của mục 3 của mục 3 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục 4 của mục
    • SAR Stop Loss: Sử dụng SAR làm stop loss sau
  4. Lấy lợi nhuận

    • ATR Fixed Take Profit Distance: Đặt khoảng cách lấy lợi nhuận cố định dựa trên ATR
    • Tỷ lệ phần trăm lấy lợi nhuận: Đặt khoảng cách phần trăm lấy lợi nhuận
  5. Thời gian thoát

    • Có thể thiết lập thoát sau khi số lượng cụ thể của thanh

Phân tích lợi thế

  1. Phán quyết hỗ trợ nhiều lần

    • Phân tích xu hướng, hỗ trợ và kháng cự tránh các tín hiệu sai
    • ATR/SAR dừng mất mát kiểm soát tốt hơn rủi ro
  2. Cấu hình linh hoạt

    • Chọn sử dụng bộ lọc xu hướng
    • Chọn ATR hoặc SAR stop loss
    • Chọn ATR hoặc tiêu chuẩn lấy lợi nhuận
    • Các tham số có thể cấu hình
  3. Phân tích khác biệt được cung cấp

    • Hiển thị các khác biệt thông thường/bộ ẩn trong lịch sử
    • Cung cấp thông báo văn bản
  4. Dễ dàng tối ưu hóa

    • Nhiều tham số cấu hình tích hợp
    • Dễ dàng kiểm tra các kết hợp tham số khác nhau

Phân tích rủi ro

  1. Các thông số không chính xác có thể làm tăng tổn thất

    • Các thông số ATR, SAR không chính xác có thể làm dừng lỗ sớm
    • Tỷ lệ thu lợi nhuận quá mức có thể thu lợi nhuận sớm
  2. Rủi ro thất bại xu hướng

    • Các thông số chỉ số xu hướng không chính xác có thể gây ra đánh giá sai
    • Các sự kiện thiên nga đen có thể gây ra sự thất bại của xu hướng
  3. Rủi ro rời khỏi thời gian

    • Tiền bồi thường

Hướng dẫn tối ưu hóa

  1. Điều chỉnh các thông số ATR, SAR để dừng lại mượt mà hơn
  2. Kiểm tra các khoảng thời gian MA khác nhau để tối ưu hóa đánh giá xu hướng
  3. Kiểm tra điều chỉnh tỷ lệ lợi nhuận để tăng tỷ lệ lợi nhuận
  4. Kết hợp các chỉ số biến động để tối ưu hóa cấu hình

Kết luận

Chiến lược này xem xét toàn diện xu hướng, dừng lỗ, lấy lợi nhuận, xác định pullback để hình thành một chiến lược giao dịch tiền điện tử tương đối hoàn chỉnh. Nó kết hợp các lợi thế của các chỉ số MACD, thêm lọc xu hướng để tránh giao dịch sai; thêm ATR / SAR dừng lỗ để kiểm soát rủi ro tốt hơn; xác định pullback cung cấp tham chiếu bổ sung. Nhiều tham số có thể cấu hình có thể dễ dàng được kiểm tra và tối ưu hóa. Nhìn chung, chiến lược này có thể phục vụ như một ví dụ tuyệt vời cho nghiên cứu chiến lược tiền điện tử.


/*backtest
start: 2023-12-01 00:00:00
end: 2023-12-31 23:59:59
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © systemalphatrader

//@version=4

strategy(title="MACD+ Strategy [SystemAlpha]", shorttitle="MACD+ Strategy [SA]", overlay=true, initial_capital=10000, currency='USD', 
   default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.04)

// == MAIN INPUT ==
// TREND FILTER
// Make input option to configure trend filter
trendFilter  = input(title="Trend Filter", defval='MA', options=['ADX', 'MA', 'SAR', 'All', 'None'])

// Translate input into trend filters
useADXFilter    = (trendFilter == 'ADX') or (trendFilter == 'All')
useSARFilter    = (trendFilter == 'SAR') or (trendFilter == 'All')
useMAFilter     = (trendFilter == 'MA') or (trendFilter == 'All')

// TRAIL STOP
// Make input option to configure trail stop
trailStop       = input(title="Trailing Stop Loss", defval='SAR', options=['ATR', 'SAR', 'None']) 

// Translate input
useATRStop      = (trailStop == 'ATR')
useSARStop      = (trailStop == 'SAR')

// TAKE PROFIT TARGET
// Make input option to configure trail stop
TPtarget       = input(title="Take Profit Type", defval='ATR', options=['ATR', 'Percent', 'None']) 

// Translate input
useATRTP        = (TPtarget == 'ATR')
usePercentTP    = (TPtarget == 'Percent')

// ALERTS and BAR COLOR
// Make input option to configure alerts
alerts          = input(title="Select Alerts to Display", defval='None', options=['Buy/Sell', 'Exit', 'Both', 'None']) 

// Translate input
showsignals     = (alerts == 'Buy/Sell') or (alerts == 'Both')
showexitsignals = (alerts == 'Exit') or (alerts == 'Both')
showBarColor    = input(true, title="Show Bar Color")

// == /MAIN INPUT  ==

/////////////////////////////////////
//*STRATEGY LOGIC                 *//
/////////////////////////////////////

// == MACD ==
fastLength = input(12, title="Fast Length")
slowlength = input(26, title="Slow Length")
MACDLength = input(9, title="MACD Length")

MACD = ema(close, fastLength) - ema(close, slowlength)
aMACD = ema(MACD, MACDLength)
delta = MACD - aMACD

// Calc breakouts
break_up        = crossover(delta, 0)
break_down      = crossunder(delta,0)
// == /MACD ==

// == DIVERGENCE ==
method      = input(title="Divergence Method", defval='Hist', options=['Hist', 'MACD'])
divtype     = input(title="Divergence Type", defval='None', options=['Regular', 'Hidden', 'Both', 'None'])
uReg        = divtype == 'Regular' or divtype == 'Both'
uHid        = divtype == 'Hidden' or divtype == 'Both'
showlabel   = input(true, title="Show Divergence Label")
v_show_last = input(500, "Plotting Lookback Bars Length")

high_src = high
low_src  = low

//  ||  Functions:
f_top_fractal(_src) =>
    _src[4] < _src[2] and _src[3] < _src[2] and _src[2] > _src[1] and 
       _src[2] > _src[0]
f_bot_fractal(_src) =>
    _src[4] > _src[2] and _src[3] > _src[2] and _src[2] < _src[1] and 
       _src[2] < _src[0]
f_fractalize(_src) =>
    f_bot_fractal__1 = f_bot_fractal(_src)
    f_top_fractal(_src) ? 1 : f_bot_fractal__1 ? -1 : 0
// === End of Functions

//  ||  Method selection
oscilator_high = float(na)
oscilator_low = float(na)
if method == 'MACD'
    oscilator_high := MACD
    oscilator_low := MACD
if method == 'Hist'
    oscilator_high := delta
    oscilator_low := delta
//
fractal_top = f_fractalize(oscilator_high) > 0 ? oscilator_high[2] : na
fractal_bot = f_fractalize(oscilator_low) < 0 ? oscilator_low[2] : na

high_prev   = valuewhen(fractal_top, oscilator_high[2], 0)[2]
high_price  = valuewhen(fractal_top, high[2], 0)[2]
low_prev    = valuewhen(fractal_bot, oscilator_low[2], 0)[2]
low_price   = valuewhen(fractal_bot, low[2], 0)[2]

regular_bearish_div = fractal_top and high[2] > high_price and oscilator_high[2] < high_prev
hidden_bearish_div  = fractal_top and high[2] < high_price and oscilator_high[2] > high_prev
regular_bullish_div = fractal_bot and low[2] < low_price and oscilator_low[2] > low_prev
hidden_bullish_div  = fractal_bot and low[2] > low_price and oscilator_low[2] < low_prev

// Plotting
plot(title='Bullish', series=fractal_top ? high[2] : na, color = regular_bearish_div and uReg or hidden_bearish_div and uHid ? color.red : na, linewidth = 2, transp=50, offset=-2, show_last = v_show_last)
plot(title='Bearish', series=fractal_bot ? low[2] : na, color = regular_bullish_div and uReg or hidden_bullish_div and uHid ? color.green : na, linewidth = 2, transp=50, offset=-2, show_last = v_show_last)

plotshape(title='Regular Bearish', series=not showlabel or not uReg ? na : regular_bearish_div ? high[2] : na, text='R', style=shape.labeldown, location=location.absolute, color=color.red, textcolor=color.white, transp=50, offset=-2, show_last = v_show_last)
plotshape(title='Hidden Bearish', series=not showlabel or not uHid ? na : hidden_bearish_div ? high[2] : na, text='H', style=shape.labeldown, location=location.absolute, color=color.red, textcolor=color.white, transp=80, offset=-2, show_last = v_show_last)
plotshape(title='Regular Bullish', series=not showlabel or not uReg ? na : regular_bullish_div ? low[2] : na, text='R', style=shape.labelup, location=location.absolute, color=color.green, textcolor=color.white, transp=50, offset=-2, show_last = v_show_last)
plotshape(title='Hidden Bullish', series=not showlabel or not uHid ? na : hidden_bullish_div ? low[2] : na, text='H', style=shape.labelup, location=location.absolute, color=color.green, textcolor=color.white, transp=80, offset=-2, show_last = v_show_last)

// == /DIVERGENCE ==

// == ENTRY ==
// == ADX FILTERING ==
// Look at ADX when it is above a user-defined key level (23 default) and this is to identify when it is trending.
// It then looks at the DMI levels.  If D+ is above D- and the ADX is sloping upwards and above the key level, it triggers a buy condition.  Opposite for short.
adxlen          = 13 //input(13, title="TF ADX Smoothing")
dilen           = 13 //input(13, title="TF DI Period")
keyLevel        = 23 //input(23, title="TF Keylevel for ADX")

// == USE BUILT-IN DMI FUNCTION TO DETERMINE ADX AND BULL/BEAR STRENGTH
[diplus, diminus, adx] = dmi(dilen, adxlen)

//Buy and Sell Filter
ADXBuyCheck     = useADXFilter? diplus > diminus : true
ADXSellCheck    = useADXFilter? diplus < diminus : true
// == /ADX FILTERING ==

// == MOVING AVERAGE FILTERING ==
// MA FILTER: Use a user-defined moving average to filter long/short if desried.
maType          = input(defval="EMA", options=["EMA", "SMA"], title = "TF MA Type")
maLength        = input(defval = 50, title = "TF MA Period", minval = 1)

// Declare function to be able to swap out EMA/SMA
ma(maType, src, length) =>
    maType == "EMA" ? ema(src, length) : sma(src, length)
maFilter        = ma(maType, close, maLength)

// Check to see if the useMaFilter check box is checked, this then inputs this conditional "maFilterCheck" variable into the strategy entry 
maFilterCheck   = if useMAFilter == true
    maFilter
else
    close
// == /MOVING AVERAGE FILTERING ==

// == PARABOLIC SAR AS AN ENTRY and EXIT OPTION ==
// SAR FILTER: The Parabolic SAR (Stop and Reverse) is a time and price technical analysis tool primarily used to identify points of potential stops and reverses.
// Go long when is located below price (BULLISH) and go short when is located above price (BEARISH).
sarStart        = 0.04 //input(0.04, "SAR Start")
sarIncrement    = 0.02 //input(0.02, "SAR Increment")
sarMaximum      = 0.5 //input(0.5, "SAR Max Value")

htclose         = close
sarOut          = useSARFilter or useSARStop ? sar(sarStart, sarIncrement, sarMaximum) : na
Trend           = sarOut < htclose ? 1 : -1

//Buy and Sell Filter
sarBuyCheck     = useSARFilter? Trend == 1: true
sarSellCheck    = useSARFilter? Trend == -1: true

// Trigger stop based on High/Low
trigResistance  = high
trigSupport     = low

// Determine if price is above resistance or below support
sarResistanceHit    = close >= sarOut and useSARStop == true
sarSupportHit       = close <= sarOut and useSARStop == true
// == /PARABOLIC SAR AS AN ENTRY and EXIT OPTION ==

// == EXITS ==
// == ATR TRAILING STOPS ==
// The ATR % stop method can be used by any type of trader because the width of the stop is determined by the percentage of average true range (ATR). 
// ATR is a measure of volatility over a specified period of time.
// Exit with ATR support/resistance is hit.
atrLookback     = 14 //input(defval=14,title="ATR Lookback Period",type=input.integer)
multiplier      = input(defval=2,title="ATR Trailing Stop Multiplier",type=input.float, step=0.1, minval=0.5, maxval=5)

// Calculate the trailing ATR
atrValue        = atr(atrLookback)
atrMultiplied   = atrValue * multiplier

// Plot the price plus or minus the ATR
atrLow          = low - atrMultiplied
atrHigh         = high + atrMultiplied

// Calculate both the low and high trailing ATRs every time. The low one never goes down, and the high one never goes up
// Set them to something to start with
trailAtrLow     = atrLow
trailAtrHigh    = atrHigh

// If the ATR Low has gone up AND it has gone above the trail, the low trailing ATR should also go up. If the ATR Low has gone up or down, but not below the trail, the ATR trail stays where it is
trailAtrLow     := na(trailAtrLow[1]) ? trailAtrLow : atrLow >= trailAtrLow[1] ? atrLow : trailAtrLow[1]
// Same for the High
trailAtrHigh    := na(trailAtrHigh[1]) ? trailAtrHigh : atrHigh <= trailAtrHigh[1] ? atrHigh : trailAtrHigh[1]

// Determine if price is above resistance or below support
atrResistanceHit    = trigResistance >= trailAtrHigh and useATRStop == true
atrSupportHit       = trigSupport <= trailAtrLow and useATRStop == true

// If price is above resistance or below support, reset the trailing ATR
trailAtrLow     := atrSupportHit ? atrLow : trailAtrLow
trailAtrHigh    := atrResistanceHit ? atrHigh : trailAtrHigh
// == /ATR TRAILING STOPS ==

// == INITIAL TP==
// ATR
tpmultiplier   = input(defval=3,title="ATR Take Profit Multiplier",type=input.float, step=0.1, minval=0.5, maxval=5)

ema = ema(close, atrLookback)
atr = rma(tr(true), atrLookback)

longATRTP     = ema + (atr * tpmultiplier)
shortATRTP    = ema - (atr * tpmultiplier)

// Determine if price is above resistance or below support
longATRTPHit    = high >= longATRTP and useATRTP == true
shortATRTPHit   = low <= shortATRTP and useATRTP == true

// STANDARD TAKE PROFIT %
// User Options to Change Inputs (%)
takePer = input(10, title='Take Profit %', type=input.float, step=0.1, minval=0.5, maxval=100) / 100

//fixed TP prices
longPercentTP   = ema * (1 + takePer)
shortPercentTP  = ema * (1 - takePer)

// Determine if price is above resistance or below support
longPercentTPHit    = high >= longPercentTP and usePercentTP == true
shortPercentTPHit   = low <= shortPercentTP and usePercentTP == true

// Set Stop and TP Values
buyStop     = trailStop == 'ATR'? trailAtrLow : trailStop == 'SAR'? sarOut : na
sellStop    = trailStop == 'ATR'? trailAtrHigh : trailStop == 'SAR'? sarOut : na
longTP      = TPtarget == 'ATR'? longATRTP : TPtarget == 'Percent'? longPercentTP : na
shortTP     = TPtarget == 'ATR'? shortATRTP : TPtarget == 'Percent'? shortPercentTP : na

// == /EXITS ==

// == PLOTTING ==
buySignal       = break_up and ADXBuyCheck and close >= maFilterCheck and sarBuyCheck 
shortSignal     = break_down and ADXSellCheck and close <= maFilterCheck and sarSellCheck
sellSignal      = atrSupportHit or sarSupportHit or longPercentTPHit or longATRTPHit
coverSignal     = atrResistanceHit or sarResistanceHit or shortPercentTPHit or shortATRTPHit

//Set BarSince counter
barsSinceLong   = 0
barsSinceShort  = 0
barsSinceLong   := nz(barsSinceLong[1])
barsSinceShort  := nz(barsSinceShort[1])

//Plot Sell and Cover Signal
plotshape(not showexitsignals and sellSignal and barsSinceLong == 1? sellSignal : na, title="Sell Long", location=location.abovebar, style=shape.diamond, size=size.auto, color=color.aqua, transp=0, show_last = v_show_last, editable = false)
plotshape(not showexitsignals and coverSignal and barsSinceShort == 1 ? coverSignal : na, title="Cover Short", location=location.belowbar, style=shape.diamond, size=size.auto, color=color.orange, transp=0, show_last = v_show_last, editable = false)
plotshape(showexitsignals and sellSignal and barsSinceLong == 1? sellSignal : na, title="Close Long Text", location=location.abovebar, style=shape.diamond, size=size.auto, color=color.aqua, transp=0, show_last = v_show_last, textcolor=color.aqua, text = "Close\nLong", editable = false)
plotshape(showexitsignals and coverSignal and barsSinceShort == 1 ? coverSignal : na, title="Cover Short Text", location=location.belowbar, style=shape.diamond, size=size.auto, color=color.orange, transp=0, show_last = v_show_last, textcolor=color.orange, text = "Cover\nShort", editable = false)

// Reset BarSince counter
if buySignal 
    barsSinceLong := 1
    barsSinceShort := 0
if shortSignal
    barsSinceShort := 1
    barsSinceLong := 0
if sellSignal
    barsSinceLong := 0
if coverSignal
    barsSinceShort := 0

// Show bar color
barcolor(showBarColor? (buySignal or shortSignal ? (shortSignal ? color.fuchsia : color.yellow) : na) : na)

// Plot Buy Alerts
plotshape(buySignal ? buySignal : na, title="Breakout Up", location=location.belowbar, style=shape.circle, size=size.auto, color=color.yellow, transp=0, editable = false)
plotshape(showsignals and buySignal, title= "Long", color=color.green, style=shape.labelup, location=location.belowbar, size=size.auto, show_last = v_show_last, text = "BUY", textcolor=color.white, editable = false)

// Plot Sell Alerts
plotshape(shortSignal ? shortSignal : na, title="Breakout Down", location=location.abovebar, style=shape.circle, size=size.auto, color=color.fuchsia, transp=0, editable = false)
plotshape(showsignals and shortSignal, title= "Short", color=color.red, style=shape.labeldown, location=location.abovebar, size=size.auto, show_last = v_show_last, text = "SELL", textcolor=color.white, editable = false)

// Plot MA Trend Filter
plot(useMAFilter? maFilter : na, title = "Trend Filter MA", color = color.green, linewidth = 2, style = plot.style_line, transp = 20, editable = true)

// Plot Initial Stop
plot(trailStop != 'None' and barsSinceLong >= 1? buyStop : na, color=#3A6CA8, title="Trail Stop Long", style = plot.style_cross, linewidth = 1, transp = 20, editable = true)
plot(trailStop != 'None' and barsSinceShort >= 1? sellStop : na, color=#3A6CA8, title="Trail Stop Short", style = plot.style_cross, linewidth = 1, transp = 20, editable = true)

// Plot Initial Target Profit
plot(TPtarget != 'None' and buySignal? longTP : na, color=color.green, title="LongTP", style = plot.style_linebr, linewidth = 1, editable = false)
plot(TPtarget != 'None' and shortSignal? shortTP : na, color=color.green, title="ShortTP", style = plot.style_linebr, linewidth = 1, editable = false)

// == /PLOTTING ==

// == ALERTS == 
// Buy and Sell Signal
alertcondition(buySignal, title='MACD Long', message='MACD {{exchange}}:{{ticker}} TF: {{interval}}. LONG (TRADE). ENTRY: {{close}}, Target Profit: {{plot("LongTP")}}, STOP LOSS: {{plot("Trail Stop Long")}}')
alertcondition(shortSignal, title='MACD Short', message='MACD {{exchange}}:{{ticker}} TF: {{interval}}. SHORT (TRADE). ENTRY: {{close}}, Target Profit: {{plot("ShortTP")}}, STOP LOSS: {{plot("Trail Stop Short")}}')
alertcondition(sellSignal, title='MACD Close Long', message='MACD {{exchange}}:{{ticker}} Close Long, Price = {{close}}')
alertcondition(coverSignal, title='MACD Cover Short', message='MACD {{exchange}}:{{ticker}} Cover Short, Price = {{close}}')
alertcondition(sellSignal or coverSignal, title="MACD Close Orders", message="{{ticker}} Close Orders")

// Initial SL and TP Hit
stophit = low <= buyStop or high >= sellStop
tphit   = low <= shortTP or high >= longTP
alertcondition(stophit, title='MACD SL Hit', message='MACD {{exchange}}:{{ticker}} Stop Loss Hit, Price = {{close}}')
alertcondition(tphit, title='MACD TP Hit', message='MACD {{exchange}}:{{ticker}} Target Profit Hit, Price = {{close}}')

//Divergence Alerts
alertcondition(regular_bullish_div, title='MACD Bullish Divergence', message='MACD Regular Bullish Divergence')
alertcondition(regular_bearish_div, title='MACD Bearish Divergence', message='MACD Regular Bearish Divergence')
alertcondition(hidden_bullish_div, title='MACD Hidden Bullish Divergence', message='MACD Hidden Bullish Divergence')
alertcondition(hidden_bearish_div, title='MACD Hidden Bearish Divergence', message='MACD Hidden Bearish Divergence')
// == /ALERTS == 

//////////////////////////
//* STRATEGY COMPONENT *//
//////////////////////////

// === BACKTEST RANGE ===
From_Year   = input(defval = 2017, title = "BACKTEST: From Year")
From_Month  = input(defval = 1, title = "BACKTEST: From Month", minval = 1, maxval = 12)
From_Day    = input(defval = 1, title = "BACKTEST: From Day", minval = 1, maxval = 31)
To_Year     = input(defval = 9999, title = "BACKTEST: To Year")
To_Month    = input(defval = 1, title = "BACKTEST: To Month", minval = 1, maxval = 12)
To_Day      = input(defval = 1, title = "BACKTEST: To Day", minval = 1, maxval = 31)
Start       = timestamp(From_Year, From_Month, From_Day, 00, 00)  // backtest start window
Finish      = timestamp(To_Year, To_Month, To_Day, 23, 59)        // backtest finish window

testPeriod() => true
// === /BACKTEST RANGE ===

// === STRATEGY ===
// Make input option to configure trade direction
tradeDirection = input(title="Trade Direction", defval="Both", options=["Long", "Short", "Both"]) 

// Translate input into trading conditions
longOK  = (tradeDirection == "Long") or (tradeDirection == "Both")
shortOK = (tradeDirection == "Short") or (tradeDirection == "Both")

// == STRATEGY ENTRIES/EXITS ==
timedExit   = input(title = "Use Timed Exit", type = input.bool, defval = true)
exitmethod  = input(title="Timed Exit Method", defval='3', options=['1', '2', '3']) 
bse         = input(10, "Bar Since Entry") // Bars to exit after entry

barsSinceEntry  = 0
barsSinceEntry  := nz(barsSinceEntry[1]) + 1

longCondition = longOK and buySignal and testPeriod()
shortcondition = shortOK and shortSignal and testPeriod()

if strategy.position_size == 0
    barsSinceEntry := 0

// === STRATEGY - LONG POSITION EXECUTION ===
if longCondition
    strategy.entry("Long", strategy.long)
    barsSinceEntry := 0

// === STRATEGY - SHORT POSITION EXECUTION ===
if shortcondition
    strategy.entry("Short", strategy.short)
    barsSinceEntry := 0

// == STRATEGY EXITS ==
if sellSignal
    strategy.close("Long")
    barsSinceEntry := 0
if coverSignal
    strategy.close("Short")
    barsSinceEntry := 0
    
// Enable Timed Exit
// Exit after specified number of bars.
if timedExit and exitmethod == '1' and barsSinceEntry > bse
    strategy.close_all()
    barsSinceEntry := 0
// Exit after specified number of bars, ONLY if position is currently profitable.
if timedExit and exitmethod == '2' and strategy.openprofit > 0 and barsSinceEntry > bse
    strategy.close_all()
    barsSinceEntry := 0
// Exit after specified number of bars, ONLY if position is currently losing.
if timedExit and exitmethod == '3' and strategy.openprofit < 0 and barsSinceEntry > bse
    strategy.close_all()
    barsSinceEntry := 0
// === /STRATEGY ===
//EOF

Thêm nữa