
Strategi ini didasarkan pada indikator SSL Channel dan Trend Wave, yang dikombinasikan dengan indikator tambahan lainnya, untuk mencapai strategi perdagangan kuantitatif yang lebih lengkap. Nama strategi ini mencakup indikator inti SSL Channel dan Trend Wave, serta kata kunci untuk perdagangan kuantitatif, sesuai dengan persyaratan.
Strategi ini didasarkan pada enam syarat masuk, dua di antaranya adalah syarat inti, yaitu:
Ketika 6 kondisi ini terpenuhi secara bersamaan, strategi akan masuk untuk melakukan over atau under. Jarak stop loss dihitung berdasarkan nilai indikator ATR, dan jarak stop loss adalah dua kali Rasio Risiko Reward dari stop loss.
Strategi ini juga memiliki mekanisme manajemen risiko yang lengkap, termasuk pengaturan stop loss, kontrol ukuran posisi, dan kontrol penarikan maksimum. Selain itu, strategi ini memetakan garis tambahan di grafik, yang dapat melihat secara intuitif setiap stop loss dan stop loss, serta kerugian spesifik. Ini sangat membantu untuk analisis dan strategi optimasi.
Keuntungan terbesar dari strategi ini adalah akurasi yang sangat tinggi dalam menentukan arah tren menggunakan indikator saluran SSL, kemudian bekerja sama dengan indikator seperti tren gelombang untuk konfirmasi, dapat mengurangi sinyal palsu secara signifikan. Pada saat yang sama, persyaratan masuk yang ketat juga dapat menghindari transaksi yang tidak perlu, sehingga mengurangi jumlah transaksi dan mengurangi biaya transaksi.
Selain itu, mekanisme pengelolaan risiko dan dana yang baik dari strategi ini juga merupakan keuntungan besar. Strategi stop-loss dan stop-loss yang baik yang telah ditetapkan sebelumnya dapat secara efektif mengontrol kerugian maksimum dalam satu transaksi.
Risiko terbesar dari strategi ini adalah bahwa persyaratan masuk yang ketat akan melewatkan beberapa peluang perdagangan, yang menyebabkan beberapa dampak pada profitabilitas. Strategi ini juga mengurangi profitabilitas ketika pasar berada dalam keadaan goyah.
Selain itu, indikator seperti tren gelombang menilai efek dari tren pasar, juga dapat dipengaruhi oleh abnormalitas pasar seperti false breakout. Pada saat ini perlu untuk menyesuaikan parameter, atau menambahkan indikator lain untuk konfirmasi.
Secara keseluruhan, risiko dari strategi ini dapat dikontrol. Dengan penyesuaian dan pengoptimalan parameter, strategi dapat disesuaikan dengan kondisi pasar yang berbeda.
Strategi ini juga dapat dioptimalkan dengan beberapa cara:
Parameter yang dioptimalkan untuk tren gelombang, sehingga dapat lebih akurat menilai titik-titik perubahan tren
Menambahkan indikator lain untuk konfirmasi, seperti KDJ, MACD, dan lain-lain, untuk menghindari dampak false breach
Optimalisasi parameter dapat disesuaikan dengan varietas dan siklus yang berbeda untuk meningkatkan stabilitas strategi
Menambahkan algoritma pembelajaran mesin, memanfaatkan pelatihan data historis, dan parameter strategi optimasi real-time
Strategi untuk meningkatkan frekuensi perdagangan dan profitabilitas dengan menggunakan algoritma seperti High Frequency Factor
Implementasi langkah-langkah optimasi ini diharapkan dapat meningkatkan profitabilitas dan stabilitas strategi.
Secara keseluruhan, strategi ini mengintegrasikan berbagai indikator dan mekanisme masuk yang ketat, serta memberikan efek pengendalian risiko yang baik sambil memastikan tingkat kemenangan yang tinggi. Dengan arah optimasi di masa depan, strategi ini memiliki potensi besar untuk dikembangkan sebagai strategi perdagangan kuantitatif yang disarankan.
/*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", "")