PSX Pro Intraday Engine v3

Pine Script logic, flowchart, and line-by-line breakdown.

← Back to Docs

This document details the exact TradingView Pine Script (v5) used as the core engine for generating signals. It incorporates trend filtering, momentum checks, chop avoidance, and session-based force exits, ensuring that signals fired to the bot are high-probability setups.

Strategy Logic Flowchart

Market Data

Close Prices

1. Trend Check

Fast EMA > Slow EMA

2. Momentum

RSI (52 - 68)

3. Chop Filter

ADX > 22

4. Session Valid?

Time inside 0000-2400 (PKT)

LONG CONDITION TRIGGERED

Calculates Dynamic SL (ATR x2.0) & TP (RR x2.5)

Fire 'BUY' Webhook Alert

{"action": "BUY", ... }

5A. TP/SL Hit

Fires SELL (Target_or_SL_Hit)

5B. Session Ends

Fires SELL (EOD_Force_Exit)

The flowchart above illustrates the life cycle of a single trade generated by the engine. All entry conditions (Trend, RSI, ADX, and Session) must align simultaneously to trigger an entry webhook. Once inside a trade, the system monitors for either a Take-Profit/Stop-Loss hit or an End-Of-Day (EOD) time limit.

Full Pine Script Code

Paste this entire code block into the Pine Editor in TradingView, click Save, and Add to Chart.

//@version=5
strategy("PSX Pro Intraday Engine v3", overlay=true, margin_long=100, initial_capital=100000, default_qty_type=strategy.percent_of_equity, default_qty_value=15)

// ==========================================
// 1. INPUT PARAMETERS
// ==========================================
grp1 = "Trend & Momentum Filters"
emaFastLen   = input.int(12, title="Fast EMA", group=grp1)
emaSlowLen   = input.int(26, title="Slow EMA", group=grp1)
rsiLen       = input.int(14, title="RSI Length", group=grp1)
rsiMin       = input.int(52, title="RSI Minimum", group=grp1)
rsiMax       = input.int(68, title="RSI Maximum (Avoid Overbought)", group=grp1)

grp2 = "Chop Filter (ADX)"
adxLen    = input.int(14, title="ADX Smoothing", group=grp2)
diLen     = input.int(14, title="DI Length", group=grp2)
adxThresh = input.int(22, title="Min ADX Strength (Filter Chop)", group=grp2)

grp3 = "Intraday Risk & Session"
atrLen      = input.int(14, title="ATR Volatility Length", group=grp3)
atrMult     = input.float(2.0, title="ATR Stop Loss Multiplier", group=grp3)
rrRatio     = input.float(2.5, title="Risk/Reward Ratio", group=grp3)
tradeSession = input.session("0000-2400", title="Trading Session (PKT)", group=grp3) // CHANGED TO 24/7 FOR CRYPTO TESTING

// ==========================================
// 2. CORE MATHEMATICS
// ==========================================
emaFast = ta.ema(close, emaFastLen)
emaSlow = ta.ema(close, emaSlowLen)
rsi     = ta.rsi(close, rsiLen)
atr     = ta.atr(atrLen)

[diPlus, diMinus, adx] = ta.dmi(diLen, adxLen)

inSession = not na(time(timeframe.period, tradeSession, "Asia/Karachi"))

// ==========================================
// 3. TRADING LOGIC (LONG ONLY)
// ==========================================
trendBullish   = emaFast > emaSlow
entryTriggerL  = ta.crossover(close, emaFast)
rsiValidLong   = rsi > rsiMin and rsi < rsiMax

marketTrending = adx > adxThresh
flat           = strategy.position_size == 0

longCondition  = trendBullish and entryTriggerL and marketTrending and rsiValidLong and inSession and flat

// ==========================================
// 4. DYNAMIC RISK MANAGEMENT
// ==========================================
var float longSL  = na
var float longTP  = na

if longCondition
    longSL := close - (atr * atrMult)
    longTP := close + ((close - longSL) * rrRatio)

// ==========================================
// 5. ENTRIES + WEBHOOK PAYLOADS
// ==========================================
if longCondition
    buyPayload = '{"action": "BUY", "ticker": "' + syminfo.ticker + '", "price": ' + str.tostring(close) + ', "stop_loss": ' + str.tostring(longSL) + ', "take_profit": ' + str.tostring(longTP) + '}'
    strategy.entry("Pro-Long", strategy.long, alert_message=buyPayload)

// ==========================================
// 6. EXITS (session-end force close + SL/TP)
// ==========================================
forceCloseLong  = not inSession and strategy.position_size > 0

if strategy.position_size > 0
    if forceCloseLong
        strategy.close("Pro-Long", comment="EOD Close", alert_message='{"action": "SELL", "ticker": "' + syminfo.ticker + '", "price": ' + str.tostring(close) + ', "reason": "EOD_Force_Exit"}')
    else
        exitPayloadL = '{"action": "SELL", "ticker": "' + syminfo.ticker + '", "price": ' + str.tostring(close) + ', "reason": "Target_or_SL_Hit"}'
        strategy.exit("Exit-Long", "Pro-Long", stop=longSL, limit=longTP, alert_message=exitPayloadL)

// ==========================================
// 7. CHART LABELS (BUY / EOD EXIT)
// ==========================================
plotshape(longCondition, title="BUY Signal", style=shape.labelup, location=location.belowbar,
     color=color.new(color.green, 0), text="BUY", textcolor=color.white, size=size.small)

plotshape(forceCloseLong, title="EOD Exit", style=shape.xcross, location=location.abovebar,
     color=color.new(color.orange, 0), text="EOD", textcolor=color.black, size=size.tiny)

var label tradeLabel = na
if longCondition
    if not na(tradeLabel)
        label.delete(tradeLabel)
    labelText = "LONG\nEntry: " + str.tostring(close, format.mintick) + "\nSL: " + str.tostring(longSL, format.mintick) + "\nTP: " + str.tostring(longTP, format.mintick)
    tradeLabel := label.new(bar_index, low - atr, labelText,
         style=label.style_label_up,
         color=color.new(color.green, 20),
         textcolor=color.white, size=size.small)

// ==========================================
// 8. CHART VISUALIZATION
// ==========================================
plot(emaFast, color=color.blue, linewidth=2, title="Fast Signal Line")
plot(emaSlow, color=color.purple, linewidth=2, title="Slow Baseline")

plot(strategy.position_size > 0 ? longSL : na, color=color.red, style=plot.style_linebr, linewidth=2, title="Long SL")
plot(strategy.position_size > 0 ? longTP : na, color=color.green, style=plot.style_linebr, linewidth=2, title="Long TP")

bgcolor(marketTrending ? color.new(color.green, 95) : color.new(color.red, 95), title="Trend vs Chop Background")

alertcondition(longCondition, title="Long Entry Alert", message="BUY signal fired")
Line-by-Line Breakdown

1. Input Parameters

This section allows you to customize the strategy directly from the TradingView UI without altering the code.

  • emaFastLen / emaSlowLen: Lengths for the Exponential Moving Averages used to gauge trend direction.
  • rsiMin / rsiMax: We only want to buy if momentum is strong enough (> 52) but not overbought (< 68).
  • adxThresh: ADX measures trend strength. A value of 22 ensures we avoid choppy, sideways markets.
  • tradeSession: The specific hours the strategy is allowed to trade. Note that timezones are localized to PKT.

2. Core Mathematics

Calculates the technical indicators using TradingView's built-in ta (Technical Analysis) library.

  • ta.ema: Calculates the fast and slow EMA based on closing prices.
  • ta.rsi: Calculates the Relative Strength Index.
  • ta.atr: Calculates the Average True Range, which measures volatility to dynamically size our Stop-Loss.
  • ta.dmi: Calculates the Directional Movement Index to extract the adx line.

3. Trading Logic

The heart of the strategy. It combines all the indicators to form a strict entry condition.

  • trendBullish: Fast EMA must be above Slow EMA.
  • entryTriggerL: The actual trigger. Fires the exact moment the price crosses back over the Fast EMA.
  • flat: Ensures we only enter a trade if we don't already have an active position open.
  • longCondition: The master boolean. It requires ALL of the above conditions to be true simultaneously.

4. Dynamic Risk Management

Calculates where to place the Stop-Loss and Take-Profit based on current market volatility.

  • longSL: Stop-loss is set exactly `ATR * 2.0` below the entry price.
  • longTP: Take-profit is calculated using the distance to the Stop-loss, multiplied by our Risk/Reward ratio (2.5).

5 & 6. Entries, Exits, and Webhook Payloads

This is how the strategy communicates with the Node.js backend.

  • buyPayload / exitPayloadL: We dynamically build JSON strings containing the exact ticker, price, and dynamically calculated SL/TP.
  • alert_message=buyPayload: When strategy.entry or strategy.exit fires, TradingView takes this JSON payload and HTTP POSTs it to your backend webhook URL.
  • forceCloseLong: If the trading session ends (e.g., market close) and we still have an open position, this forces an immediate exit to prevent holding overnight.