Эта стратегия в основном основана на индикаторе SSL Channel и индикаторе Wave Trend в сочетании с другими вспомогательными индикаторами для реализации относительно полной количественной торговой стратегии.
Эта стратегия имеет шесть условий для вступления, из которых первые два являются основными условиями, а именно:
Когда эти 6 условий выполняются одновременно, стратегия будет длинной или короткой. Расстояние стоп-лосса рассчитывается на основе значения индикатора ATR, а расстояние прибыли - это коэффициент риска и вознаграждения умноженное на стоп-лосс.
Стратегия также имеет надежный механизм управления рисками и деньгами, включая установку стоп-лосса, контроль размеров позиций и максимальный контроль вывода.
Наибольшее преимущество этой стратегии заключается в том, что индикатор SSL Channel очень точно определяет направление тренда. В сочетании с Wave Trend и другими индикаторами для подтверждения он может значительно уменьшить ложные сигналы. В то же время строгие условия входа также могут избежать ненужных сделок, тем самым уменьшая количество сделок и снижая затраты на транзакции.
Кроме того, разумный механизм управления рисками и капиталом стратегии также является значительным преимуществом. Заранее установленные стратегии стоп-лосса и прибыли могут эффективно контролировать максимальную потерю одной сделки. В сочетании с контролем размеров позиций он может поддерживать максимальное снижение счета в пределах приемлемого диапазона.
Самый большой риск этой стратегии заключается в том, что строгие условия входа могут упустить некоторые торговые возможности, влияя на прибыльность.
Кроме того, на эффективность Wave Trend и других индикаторов в определении рыночных тенденций также будут влиять аномалии, такие как ложные прорывы на рынке.
В целом, риски этой стратегии все еще поддаются контролю.
Для этой стратегии существует несколько направлений оптимизации:
Оптимизируйте параметры тренда волны для более точного определения точек переворота тренда
Добавить другие индикаторы для подтверждения, такие как KDJ, MACD и т. д., чтобы избежать влияния ложных прорывов.
Параметры могут быть настроены и оптимизированы для различных продуктов и временных рамок для улучшения стабильности стратегии
Добавить алгоритмы машинного обучения для обучения моделей с историческими данными и оптимизировать параметры в режиме реального времени
Использование высокочастотных факторов и других алгоритмов для увеличения частоты и прибыльности стратегии торговли
Ожидается, что посредством реализации этих мер оптимизации рентабельность и стабильность стратегии будут повышены.
В целом, эта стратегия объединяет несколько индикаторов и строгие механизмы входа, чтобы обеспечить высокий уровень выигрыша при достижении хорошего контроля рисков.
/*backtest start: 2024-01-01 00:00:00 end: 2024-01-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/ // © kevinmck100 // @credits // - Wave Trend: Indicator: WaveTrend Oscillator [WT] by @LazyBear // - SSL Channel: SSL channel by @ErwinBeckers // - SSL Hybrid: SSL Hybrid by @Mihkel00 // - Keltner Channels: Keltner Channels Bands by @ceyhun // - Candle Height: Candle Height in Percentage - Columns by @FreeReveller // - NNFX ATR: NNFX ATR by @sueun123 // // Strategy: Based on the YouTube video "This Unique Strategy Made 47% Profit in 2.5 Months [SSL + Wave Trend Strategy Tested 100 Times]" by TradeSmart. // @description // // Strategy incorporates the following features: // // - Risk management: Configurable X% loss per stop loss // Configurable R:R ratio // // - Trade entry: Based on strategy conditions below // // - Trade exit: Based on strategy conditions below // // - Backtesting: Configurable backtesting range by date // // - Chart drawings: Each entry condition indicator can be turned on and off // TP/SL boxes drawn for all trades. Can be turned on and off // Trade exit information labels. Can be turned on and off // NOTE: Trade drawings will only be applicable when using overlay strategies // // - Alerting: Alerts on LONG and SHORT trade entries // // - Debugging: Includes section with useful debugging techniques // // Strategy conditions: // // - Trade entry: LONG: C1: SSL Hybrid baseline is BLUE // C2: SSL Channel crosses up (green on top) // C3: Wave Trend crosses up (represented by pink candle body) // C4: Entry candle height is not greater than configured threshold // C5: Entry candle is inside Keltner Channel (wicks or body depending on configuration) // C6: Take Profit target does not touch EMA (represents resistance) // // SHORT: C1: SSL Hybrid baseline is RED // C2: SSL Channel crosses down (red on top) // C3: Wave Trend crosses down (represented by orange candle body) // C4: Entry candle height is not greater than configured threshold // C5: Entry candle is inside Keltner Channel (wicks or body depending on configuration) // C6: Take Profit target does not touch EMA (represents support) // // - Trade exit: Stop Loss: Size configurable with NNFX ATR multiplier // Take Profit: Calculated from Stop Loss using R:R ratio //@version=5 INITIAL_CAPITAL = 1000 DEFAULT_COMMISSION = 0.02 MAX_DRAWINGS = 500 IS_OVERLAY = true strategy("SSL + Wave Trend Strategy", overlay = IS_OVERLAY, initial_capital = INITIAL_CAPITAL, currency = currency.NONE, max_labels_count = MAX_DRAWINGS, max_boxes_count = MAX_DRAWINGS, max_lines_count = MAX_DRAWINGS, default_qty_type = strategy.cash, commission_type = strategy.commission.percent, commission_value = DEFAULT_COMMISSION) // ============================================================================= // INPUTS // ============================================================================= // ---------------------- // Trade Entry Conditions // ---------------------- useSslHybrid = input.bool (true, "Use SSL Hybrid Condition", group = "Strategy: Entry Conditions", inline = "SC1") useKeltnerCh = input.bool (true, "Use Keltner Channel Condition ", group = "Strategy: Entry Conditions", inline = "SC2") keltnerChWicks = input.bool (true, "Keltner Channel Include Wicks", group = "Strategy: Entry Conditions", inline = "SC2") useEma = input.bool (true, "Target not touch EMA Condition", group = "Strategy: Entry Conditions", inline = "SC3") useCandleHeight = input.bool (true, "Use Candle Height Condition", group = "Strategy: Entry Conditions", inline = "SC4") candleHeight = input.float (1.0, "Candle Height Threshold ", group = "Strategy: Entry Conditions", inline = "SC5", minval = 0, step = 0.1, tooltip = "Percentage difference between high and low of a candle. Expressed as a decimal. Lowering this value will filter out trades on volatile candles.") // --------------------- // Trade Exit Conditions // --------------------- slAtrMultiplier = input.float (1.7, "Stop Loss ATR Multiplier ", group = "Strategy: Exit Conditions", inline = "EC1", minval = 0, step = 0.1, tooltip = "Size 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.") // --------------- // Risk Management // --------------- riskReward = input.float (2.5, "Risk : Reward 1 :", group = "Strategy: Risk Management", inline = "RM1", minval = 0, step = 0.1, tooltip = "Used to determine Take Profit level. Take Profit will be Stop Loss multiplied by this value.") accountRiskPercent = input.float (1, "Portfolio Risk % ", group = "Strategy: Risk Management", inline = "RM2", 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.") // ---------- // Date Range // ---------- startYear = input.int (2022, "Start Date ", group = "Strategy: Date Range", inline = "DR1", minval = 1900, maxval = 2100) startMonth = input.int (1, "", group = "Strategy: Date Range", inline = "DR1", options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) startDate = input.int (1, "", group = "Strategy: Date Range", inline = "DR1", options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]) endYear = input.int (2100, "End Date ", group = "Strategy: Date Range", inline = "DR2", minval = 1900, maxval = 2100) endMonth = input.int (1, "", group = "Strategy: Date Range", inline = "DR2", options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) endDate = input.int (1, "", group = "Strategy: Date Range", inline = "DR2", options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]) // ---------------- // Display Settings // ---------------- showTpSlBoxes = input.bool (true, "Show TP / SL Boxes", group = "Strategy: Drawings", inline = "D1", 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.") showLabels = input.bool (false, "Show Trade Exit Labels", group = "Strategy: Drawings", inline = "D2", 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.") // ------------------ // Indicator Settings // ------------------ // Indicator display options showSslHybrid = input.bool (true, "Show SSL Hybrid", group = "Indicators: Drawings", inline = "ID1") showSslChannel = input.bool (true, "Show SSL Channel", group = "Indicators: Drawings", inline = "ID2") showEma = input.bool (true, "Show EMA", group = "Indicators: Drawings", inline = "ID3") showKeltner = input.bool (true, "Show Keltner Channel", group = "Indicators: Drawings", inline = "ID4") showWaveTrend = input.bool (true, "Show Wave Trend Flip Candles", group = "Indicators: Drawings", inline = "ID5") showAtrSl = input.bool (true, "Show ATR Stop Loss Bands", group = "Indicators: Drawings", inline = "ID6") // Wave Trend Settings n1 = input.int (10, "Channel Length ", group = "Indicators: Wave Trend", inline = "WT1") n2 = input.int (21, "Average Length ", group = "Indicators: Wave Trend", inline = "WT2") obLevel1 = input.int (60, "Over Bought Level 1 ", group = "Indicators: Wave Trend", inline = "WT3") obLevel2 = input.int (53, "Over Bought Level 2 ", group = "Indicators: Wave Trend", inline = "WT4") osLevel1 = input.int (-60, "Over Sold Level 1 ", group = "Indicators: Wave Trend", inline = "WT5") osLevel2 = input.int (-53, "Over Sold Level 2 ", group = "Indicators: Wave Trend", inline = "WT6") // SSL Channel Settings sslChLen = input.int (10, "Period ", group = "Indicators: SSL Channel", inline = "SC1") // SSL Hybrid Settings // Show/hide Inputs show_color_bar = input.bool (false, "Show Color Bars", group = "Indicators: SSL Hybrid", inline = "SH2") // Baseline Inputs maType = input.string ("HMA", "Baseline Type ", group = "Indicators: SSL Hybrid", inline = "SH3", options=["SMA", "EMA", "DEMA", "TEMA", "LSMA", "WMA", "MF", "VAMA", "TMA", "HMA", "JMA", "Kijun v2", "EDSMA", "McGinley"]) len = input.int (60, "Baseline Length ", group = "Indicators: SSL Hybrid", inline = "SH4") src = input.source (close, "Source ", group = "Indicators: SSL Hybrid", inline = "SH5") kidiv = input.int (1, "Kijun MOD Divider ", group = "Indicators: SSL Hybrid", inline = "SH6", maxval=4) jurik_phase = input.int (3, "* Jurik (JMA) Only - Phase ", group = "Indicators: SSL Hybrid", inline = "SH7") jurik_power = input.int (1, "* Jurik (JMA) Only - Power ", group = "Indicators: SSL Hybrid", inline = "SH8") volatility_lookback = input.int (10, "* Volatility Adjusted (VAMA) Only - Volatility lookback length", group = "Indicators: SSL Hybrid", inline = "SH9") //Modular Filter Inputs beta = input.float (0.8, "Modular Filter, General Filter Only - Beta ", group = "Indicators: SSL Hybrid", inline = "SH10", minval=0, maxval=1, step=0.1) feedback = input.bool (false, "Modular Filter Only - Feedback", group = "Indicators: SSL Hybrid", inline = "SH11") z = input.float (0.5, "Modular Filter Only - Feedback Weighting ", group = "Indicators: SSL Hybrid", inline = "SH12", step=0.1, minval=0, maxval=1) //EDSMA Inputs ssfLength = input.int (20, "EDSMA - Super Smoother Filter Length ", group = "Indicators: SSL Hybrid", inline = "SH13", minval=1) ssfPoles = input.int (2, "EDSMA - Super Smoother Filter Poles ", group = "Indicators: SSL Hybrid", inline = "SH14", options=[2, 3]) ///Keltner Baseline Channel Inputs useTrueRange = input.bool (true, "Use True Range?", group = "Indicators: SSL Hybrid", inline = "SH15") multy = input.float (0.2, "Base Channel Multiplier ", group = "Indicators: SSL Hybrid", inline = "SH16", step=0.05) // EMA Settings emaLength = input.int (200, "EMA Length ", group = "Indicators: EMA", inline = "E1", minval = 1) // Keltner Channel Settings kcLength = input.int (20, "Length ", group = "Indicators: Keltner Channel", inline = "KC1", minval=1) kcMult = input.float (1.5, "Multiplier ", group = "Indicators: Keltner Channel", inline = "KC2") kcSrc = input.source (close, "Source ", group = "Indicators: Keltner Channel", inline = "KC3") alen = input.int (10, "ATR Length ", group = "Indicators: Keltner Channel", inline = "KC4", minval=1) // Candle Height in Percentage Settings chPeriod = input.int (20, "Period ", group = "Indicators: Candle Height", inline = "CH1") // NNFX ATR Settings nnfxAtrLength = input.int (14, "Length ", group = "Indicators: NNFX ATR (Stop Loss Settings)", inline = "ATR1", minval = 1) nnfxSmoothing = input.string ("RMA", "Smoothing ", group = "Indicators: NNFX ATR (Stop Loss Settings)", inline = "ATR3", options = ["RMA", "SMA", "EMA", "WMA"]) // ============================================================================= // INDICATORS // ============================================================================= // ---------- // Wave Trend // ---------- ap = hlc3 esa = ta.ema(ap, n1) d = ta.ema(math.abs(ap - esa), n1) ci = (ap - esa) / (0.015 * d) tci = ta.ema(ci, n2) wt1 = tci wt2 = ta.sma(wt1, 4) // Show Wave Trend crosses on chart as colour changes (pink bullish, orange bearish) wtBreakUp = ta.crossover (wt1, wt2) wtBreakDown = ta.crossunder (wt1, wt2) barColour = showWaveTrend ? wtBreakUp ? color.fuchsia : wtBreakDown ? color.orange : na : na barcolor(color = barColour) // ----------- // SSL Channel // ----------- smaHigh = ta.sma(high, sslChLen) smaLow = ta.sma(low, sslChLen) var int sslChHlv = na sslChHlv := close > smaHigh ? 1 : close < smaLow ? -1 : sslChHlv[1] sslChDown = sslChHlv < 0 ? smaHigh : smaLow sslChUp = sslChHlv < 0 ? smaLow : smaHigh plot(showSslChannel ? sslChDown : na, "SSL Channel Down", linewidth=1, color=color.new(color.red, 30)) plot(showSslChannel ? sslChUp : na, "SSL Channel Up", linewidth=1, color=color.new(color.lime, 30)) // ---------- // SSL Hybrid // ---------- //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 = feedback ? z * src + (1 - 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 = beta * b + (1 - beta) * c lower = beta * c + (1 - 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, volatility_lookback) vol_down= ta.lowest(dev, 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 = jurik_phase < -100 ? 0.5 : jurik_phase > 100 ? 2.5 : jurik_phase / 100 + 1.5 beta = 0.45 * (len - 1) / (0.45 * (len - 1) + 2) alpha = math.pow(beta, 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 / kidiv), ta.highest(len / 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 = ssfPoles == 2 ? get2PoleSSF(avgZeros, ssfLength) : get3PoleSSF(avgZeros, 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 BBMC = ma(maType, close, len) Keltma = ma(maType, src, len) range_1 = useTrueRange ? ta.tr : high - low rangema = ta.ema(range_1, len) upperk = Keltma + rangema * multy lowerk = Keltma - rangema * multy //COLORS color_bar = close > upperk ? #00c3ff : close < lowerk ? #ff0062 : color.gray //PLOTS p1 = plot(showSslHybrid ? BBMC : na, color=color.new(color_bar, 0), linewidth=4, title="MA Baseline") barcolor(show_color_bar ? color_bar : na) // --- // EMA // --- ema = ta.ema(close, emaLength) plot(showEma ? ema : na, "EMA Trend Line", color.white) // ---------------- // Keltner Channels // ---------------- kcMa = ta.ema(kcSrc, kcLength) KTop2 = kcMa + kcMult * ta.atr(alen) KBot2 = kcMa - kcMult * ta.atr(alen) upperPlot = plot(showKeltner ? KTop2 : na, color=color.new(color.blue, 0), title="Upper", style = plot.style_stepline) lowerPlot = plot(showKeltner ? KBot2 : na, color=color.new(color.blue, 0), title="Lower", style = plot.style_stepline) // --------------------------- // Candle Height in Percentage // --------------------------- percentHL = (high - low) / low * 100 percentRed = open > close ? (open - close) / close * 100 : 0 percentGreen= open < close ? (close - open) / open * 100 : 0 // -------- // NNFX ATR // -------- function(source, length) => if nnfxSmoothing == "RMA" ta.rma(source, nnfxAtrLength) else if nnfxSmoothing == "SMA" ta.sma(source, nnfxAtrLength) else if nnfxSmoothing == "EMA" ta.ema(source, nnfxAtrLength) else ta.wma(source, nnfxAtrLength) formula(number, decimals) => factor = math.pow(10, decimals) int(number * factor) / factor nnfxAtr = formula(function(ta.tr(true), nnfxAtrLength), 5) * slAtrMultiplier //Sell longSlAtr = nnfxAtrLength ? close - nnfxAtr : close + nnfxAtr shortSlAtr = nnfxAtrLength ? close + nnfxAtr : close - nnfxAtr plot(showAtrSl ? longSlAtr : na, "Long SL", color = color.new(color.red, 35), linewidth = 1, trackprice = true, editable = true, style = plot.style_stepline) plot(showAtrSl ? shortSlAtr : na, "Short SL", color = color.new(color.red, 35), linewidth = 1, trackprice = true, editable = true, style = plot.style_stepline) // ============================================================================= // FUNCTIONS // ============================================================================= 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 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 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 showLabels labelStr = "Position Size: " + str.tostring(math.abs(posSize), "#.##") + "\nPNL: " + str.tostring(pnl, "#.##") + "\nCapital: " + str.tostring(strategy.equity, "#.##") + "\nEntry Price: " + str.tostring(entryPrice, "#.##") 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) // ============================================================================= // STRATEGY LOGIC // ============================================================================= // See strategy description at top for details on trade entry/exit logis // ---------- // CONDITIONS // ---------- // 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 // Exit calculations slAmount = nnfxAtr slPercent = math.abs((1 - (close - slAmount) / close) * 100) tpPercent = slPercent * riskReward tpPoints = percentAsPoints(tpPercent) tpTarget = calcProfitTrgtPrice(tpPoints, wtBreakUp) inDateRange = true // Condition 1: SSL Hybrid blue for long or red for short bullSslHybrid = useSslHybrid ? close > upperk : true bearSslHybrid = useSslHybrid ? close < lowerk : true // Condition 2: SSL Channel crosses up for long or down for short bullSslChannel = ta.crossover(sslChUp, sslChDown) bearSslChannel = ta.crossover(sslChDown, sslChUp) // Condition 3: Wave Trend crosses up for long or down for short bullWaveTrend = wtBreakUp bearWaveTrend = wtBreakDown // Condition 4: Entry candle heignt <= 0.6 on Candle Height in Percentage candleHeightValid = useCandleHeight ? percentGreen <= candleHeight and percentRed <= candleHeight : true // Condition 5: Entry candle is inside Keltner Channel withinCh = keltnerChWicks ? high < KTop2 and low > KBot2 : open < KTop2 and close < KTop2 and open > KBot2 and close > KBot2 insideKeltnerCh = useKeltnerCh ? withinCh : true // Condition 6: TP target does not touch 200 EMA bullTpValid = useEma ? not (close < ema and tpTarget > ema) : true bearTpValid = useEma ? not (close > ema and tpTarget < ema) : true // Combine all entry conditions goLong = inDateRange and bullSslHybrid and bullSslChannel and bullWaveTrend and candleHeightValid and insideKeltnerCh and bullTpValid goShort = inDateRange and bearSslHybrid and bearSslChannel and bearWaveTrend and candleHeightValid and insideKeltnerCh and bearTpValid // Entry decisions openLong = (goLong and not inLong) openShort = (goShort and not inShort) flippingSides = (goLong and inShort) or (goShort and inLong) enteringTrade = openLong or openShort inTrade = inLong or inShort // Risk calculations riskAmt = strategy.equity * accountRiskPercent / 100 entryQty = math.abs(riskAmt / slPercent * 100) / close 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 alert(message="BUY Trade Entry Alert", freq=alert.freq_once_per_bar_close) 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 alert(message="SELL Trade Entry Alert", freq=alert.freq_once_per_bar_close) if enteringTrade profitPoints := percentAsPoints(tpPercent) lossPoints := percentAsPoints(slPercent) slPrice := calcStopLossPrice(lossPoints, openLong) tpPrice := calcProfitTrgtPrice(profitPoints, openLong) tradeEntryBar := bar_index 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") // ============================================================================= // DRAWINGS // ============================================================================= // ----------- // TP/SL 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) // Print boxes for trades closed at profit or loss 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) // Print TP/SL box for current open trade if barstate.islastconfirmedhistory and strategy.position_size != 0 printTpSlNotHitBox(tradeEntryBar + 1, bar_index + 1, strategy.position_avg_price, slPrice, tpPrice) // ============================================================================= // DEBUGGING // ============================================================================= // Data window plots plotchar(goLong, "Enter Long", "") plotchar(goShort, "Enter Short", "")