
이 전략은 주로 SSL 통로 지표와 파동 트렌드 지표에 기반하며, 다른 보조 지표와 결합하여 보다 완전한 양적 거래 전략을 구현한다. 이 전략 이름은 핵심 지표 SSL 통로와 파동 트렌드, 그리고 양적 거래의 키워드를 포함하고 있으며, 요구 사항에 부합한다.
이 전략은 6개의 조건에 따라 거래가 이루어집니다. 그 중 첫 번째 두 가지는 핵심 조건입니다.
이 6가지 조건이 동시에 충족될 때, 전략은 상장하거나 상장하지 않는다. 스톱로스 거리는 ATR 지표의 수치를 기준으로 계산되며, 스톱로스 거리는 스톱로스의 리스크 리워드 비율의 두 배이다.
이 전략은 또한 stop loss 설정, 포지션 규모 제어, 최대 철회 제어 등이 포함된 완벽한 위험 관리 메커니즘을 갖추고 있습니다. 또한, 이 전략은 차트에 보조 라인을 그리고 있으며, 각 스톱 및 스톱 포지션을 직관적으로 볼 수 있으며, 구체적인 손실 상황을 볼 수 있습니다. 이것은 분석 및 최적화 전략에 매우 도움이됩니다.
이 전략의 가장 큰 장점은 SSL 통로 지표를 사용하여 트렌드 방향을 판단하는 정확도가 매우 높으며, 파동 트렌드와 같은 지표와 함께 확인하면 가짜 신호를 크게 줄일 수 있다는 것입니다. 또한, 엄격한 입시 조건은 불필요한 거래를 피할 수 있으며, 따라서 거래 횟수를 줄이고 거래 비용을 줄일 수 있습니다.
또한, 이 전략의 완벽한 위험과 자금 관리 메커니즘도 큰 장점이다. 미리 설정된 좋은 중지 손실 및 중지 전략은 단일 거래의 최대 손실을 효과적으로 제어할 수 있다. 포지션 규모의 제어와 함께, 계좌의 최대 인출을 감당할 수 있는 범위 내에서 제어할 수 있다.
이 전략의 가장 큰 위험은, 엄격한 입시 조건으로 거래 기회를 놓치게 되고, 이로 인해 수익성에 영향을 미치게 된다. 시장이 흔들리는 상태일 때 이 전략의 수익성은 또한 할인된다.
또한, 파동 트렌드 같은 지표가 시장 트렌드를 판단하는 효과에 영향을 미치기도 한다. 이때는 파라미터를 조정하거나, 다른 지표를 추가하여 확인해야 한다.
전반적으로, 이 전략의 위험은 통제할 수 있다. 매개 변수를 조정하고 최적화함으로써 전략이 다른 시장 환경에 더 잘 적응할 수 있다.
이 전략은 다음과 같은 몇 가지 측면에서 최적화될 수 있습니다.
트렌드 전환점을 더 정확하게 판단할 수 있도록 파동 트렌드의 매개 변수를 최적화합니다.
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", "")