Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save feliperazeek/bdacc901f9ce3e561f14145681af60f6 to your computer and use it in GitHub Desktop.
Save feliperazeek/bdacc901f9ce3e561f14145681af60f6 to your computer and use it in GitHub Desktop.
123-UShape-strategy.pine
//@version=5
strategy("NakInvest - 123 Strategy (Full Control)", overlay=true,
default_qty_type=strategy.percent_of_equity,
default_qty_value=1,
commission_type=strategy.commission.percent,
commission_value=0.045)
// === INPUTS ===
// Pattern
minBodyRatio = input.float(0.7, "Min Body Size Ratio (Candle 3 vs 1)", minval=0.1, group="123 Pattern")
maxBody2Ratio = input.float(0.3, "Max Body Size Ratio for Candle 2 (vs Candle 1)", minval=0.05, group="123 Pattern")
showPatternLabels = input.bool(true, "Show 123 Pattern Labels", group="123 Pattern")
// Trade Direction
enableLong = input.bool(true, "Enable Long Trades", group="Trade Direction")
enableShort = input.bool(true, "Enable Short Trades", group="Trade Direction")
// Moving Averages
maType = input.string("EMA", "MA Type", options=["EMA", "SMA"], group="Moving Averages")
fastLength = input.int(40, "Fast MA Length", group="Moving Averages")
slowLength = input.int(80, "Slow MA Length", group="Moving Averages")
// MA Filters
useTrendFilter = input.bool(false, "Use Trend Filter (Fast > Slow)", group="MA Filter")
useMASlope = input.bool(false, "Use MA Slope Filter", group="MA Filter")
requirePriceAboveBelowMA = input.bool(false, "Require Price Above/Below Both MAs", group="MA Filter")
// Stop Loss Options
slType = input.string("Candle", "Stop Loss Type", options=["Candle", "Percentage"], group="Stop Loss")
slPerc = input.float(5.0, "Stop Loss %", minval=0, maxval=100, group="Stop Loss")
// Take Profit Options
tpType = input.string("Percentage", "Take Profit Type", options=["Percentage", "MA Exit", "Risk-Reward"], group="Take Profit")
tpPerc = input.float(1.0, "Target Profit %", minval=0, maxval=100, group="Take Profit")
rrRatio = input.float(2.0, "Risk-Reward Ratio (for RR TP)", minval=0.5, step=0.1, group="Take Profit")
atrMultiplier = input.float(1.0, "ATR Multiplier (RR TP)", minval=0.1, group="Take Profit")
atrLength = input.int(14, "ATR Length (RR TP)", group="Take Profit")
// Date Filter
startDate = input.time(timestamp("2025-01-01 00:00 +0000"), "Start Date", group="Date Filter")
endDate = input.time(timestamp("2030-01-01 00:00 +0000"), "End Date", group="Date Filter")
inDateRange = time >= startDate and time <= endDate
// Time-of-Day Filter
useSessionTime = input.bool(false, "Enable Time of Day Filter", group="Time Filter")
sessionStart = input.time(timestamp("1970-01-01 09:30 +0000"), "Session Start (UTC)", group="Time Filter")
sessionEnd = input.time(timestamp("1970-01-01 16:00 +0000"), "Session End (UTC)", group="Time Filter")
t = time % 86400000
inSession = not useSessionTime or (t >= (sessionStart % 86400000) and t <= (sessionEnd % 86400000))
// Day-of-Week Filter
useWeekdayFilter = input.bool(false, "Enable Weekday Filter", group="Time Filter")
mon = input.bool(true, "Monday", group="Time Filter")
tue = input.bool(true, "Tuesday", group="Time Filter")
wed = input.bool(true, "Wednesday", group="Time Filter")
thu = input.bool(true, "Thursday", group="Time Filter")
fri = input.bool(true, "Friday", group="Time Filter")
allowedWeekday = dayofweek == dayofweek.monday and mon or
dayofweek == dayofweek.tuesday and tue or
dayofweek == dayofweek.wednesday and wed or
dayofweek == dayofweek.thursday and thu or
dayofweek == dayofweek.friday and fri
inWeekday = not useWeekdayFilter or allowedWeekday
// === MA CALCULATION ===
getMA(src, len) => maType == "EMA" ? ta.ema(src, len) : ta.sma(src, len)
fastMA = getMA(close, fastLength)
slowMA = getMA(close, slowLength)
fastSlope = fastMA - fastMA[1]
slowSlope = slowMA - slowMA[1]
plot(fastMA, title="Fast MA", color=color.green)
plot(slowMA, title="Slow MA", color=color.red)
// === PATTERN LOGIC ===
bodySize(idx) => math.abs(close[idx] - open[idx])
isGreen(idx) => close[idx] > open[idx]
isRed(idx) => close[idx] < open[idx]
c1_body = bodySize(2)
c2_body = bodySize(1)
c3_body = bodySize(0)
is123Bullish = isRed(2) and c2_body < c1_body * maxBody2Ratio and isGreen(0) and bodySize(0) >= c1_body * minBodyRatio
is123Bearish = isGreen(2) and c2_body < c1_body * maxBody2Ratio and isRed(0) and bodySize(0) >= c1_body * minBodyRatio
// === LABELS ===
if showPatternLabels
if enableLong and is123Bullish
label.new(bar_index, low, "123-U", style=label.style_label_up, color=color.green, textcolor=color.white, size=size.small)
if enableShort and is123Bearish
label.new(bar_index, high, "123-∩", style=label.style_label_down, color=color.red, textcolor=color.white, size=size.small)
// === FILTERS ===
trendLong = not useTrendFilter or (fastMA > slowMA)
trendShort = not useTrendFilter or (fastMA < slowMA)
slopeLong = not useMASlope or (fastSlope > 0)
slopeShort = not useMASlope or (fastSlope < 0)
priceAboveMAs = close > fastMA and close > slowMA
priceBelowMAs = close < fastMA and close < slowMA
inTimeAndDate = inDateRange and inSession and inWeekday
// === ATR ===
atr = ta.atr(atrLength)
// === LONG TRADE ===
if enableLong and is123Bullish and trendLong and slopeLong and (not requirePriceAboveBelowMA or priceAboveMAs) and inTimeAndDate
slLong = slType == "Candle" ? low : close * (1 - slPerc / 100), tpLong = tpType == "Percentage" ? close * (1 + tpPerc / 100) : tpType == "Risk-Reward" ? close + (close - slLong) * rrRatio : na
strategy.entry("Long", strategy.long), strategy.exit("Exit Long", from_entry="Long", stop=slLong, limit=tpType == "MA Exit" ? na : tpLong)
line.new(bar_index, tpType == "MA Exit" ? na : tpLong, bar_index + 1, tpType == "MA Exit" ? na : tpLong, color=color.green, width=1)
line.new(bar_index, slLong, bar_index + 1, slLong, color=color.red, width=1)
// === SHORT TRADE ===
if enableShort and is123Bearish and trendShort and slopeShort and (not requirePriceAboveBelowMA or priceBelowMAs) and inTimeAndDate
slShort = slType == "Candle" ? high : close * (1 + slPerc / 100), tpShort = tpType == "Percentage" ? close * (1 - tpPerc / 100) : tpType == "Risk-Reward" ? close - (slShort - close) * rrRatio : na
strategy.entry("Short", strategy.short), strategy.exit("Exit Short", from_entry="Short", stop=slShort, limit=tpType == "MA Exit" ? na : tpShort)
line.new(bar_index, tpType == "MA Exit" ? na : tpShort, bar_index + 1, tpType == "MA Exit" ? na : tpShort, color=color.green, width=1)
line.new(bar_index, slShort, bar_index + 1, slShort, color=color.red, width=1)
// === MA EXIT ===
if tpType == "MA Exit"
strategy.close("Long", when=close < fastMA)
strategy.close("Short", when=close > fastMA)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment