OPEN-SOURCE SCRIPT

jaems_Double BB[Alert]/W-Bottom/Dashboard

85
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at mozilla.org/MPL/2.0/
// © Kingjmaes

//version=6
strategy("jaems_Double BB[Alert]/W-Bottom/Dashboard", shorttitle="jaems_Double BB[Alert]/W-Bottom/Dashboard", overlay=true, commission_type=strategy.commission.percent, commission_value=0.05, slippage=1, process_orders_on_close=true)

// ==========================================
// 1. 사용자 입력 (Inputs)
// ==========================================
group_date = "📅 백테스트 기간 설정"
startTime = input.time(timestamp("2024-01-01 00:00"), "시작일", group=group_date)
endTime = input.time(timestamp("2099-12-31 23:59"), "종료일", group=group_date)

group_bb = "📊 더블 볼린저 밴드 설정"
bb_len = input.int(20, "길이 (Length)", minval=5, group=group_bb)
bb_mult_inner = input.float(1.0, "내부 밴드 승수 (Inner A)", step=0.1, group=group_bb)
bb_mult_outer = input.float(2.0, "외부 밴드 승수 (Outer B)", step=0.1, group=group_bb)

group_w = "📉 W 바닥 패턴 설정"
pivot_left = input.int(3, "피벗 좌측 봉 수", minval=1, group=group_w)
pivot_right = input.int(1, "피벗 우측 봉 수", minval=1, group=group_w)

group_dash = "🖥️ 대시보드 설정"
show_dash = input.bool(true, "대시보드 표시", group=group_dash)
comp_sym = input.symbol("NASDAQ:NDX", "비교 지수 (GS Trend)", group=group_dash, tooltip="S&P500은 'SP:SPX', 비트코인은 'BINANCE:BTCUSDT' 등을 입력하세요.")
rsi_len = input.int(14, "RSI 길이", group=group_dash)

group_risk = "🛡 리스크 관리"
use_sl_tp = input.bool(true, "손절/익절 사용", group=group_risk)
sl_pct = input.float(2.0, "손절매 (%)", step=0.1, group=group_risk) / 100
tp_pct = input.float(4.0, "익절매 (%)", step=0.1, group=group_risk) / 100

// ==========================================
// 2. 데이터 처리 및 계산 (Calculations)
// ==========================================
// 기간 필터
inDateRange = time >= startTime and time <= endTime

// [지표 1] 더블 볼린저 밴드
basis = ta.sma(close, bb_len)
dev_inner = ta.stdev(close, bb_len) * bb_mult_inner
dev_outer = ta.stdev(close, bb_len) * bb_mult_outer

upper_A = basis + dev_inner
lower_A = basis - dev_inner
upper_B = basis + dev_outer
lower_B = basis - dev_outer
percent_b = (close - lower_B) / (upper_B - lower_B)

// [지표 2] W 바닥형 (W-Bottom) - 리페인팅 방지
pl = ta.pivotlow(low, pivot_left, pivot_right)
var float p1_price = na
var float p1_pb = na
var float p2_price = na
var float p2_pb = na
var bool is_w_setup = false

if not na(pl)
p1_price := p2_price
p1_pb := p2_pb
p2_price := low[pivot_right]
p2_pb := percent_b[pivot_right]

// 패턴 감지
bool cond_w = (p1_price < lower_B[pivot_right]) and (p2_price > p1_price) and (p2_pb > p1_pb)
is_w_setup := cond_w ? true : false

w_bottom_signal = is_w_setup and close > open and close > lower_A
if w_bottom_signal
is_w_setup := false

// [지표 3] GS 트렌드 (나스닥 상대 강도)
ndx_close = request.security(comp_sym, timeframe.period, close)
rs_ratio = close / ndx_close
rs_sma = ta.sma(rs_ratio, 20)
gs_trend_bull = rs_ratio > rs_sma

// [지표 4] RSI & MACD
rsi_val = ta.rsi(close, rsi_len)
[macd_line, signal_line, _] = ta.macd(close, 12, 26, 9)
macd_bull = macd_line > signal_line

// ==========================================
// 3. 전략 로직 (Strategy Logic)
// ==========================================
long_cond = (ta.crossover(close, lower_A) or ta.crossover(close, basis) or w_bottom_signal) and inDateRange and barstate.isconfirmed
short_cond = (ta.crossunder(close, upper_B) or ta.crossunder(close, upper_A) or ta.crossunder(close, basis)) and inDateRange and barstate.isconfirmed

// 진입 실행 및 알람 발송
if long_cond
strategy.entry("Long", strategy.long, comment="Entry Long")
alert("Long Entry Triggered | Price: " + str.tostring(close), alert.freq_once_per_bar_close)

if short_cond
strategy.entry("Short", strategy.short, comment="Entry Short")
alert("Short Entry Triggered | Price: " + str.tostring(close), alert.freq_once_per_bar_close)

// 청산 실행
if use_sl_tp
if strategy.position_size > 0
strategy.exit("Exit Long", "Long", stop=strategy.position_avg_price * (1 - sl_pct), limit=strategy.position_avg_price * (1 + tp_pct), comment_loss="L-SL", comment_profit="L-TP")
if strategy.position_size < 0
strategy.exit("Exit Short", "Short", stop=strategy.position_avg_price * (1 + sl_pct), limit=strategy.position_avg_price * (1 - tp_pct), comment_loss="S-SL", comment_profit="S-TP")

// 별도 알람: W 패턴 감지 시
if w_bottom_signal
alert("W-Bottom Pattern Detected!", alert.freq_once_per_bar_close)

// ==========================================
// 4. 대시보드 시각화 (Dashboard Visualization)
// ==========================================
c_bg_head = color.new(color.black, 20)
c_bg_cell = color.new(color.black, 40)
c_text = color.white
c_bull = color.new(#00E676, 0)
c_bear = color.new(#FF5252, 0)
c_neu = color.new(color.gray, 30)

get_trend_color(is_bull) => is_bull ? c_bull : c_bear
get_pos_text() => strategy.position_size > 0 ? "LONG 🟢" : strategy.position_size < 0 ? "SHORT 🔴" : "FLAT ⚪"
get_pos_color() => strategy.position_size > 0 ? c_bull : strategy.position_size < 0 ? c_bear : c_neu

var table dash = table.new(position.top_right, 2, 7, border_width=1, border_color=color.gray, frame_color=color.gray, frame_width=1)

if show_dash and (barstate.islast or barstate.islastconfirmedhistory)
table.cell(dash, 0, 0, "METRIC", bgcolor=c_bg_head, text_color=c_text, text_size=size.small)
table.cell(dash, 1, 0, "STATUS", bgcolor=c_bg_head, text_color=c_text, text_size=size.small)

table.cell(dash, 0, 1, "GS Trend", bgcolor=c_bg_cell, text_color=c_text, text_halign=text.align_left, text_size=size.small)
table.cell(dash, 1, 1, gs_trend_bull ? "Bullish" : "Bearish", bgcolor=c_bg_cell, text_color=get_trend_color(gs_trend_bull), text_size=size.small)

rsi_col = rsi_val > 70 ? c_bear : rsi_val < 30 ? c_bull : c_neu
table.cell(dash, 0, 2, "RSI (14)", bgcolor=c_bg_cell, text_color=c_text, text_halign=text.align_left, text_size=size.small)
table.cell(dash, 1, 2, str.tostring(rsi_val, "#.##"), bgcolor=c_bg_cell, text_color=rsi_col, text_size=size.small)

table.cell(dash, 0, 3, "MACD", bgcolor=c_bg_cell, text_color=c_text, text_halign=text.align_left, text_size=size.small)
table.cell(dash, 1, 3, macd_bull ? "Bullish" : "Bearish", bgcolor=c_bg_cell, text_color=get_trend_color(macd_bull), text_size=size.small)

w_status = w_bottom_signal ? "DETECTED!" : is_w_setup ? "Setup Ready" : "Waiting"
w_col = w_bottom_signal ? c_bull : is_w_setup ? color.yellow : c_neu
table.cell(dash, 0, 4, "W-Bottoms", bgcolor=c_bg_cell, text_color=c_text, text_halign=text.align_left, text_size=size.small)
table.cell(dash, 1, 4, w_status, bgcolor=c_bg_cell, text_color=w_col, text_size=size.small)

table.cell(dash, 0, 5, "Position", bgcolor=c_bg_cell, text_color=c_text, text_halign=text.align_left, text_size=size.small)
table.cell(dash, 1, 5, get_pos_text(), bgcolor=c_bg_cell, text_color=get_pos_color(), text_size=size.small)

last_sig = long_cond ? "BUY SIGNAL" : short_cond ? "SELL SIGNAL" : "HOLD"
last_col = long_cond ? c_bull : short_cond ? c_bear : c_neu
table.cell(dash, 0, 6, "Signal", bgcolor=c_bg_cell, text_color=c_text, text_halign=text.align_left, text_size=size.small)
table.cell(dash, 1, 6, last_sig, bgcolor=c_bg_cell, text_color=last_col, text_size=size.small)

// ==========================================
// 5. 시각화 (Visualization)
// ==========================================
p_upper_B = plot(upper_B, "Upper B", color=color.new(color.red, 50))
p_upper_A = plot(upper_A, "Upper A", color=color.new(color.red, 0))
p_basis = plot(basis, "Basis", color=color.gray)
p_lower_A = plot(lower_A, "Lower A", color=color.new(color.green, 0))
p_lower_B = plot(lower_B, "Lower B", color=color.new(color.green, 50))
fill(p_upper_B, p_upper_A, color=color.new(color.red, 90))
fill(p_lower_A, p_lower_B, color=color.new(color.green, 90))

plotshape(long_cond, title="Long", style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small)
plotshape(short_cond, title="Short", style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small)

Disclaimer

The information and publications are not meant to be, and do not constitute, financial, investment, trading, or other types of advice or recommendations supplied or endorsed by TradingView. Read more in the Terms of Use.