Tài nguyên đang được tải lên... tải...

Xu hướng theo chiến lược dựa trên SSL Baseline

Tác giả:ChaoZhang, Ngày: 2024-01-15 14:36:39
Tags:

img

Tổng quan

Chiến lược này sử dụng kênh SSL để đánh giá xu hướng thị trường và theo xu hướng dựa trên đường cơ sở trung bình động. Nó phù hợp với khung thời gian trung và dài hạn như biểu đồ 4 giờ và hàng ngày.

Chiến lược logic

  1. Các kênh SSL bao gồm các kênh Keltner và True Range. Nó có thể xác định hướng xu hướng. Một sự đột phá trên dải trên là một tín hiệu tăng trong khi một sự đột phá dưới dải dưới là một tín hiệu giảm.

  2. Chiến lược tính toán đường cơ sở với EMA và các chỉ số MA khác.

  3. Chiến lược này đi dài khi giá vượt qua dải trên SSL và đi ngắn khi giá vượt qua dải dưới. Nó theo xu hướng tăng bằng cách mua giảm và xu hướng giảm bằng cách bán tăng.

  4. Các phương pháp dừng lỗ bao gồm dựa trên tỷ lệ phần trăm, dựa trên ATR và nhìn lại mức cao nhất / thấp nhất.

Phân tích lợi thế

  1. SSL Channel đánh giá chính xác hướng xu hướng với ít tín hiệu sai hơn.

  2. Các loại và tham số MA linh hoạt phù hợp với nhiều tình huống thị trường hơn.

  3. Phương pháp dừng lỗ linh hoạt có hiệu quả kiểm soát rủi ro.

  4. Khả năng đi cả dài và ngắn sử dụng đầy đủ các cơ hội thị trường song phương.

Phân tích rủi ro

  1. Sự chậm trễ của các chỉ số MA có thể dẫn đến tổn thất tích lũy.

  2. Sự đảo ngược nhanh chóng sau khi phá vỡ các băng tần SSL mang lại những cú đấm ở các thị trường khác nhau.

  3. ATR và nhìn lại dừng lỗ có thể quá lỏng lẻo trên bất thường, mở rộng tổn thất.

Chiến thuật quản lý rủi ro:

  1. Điều chỉnh các thông số MA hoặc sử dụng các loại MA khác.
  2. Mở rộng tỷ lệ dừng lỗ để dừng lỗ kịp thời.
  3. Thêm nhân trong ATR.

Hướng tối ưu hóa

  1. Kiểm tra nhiều loại MA hơn để tìm các thông số tối ưu.
  2. Tối ưu hóa chu kỳ ATR để dừng mất mát.
  3. Kiểm tra các nhân stop loss khác nhau.
  4. Kiểm tra hệ số phần thưởng rủi ro cho lợi nhuận.

Kết luận

Chiến lược này theo dõi hiệu quả các xu hướng bằng cách kết hợp SSL Channel để xác định xu hướng và đường MA để xác nhận các yếu tố kích hoạt nhập cảnh. Nó cung cấp các phương pháp linh hoạt để ngăn chặn tổn thất và lấy lợi nhuận, cân bằng rủi ro và lợi nhuận. Kiểm tra liên tục và điều chỉnh tham số sẽ dẫn đến hiệu suất tốt hơn. Đây là một chiến lược hiệu quả xứng đáng theo dõi và sử dụng lâu dài.


/*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/
// Thanks to @kevinmck100 for opensource strategy template and @Mihkel00 for SSL Hybrid
// @fpemehd
// @version=5
strategy(title = '[fpemehd] SSL Baseline Strategy',
      shorttitle = '[f] SSL',
      overlay = true)

// # ========================================================================= #
// #                                Inputs 
// # ========================================================================= #

// 1. Time
i_start                 = input (defval = timestamp("20 Jan 1990 00:00 +0900"), title = "Start Date", tooltip = "Choose Backtest Start Date", inline = "Start Date", group = "Time" ) 
i_end                   = input (defval = timestamp("20 Dec 2030 00:00 +0900"), title = "End Date", tooltip = "Choose Backtest End Date", inline = "End Date", group = "Time" ) 
inDateRange             = true


// 2. Inputs for direction: Long? Short? Both? 
// i_longEnabled           = input.bool(defval = true , title = "Long?", tooltip = "Enable Long Position Trade?", inline = "1", group = "Long / Short" )
// i_shortEnabled          = input.bool(defval = true , title = "Short?", tooltip = "Enable Short Position Trade?", inline = "1", group = "Long / Short" )

// 3. Shared inputs for Long and Short
//// 3-1. Inputs for Stop Loss Type: ATR or Percent?
i_slType                = input.string (defval = "ATR", title = "SL Type ", group = "Strategy: Stop Loss Conditions", options = ["Percent", "ATR", "Previous LL / HH"], tooltip = "Stop Loss based on %? ATR?", inline = "1") 
i_slPercent             = input.float (defval = 3, title = "SL % ",             group = "Strategy: Stop Loss Conditions", inline = "2")
i_slAtrLength           = input.int (14, "SL ATR Length ",                      group = "Strategy: Stop Loss Conditions", inline = "3", minval = 0, maxval = 10000)
i_slAtrMultiplier       = input.float (4,    "SL ATR Multiplier",               group = "Strategy: Stop Loss Conditions",    inline = "3", minval = 0, step = 0.1,     tooltip = "Length of ATR used to calculate Stop Loss. \nSize of StopLoss is determined by multiplication of ATR value. Take Profit is derived from this also by multiplying the StopLoss value by the Risk:Reward multiplier.")
i_slLookBack            = input.int(30,   "Lowest Price Before Entry",          group = "Strategy: Stop Loss Conditions",    inline = "4", minval = 30, step = 1,     tooltip = "Lookback to find the Lowest Price. \nStopLoss is determined by the Lowest price of the look back period. Take Profit is derived from this also by multiplying the StopLoss value by the Risk:Reward multiplier.")

//// 3-2. Inputs for Quantity & Risk Manangement: Take Profit
i_riskReward            = input.float(2,    "Risk : Reward  Ratio ",            group = "Strategy: Risk Management",    inline = "1", minval = 0, step = 0.1,     tooltip = "Previous high or low (long/short dependant) is used to determine TP level. 'Risk : Reward' ratio is then used to calculate SL based of previous high/low level.\n\nIn short, the higher the R:R ratio, the smaller the SL since TP target is fixed by previous high/low price data.")
i_accountRiskPercent    = input.float(1,    "Portfolio Risk %",                 group = "Strategy: Risk Management",    inline = "1", minval = 0, step = 0.1,     tooltip = "Percentage of portfolio you lose if trade hits SL.\n\nYou then stand to gain\n  Portfolio Risk % * Risk : Reward\nif trade hits TP.")



// 4. Inputs for Drawings
i_showTpSlBoxes       = input.bool(false,  "Show TP / SL Boxes",               group = "Strategy: Drawings",           inline = "1",  tooltip = "Show or hide TP and SL position boxes.\n\nNote: TradingView limits the maximum number of boxes that can be displayed to 500 so they may not appear for all price data under test.")
i_showLabels          = input.bool(false, "Show Trade Exit Labels",            group = "Strategy: Drawings",           inline = "1",  tooltip = "Useful labels to identify Profit/Loss and cumulative portfolio capital after each trade closes.\n\nAlso note that TradingView limits the max number of 'boxes' that can be displayed on a chart (max 500). This means when you lookback far enough on the chart you will not see the TP/SL boxes. However you can check this option to identify where trades exited.")
i_showDashboard       = input.bool(false, "Show Dashboard",                    group = "Strategy: Drawings",           inline = "1",  tooltip = "Show Backtest Results")
i_show_color_bar      = input.bool(false , "Color Bars",                       group = "Strategy: Drawings",           inline = "1") 
// 5. Inputs for Indicators
//// 5-1. Inputs for Indicator - 1: SSL Hybrid
i_useTrueRange = input.bool(defval = true , title = "use true range for Keltner Channel?", tooltip = "", inline = " ", group = "1: SSL Hybrid") 
i_maType = input.string(defval='EMA', title='Baseline Type', options=['SMA', 'EMA', 'DEMA', 'TEMA', 'LSMA', 'WMA', 'MF', 'VAMA', 'TMA', 'HMA', 'JMA', 'Kijun v2', 'EDSMA', 'McGinley'],group = "1: SSL Hybrid")
i_len = input.int(defval=30,title='Baseline Length', group = "1: SSL Hybrid")
i_multy = input.float(0.2, step=0.05, title='Base Channel Multiplier', group = "1: SSL Hybrid")

// Input for Baseline
i_kidiv = input.int(defval=1, maxval=4, minval=0, title='Kijun MOD Divider',inline="Kijun v2", group="1: SSL Hybrid")
i_jurik_phase = input.int(defval=3, title='Baseline Type = JMA -> Jurik Phase', inline='JMA',group="1: SSL Hybrid")
i_jurik_power = input.int(defval=1, title='Baseline Type = JMA -> Jurik Power', inline='JMA',group="1: SSL Hybrid")
i_volatility_lookback = input.int(defval=10, title='Baseline Type = VAMA -> Volatility lookback length', inline='VAMA',group="1: SSL Hybrid")
// MF
i_beta = input.float(0.8, minval=0, maxval=1, step=0.1, title='Baseline Type = MF (Modular Filter, General Filter) ->Beta', inline='MF',group="1: SSL Hybrid")
i_feedback = input.bool(defval=false, title='Baseline Type = MF (Modular Filter) -> Use Feedback?', inline='MF',group="1: SSL Hybrid")
i_z = input.float(0.5, title='Baseline Type = MF (Modular Filter) ->  Feedback Weighting', step=0.1, minval=0, maxval=1, inline='MF',group="1: SSL Hybrid")
// EDSMA
i_ssfLength = input.int(title='EDSMA - Super Smoother Filter Length', minval=1, defval=20, inline='EDSMA',group="1: SSL Hybrid")
i_ssfPoles = input.int(title='EDSMA - Super Smoother Filter Poles', defval=2, options=[2, 3], inline='EDSMA',group="1: SSL Hybrid")

// # ========================================================================= #
// #               Functions for Stop Loss & Take Profit & Plots
// # ========================================================================= #

percentAsPoints(pcnt) =>
    math.round(pcnt / 100 * close / syminfo.mintick) 
    
calcStopLossPrice(pointsOffset, isLong) =>
    priceOffset = pointsOffset * syminfo.mintick
    if isLong
        close - priceOffset
    else 
        close + priceOffset

calcProfitTrgtPrice(pointsOffset, isLong) =>
    calcStopLossPrice(-pointsOffset, isLong)
    
        
printLabel(barIndex, msg) => label.new(barIndex, close, msg)

printTpSlHitBox(left, right, slHit, tpHit, entryPrice, slPrice, tpPrice) => 
    if i_showTpSlBoxes
        box.new (left = left,   top = entryPrice,   right = right,  bottom = slPrice,   bgcolor = slHit ? color.new(color.red, 60)   : color.new(color.gray, 90), border_width = 0)
        box.new (left = left,   top = entryPrice,   right = right,  bottom = tpPrice,   bgcolor = tpHit ? color.new(color.green, 60) : color.new(color.gray, 90), border_width = 0)
        line.new(x1 = left,     y1 = entryPrice,    x2 = right,     y2 = entryPrice,    color = color.new(color.yellow, 20))
        line.new(x1 = left,     y1 = slPrice,       x2 = right,     y2 = slPrice,       color = color.new(color.red, 20))
        line.new(x1 = left,     y1 = tpPrice,       x2 = right,     y2 = tpPrice,       color = color.new(color.green, 20))
        
printTpSlNotHitBox(left, right, entryPrice, slPrice, tpPrice) => 
    if i_showTpSlBoxes
        box.new (left = left,   top = entryPrice,   right = right,  bottom = slPrice,   bgcolor = color.new(color.gray, 90), border_width = 0)
        box.new (left = left,   top = entryPrice,   right = right,  bottom = tpPrice,   bgcolor = color.new(color.gray, 90), border_width = 0)
        line.new(x1 = left,     y1 = entryPrice,    x2 = right,     y2 = entryPrice,    color = color.new(color.yellow, 20))
        line.new(x1 = left,     y1 = slPrice,       x2 = right,     y2 = slPrice,       color = color.new(color.red, 20))
        line.new(x1 = left,     y1 = tpPrice,       x2 = right,     y2 = tpPrice,       color = color.new(color.green, 20))
        
printTradeExitLabel(x, y, posSize, entryPrice, pnl) => 
    if i_showLabels
        labelStr = "Position Size: " + str.tostring(math.abs(posSize), "#.##") + "\nPNL: " + str.tostring(pnl, "#.##") + "\nCapital: " + str.tostring(strategy.equity, "#.##") + "\nEntry Price: " + str.tostring(entryPrice, "#.##") + "\nExit Price: " + str.tostring(close,"#.##")
        label.new(x = x, y = y, text = labelStr, color = pnl > 0 ? color.new(color.green, 60) : color.new(color.red, 60), textcolor = color.white, style = label.style_label_down)

f_fillCell(_table, _column, _row, _title, _value, _bgcolor, _txtcolor) =>
    _cellText = _title + " " + _value
    table.cell(_table, _column, _row, _cellText, bgcolor=_bgcolor, text_color=_txtcolor, text_size=size.auto)

// # ========================================================================= #
// #                          Entry, Close Logic 
// # ========================================================================= #
// 1. Calculate Indicators
//// 1-1. Calculate Indicators for SSL Hybrid Baseline
////// TEMA
tema(src, len) =>
    ema1 = ta.ema(src, len)
    ema2 = ta.ema(ema1, len)
    ema3 = ta.ema(ema2, len)
    3 * ema1 - 3 * ema2 + ema3
////// EDSMA
get2PoleSSF(src, length) =>
    PI = 2 * math.asin(1)
    arg = math.sqrt(2) * PI / length
    a1 = math.exp(-arg)
    b1 = 2 * a1 * math.cos(arg)
    c2 = b1
    c3 = -math.pow(a1, 2)
    c1 = 1 - c2 - c3

    ssf = 0.0
    ssf := c1 * src + c2 * nz(ssf[1]) + c3 * nz(ssf[2])
    ssf

get3PoleSSF(src, length) =>
    PI = 2 * math.asin(1)

    arg = PI / length
    a1 = math.exp(-arg)
    b1 = 2 * a1 * math.cos(1.738 * arg)
    c1 = math.pow(a1, 2)

    coef2 = b1 + c1
    coef3 = -(c1 + b1 * c1)
    coef4 = math.pow(c1, 2)
    coef1 = 1 - coef2 - coef3 - coef4

    ssf = 0.0
    ssf := coef1 * src + coef2 * nz(ssf[1]) + coef3 * nz(ssf[2]) + coef4 * nz(ssf[3])
    ssf

ma(type, src, len) =>
    float result = 0
    if type == 'TMA'
        result := ta.sma(ta.sma(src, math.ceil(len / 2)), math.floor(len / 2) + 1)
        result
    if type == 'MF'
        ts = 0.
        b = 0.
        c = 0.
        os = 0.
        //----
        alpha = 2 / (len + 1)
        a = i_feedback ? i_z * src + (1 - i_z) * nz(ts[1], src) : src
        //----
        b := a > alpha * a + (1 - alpha) * nz(b[1], a) ? a : alpha * a + (1 - alpha) * nz(b[1], a)
        c := a < alpha * a + (1 - alpha) * nz(c[1], a) ? a : alpha * a + (1 - alpha) * nz(c[1], a)
        os := a == b ? 1 : a == c ? 0 : os[1]
        //----
        upper = i_beta * b + (1 - i_beta) * c
        lower = i_beta * c + (1 - i_beta) * b
        ts := os * upper + (1 - os) * lower
        result := ts
        result
    if type == 'LSMA'
        result := ta.linreg(src, len, 0)
        result
    if type == 'SMA'  // Simple
        result := ta.sma(src, len)
        result
    if type == 'EMA'  // Exponential
        result := ta.ema(src, len)
        result
    if type == 'DEMA'  // Double Exponential
        e = ta.ema(src, len)
        result := 2 * e - ta.ema(e, len)
        result
    if type == 'TEMA'  // Triple Exponential
        e = ta.ema(src, len)
        result := 3 * (e - ta.ema(e, len)) + ta.ema(ta.ema(e, len), len)
        result
    if type == 'WMA'  // Weighted
        result := ta.wma(src, len)
        result
    if type == 'VAMA'  // Volatility Adjusted
        /// Copyright © 2019 to present, Joris Duyck (JD)
        mid = ta.ema(src, len)
        dev = src - mid
        vol_up = ta.highest(dev, i_volatility_lookback)
        vol_down = ta.lowest(dev, i_volatility_lookback)
        result := mid + math.avg(vol_up, vol_down)
        result
    if type == 'HMA'  // Hull
        result := ta.wma(2 * ta.wma(src, len / 2) - ta.wma(src, len), math.round(math.sqrt(len)))
        result
    if type == 'JMA'  // Jurik
        /// Copyright © 2018 Alex Orekhov (everget)
        /// Copyright © 2017 Jurik Research and Consulting.
        phaseRatio = i_jurik_phase < -100 ? 0.5 : i_jurik_phase > 100 ? 2.5 : i_jurik_phase / 100 + 1.5
        beta = 0.45 * (len - 1) / (0.45 * (len - 1) + 2)
        alpha = math.pow(beta, i_jurik_power)
        jma = 0.0
        e0 = 0.0
        e0 := (1 - alpha) * src + alpha * nz(e0[1])
        e1 = 0.0
        e1 := (src - e0) * (1 - beta) + beta * nz(e1[1])
        e2 = 0.0
        e2 := (e0 + phaseRatio * e1 - nz(jma[1])) * math.pow(1 - alpha, 2) + math.pow(alpha, 2) * nz(e2[1])
        jma := e2 + nz(jma[1])
        result := jma
        result
    if type == 'Kijun v2'
        kijun = math.avg(ta.lowest(len), ta.highest(len))  //, (open + close)/2)
        conversionLine = math.avg(ta.lowest(len / i_kidiv), ta.highest(len / i_kidiv))
        delta = (kijun + conversionLine) / 2
        result := delta
        result
    if type == 'McGinley'
        mg = 0.0
        mg := na(mg[1]) ? ta.ema(src, len) : mg[1] + (src - mg[1]) / (len * math.pow(src / mg[1], 4))
        result := mg
        result
    if type == 'EDSMA'
        zeros = src - nz(src[2])
        avgZeros = (zeros + zeros[1]) / 2

        // Ehlers Super Smoother Filter 
        ssf = i_ssfPoles == 2 ? get2PoleSSF(avgZeros, i_ssfLength) : get3PoleSSF(avgZeros, i_ssfLength)

        // Rescale filter in terms of Standard Deviations
        stdev = ta.stdev(ssf, len)
        scaledFilter = stdev != 0 ? ssf / stdev : 0

        alpha = 5 * math.abs(scaledFilter) / len

        edsma = 0.0
        edsma := alpha * src + (1 - alpha) * nz(edsma[1])
        result := edsma
        result
    result

////// Keltner Baseline Channel (Baseline) 
BBMC = ma(i_maType, close, i_len)
Keltma = ma(i_maType, close, i_len)
range_1 = i_useTrueRange ? ta.tr : high - low
rangema = ta.ema(range_1, i_len)
upperk = Keltma + rangema * i_multy
lowerk = Keltma - rangema * i_multy

// 2. Entry Condition for Long and Short
// Condition 1
bullSSL             = close > upperk
bearSSL             = close < lowerk
// Enter Position based on Condition 1
goLong              = inDateRange and bullSSL 
goShort             = inDateRange and bearSSL 
// # ========================================================================= #
// #                   Position Control Logic (Entry & Exit)
// # ========================================================================= #
// 1. Trade entry and exit variables
var tradeEntryBar   = bar_index
var profitPoints    = 0.
var lossPoints      = 0.
var slPrice         = 0.
var tpPrice         = 0.
var inLong          = false 
var inShort         = false
// 2. Entry decisions
openLong            = (goLong and not inLong)                           // Long entry condition & not in long position
openShort           = (goShort and not inShort)                         // Short entry condition & not in short position
flippingSides       = (goLong and inShort) or (goShort and inLong)      // (Long entry condition & in short position) and the opposite
enteringTrade       = openLong or openShort                             // Entering Long or Short Condition
inTrade             = inLong or inShort
// 3. Stop Loss & Take Profit Percent
lowestLow           = ta.lowest(source = low, length = i_slLookBack) 
highestHigh         = ta.highest(source = high, length = i_slLookBack) 
llhhSLPercent       = openLong ? math.abs((close - lowestLow) / close) * 100 : openShort ? math.abs((highestHigh - close) / close) * 100 : na
atr                 = ta.atr(i_slAtrLength)
slAmount            = atr * i_slAtrMultiplier
slPercent           = i_slType == 'ATR' ? math.abs((1 - (close - slAmount) / close) * 100) : i_slType == 'Percent' ? i_slPercent : llhhSLPercent
tpPercent           = slPercent * i_riskReward
// 4. Risk calculations & Quantity Management
riskAmt             = strategy.equity * i_accountRiskPercent / 100
entryQty            = math.abs(riskAmt / slPercent * 100)  / close

// 5. Open Position
if openLong
    if strategy.position_size < 0
        printTpSlNotHitBox(tradeEntryBar + 1, bar_index + 1, strategy.position_avg_price, slPrice, tpPrice)
        printTradeExitLabel(bar_index + 1, math.max(tpPrice, slPrice), strategy.position_size, strategy.position_avg_price, strategy.openprofit)
    strategy.entry("Long", strategy.long, qty = entryQty, alert_message = "Long Entry")
    enteringTrade   := true
    inLong          := true
    inShort         := false

if openShort
    if strategy.position_size > 0
        printTpSlNotHitBox(tradeEntryBar + 1, bar_index + 1, strategy.position_avg_price, slPrice, tpPrice)
        printTradeExitLabel(bar_index + 1, math.max(tpPrice, slPrice), strategy.position_size, strategy.position_avg_price, strategy.openprofit)
    strategy.entry("Short", strategy.short, qty = entryQty, alert_message = "Short Entry")
    enteringTrade   := true
    inShort         := true
    inLong          := false

if enteringTrade
    profitPoints    := percentAsPoints(tpPercent)
    lossPoints      := percentAsPoints(slPercent)
    slPrice         := calcStopLossPrice(lossPoints, openLong) 
    tpPrice         := calcProfitTrgtPrice(profitPoints, openLong)
    tradeEntryBar   := bar_index

// Can add more take profit Actions 
strategy.exit("TP/SL", profit = profitPoints, loss = lossPoints, comment_profit = "TP Hit", comment_loss = "SL Hit", alert_profit = "TP Hit Alert", alert_loss = "SL Hit Alert")

// # ========================================================================= #
// #                    Plots (Bar Color, Plot, Label, Boxes)
// # ========================================================================= #

// 1. SSL Hybrid Baseline 
longColor = #00c3ff
shortColor = #ff0062
color_bar = close > upperk ? longColor : close < lowerk ? shortColor : color.gray
p1 = plot(BBMC, color=color.new(color=color_bar, transp=0), linewidth=4, title='MA Baseline')

// 2. Bar color Based On SSL Hybrid Baseline
barcolor(i_show_color_bar ? color_bar : na)
up_channel = plot(upperk, color=color_bar, title='Baseline Upper Channel')
low_channel = plot(lowerk, color=color_bar, title='Basiline Lower Channel')
fill(up_channel, low_channel, color.new(color=color_bar, transp=90))


// 3. Stoploss Boxes
slHit           = (inShort and high >= slPrice) or (inLong  and low <= slPrice)
tpHit           = (inLong  and high >= tpPrice) or (inShort and low <= tpPrice)
exitTriggered   = slHit or tpHit
entryPrice      = strategy.closedtrades.entry_price (strategy.closedtrades - 1)
pnl             = strategy.closedtrades.profit      (strategy.closedtrades - 1)
posSize         = strategy.closedtrades.size        (strategy.closedtrades - 1)

if (inTrade and exitTriggered) 
    inShort    := false
    inLong     := false 
    printTpSlHitBox(tradeEntryBar + 1, bar_index, slHit, tpHit, entryPrice, slPrice, tpPrice)
    printTradeExitLabel(bar_index, math.max(tpPrice, slPrice), posSize, entryPrice, pnl)

if barstate.islastconfirmedhistory and strategy.position_size != 0
    printTpSlNotHitBox(tradeEntryBar + 1, bar_index + 1, strategy.position_avg_price, slPrice, tpPrice)
    

// 4. Data Windows
plotchar(slPrice,    "Stop Loss Price",     "")
plotchar(tpPrice,    "Take Profit Price",   "")

// 5. Showing Labels
plotDebugLabels = false
if plotDebugLabels
    if bar_index == tradeEntryBar 
        printLabel(bar_index, "Position size: " + str.tostring(entryQty * close, "#.##"))

// 6. Showing Dashboard
if i_showDashboard
    var bgcolor = color.new(color.black,0)
    
    // Keep track of Wins/Losses streaks
    newWin  = (strategy.wintrades  > strategy.wintrades[1]) and (strategy.losstrades == strategy.losstrades[1]) and (strategy.eventrades == strategy.eventrades[1])
    newLoss = (strategy.wintrades == strategy.wintrades[1]) and (strategy.losstrades  > strategy.losstrades[1]) and (strategy.eventrades == strategy.eventrades[1])

    varip int winRow     = 0
    varip int lossRow    = 0
    varip int maxWinRow  = 0
    varip int maxLossRow = 0

    if newWin
        lossRow := 0
        winRow := winRow + 1
    if winRow > maxWinRow
        maxWinRow := winRow
        
    if newLoss
        winRow := 0
        lossRow := lossRow + 1
    if lossRow > maxLossRow
        maxLossRow := lossRow


    // Prepare stats table
    var table dashTable = table.new(position.bottom_right, 1, 15, border_width=1)
    
   
    if barstate.islastconfirmedhistory
        // Update table
        dollarReturn = strategy.netprofit
        f_fillCell(dashTable, 0, 0, "Start:", str.format("{0,date,long}", strategy.closedtrades.entry_time(0)) , bgcolor, color.white) // + str.format(" {0,time,HH:mm}", strategy.closedtrades.entry_time(0)) 
        f_fillCell(dashTable, 0, 1, "End:", str.format("{0,date,long}", strategy.opentrades.entry_time(0)) , bgcolor, color.white) // + str.format(" {0,time,HH:mm}", strategy.opentrades.entry_time(0))
        _profit = (strategy.netprofit / strategy.initial_capital) * 100
        f_fillCell(dashTable, 0, 2, "Net Profit:", str.tostring(_profit, '##.##') + "%", _profit > 0 ? color.green : color.red, color.white)
        _numOfDaysInStrategy = (strategy.opentrades.entry_time(0) - strategy.closedtrades.entry_time(0)) / (1000 * 3600 * 24)
        f_fillCell(dashTable, 0, 3, "Percent Per Day", str.tostring(_profit / _numOfDaysInStrategy, '#########################.#####')+"%", _profit > 0 ? color.green : color.red, color.white)
        _winRate = ( strategy.wintrades / strategy.closedtrades ) * 100
        f_fillCell(dashTable, 0, 4, "Percent Profitable:", str.tostring(_winRate, '##.##') + "%", _winRate < 50 ? color.red : _winRate < 75 ? #999900 : color.green, color.white)
        f_fillCell(dashTable, 0, 5, "Profit Factor:", str.tostring(strategy.grossprofit / strategy.grossloss,  '##.###'), strategy.grossprofit > strategy.grossloss ? color.green : color.red, color.white)
        f_fillCell(dashTable, 0, 6, "Total Trades:", str.tostring(strategy.closedtrades), bgcolor, color.white)
        f_fillCell(dashTable, 0, 8, "Max Wins In A Row:", str.tostring(maxWinRow, '######') , bgcolor, color.white)
        f_fillCell(dashTable, 0, 9, "Max Losses In A Row:", str.tostring(maxLossRow, '######') , bgcolor, color.white)

Thêm nữa