Page 2 of 3
Re: Write Entry Rules So Specific a Stranger Could Follow Them
Posted: Wed Sep 23, 2026 8:55 am
by PTScalper
Adding a time filter prevents your system from taking trades during low-liquidity periods (like the Asian session) or highly volatile, unpredictable periods (like the first 5 minutes of the open).
Here is the updated script. It introduces a session input set to standard New York stock exchange hours (09:30 to 16:00 EST). I also added a subtle grey background highlight to your chart so you can visually verify exactly when the algorithm is "awake" and looking for trades.
Code: Select all
//@version=5
strategy("The Complete Stranger Rule - NY Session", overlay=true, initial_capital=1000, default_qty_type=strategy.percent_of_equity, default_qty_value=10)
// ==========================================
// 1. SETTINGS INPUTS (Adjustable)
// ==========================================
slPercent = input.float(1.0, title="Stop Loss (%)", step=0.1) / 100
tpPercent = input.float(2.0, title="Take Profit (%)", step=0.1) / 100
// Session Time Inputs
tradeSession = input.session("0930-1600", title="Trading Session")
timeZone = input.string("America/New_York", title="Time Zone")
// ==========================================
// 2. DEFINE THE TIME FILTER
// ==========================================
// The time() function returns 'na' (not applicable) if the current bar is outside the session.
// We use 'not na()' to create a simple true/false condition.
inSession = not na(time(timeframe.period, tradeSession, timeZone))
// ==========================================
// 3. DEFINE THE INDICATORS
// ==========================================
ema20 = ta.ema(close, 20)
rsiValue = ta.rsi(close, 14)
volSma20 = ta.sma(volume, 20)
// ==========================================
// 4. DEFINE THE EXACT ENTRY RULES
// ==========================================
// LONG: Price > EMA, RSI > 50, Volume spike, AND market is in the defined session
enterLong = (close > ema20) and (rsiValue > 50) and (volume > volSma20) and inSession
// SHORT: Price < EMA, RSI < 50, Volume spike, AND market is in the defined session
enterShort = (close < ema20) and (rsiValue < 50) and (volume > volSma20) and inSession
// ==========================================
// 5. EXECUTE TRADES & SET EXITS
// ==========================================
// Enter Long
if (enterLong and strategy.position_size == 0)
strategy.entry("Long", strategy.long)
// Enter Short
if (enterShort and strategy.position_size == 0)
strategy.entry("Short", strategy.short)
// Calculate dynamic SL/TP levels depending on trade direction
longStopPrice = strategy.position_avg_price * (1 - slPercent)
longTakeProfit = strategy.position_avg_price * (1 + tpPercent)
shortStopPrice = strategy.position_avg_price * (1 + slPercent)
shortTakeProfit = strategy.position_avg_price * (1 - tpPercent)
// Send the exit orders to the broker/backtester
if (strategy.position_size > 0) // If we are Long
strategy.exit("Exit Long", from_entry="Long", stop=longStopPrice, limit=longTakeProfit)
if (strategy.position_size < 0) // If we are Short
strategy.exit("Exit Short", from_entry="Short", stop=shortStopPrice, limit=shortTakeProfit)
// ==========================================
// 6. CHART VISUALS
// ==========================================
// Plot the 20 EMA
plot(ema20, color=color.blue, title="20 EMA", linewidth=2)
// Highlight the background green for Longs, red for Shorts
bgcolor(enterLong ? color.new(color.green, 85) : na, title="Long Entry Met")
bgcolor(enterShort ? color.new(color.red, 85) : na, title="Short Entry Met")
// Highlight the trading session background slightly to see when the bot is active
bgcolor(inSession ? color.new(color.gray, 95) : na, title="Session Active")
// Determine which level to plot based on position direction
activeTP = strategy.position_size > 0 ? longTakeProfit : (strategy.position_size < 0 ? shortTakeProfit : na)
activeSL = strategy.position_size > 0 ? longStopPrice : (strategy.position_size < 0 ? shortStopPrice : na)
// Draw visual lines for SL and TP while in a trade
plot(activeTP, color=color.green, style=plot.style_linebr, linewidth=2, title="Active TP Level")
plot(activeSL, color=color.red, style=plot.style_linebr, linewidth=2, title="Active SL Level")
Re: Write Entry Rules So Specific a Stranger Could Follow Them
Posted: Wed Sep 23, 2026 8:55 am
by PTScalper
Note on Overnight Risk
Right now, the inSession rule only prevents new entries outside of market hours. If a trade is opened at 15:55, and neither the Stop Loss nor the Take Profit is hit by 16:00, the strategy will hold that trade overnight into the next day.
Re: Write Entry Rules So Specific a Stranger Could Follow Them
Posted: Wed Sep 23, 2026 8:56 am
by PTScalper
To prevent overnight gap risks, we need to introduce a "flatten" window just before the market closes. If a trade is still active when this window hits, the system will automatically close it at the current market price and block any new entries from firing until the next day.
I have updated the script and organized the settings menu into clean Risk Management and Time Filters groups.
Code: Select all
//@version=5
strategy("The Complete Stranger Rule - EOD Close", overlay=true, initial_capital=1000, default_qty_type=strategy.percent_of_equity, default_qty_value=10)
// ==========================================
// 1. SETTINGS INPUTS (Adjustable)
// ==========================================
slPercent = input.float(1.0, title="Stop Loss (%)", step=0.1, group="Risk Management") / 100
tpPercent = input.float(2.0, title="Take Profit (%)", step=0.1, group="Risk Management") / 100
// Session Time Inputs
tradeSession = input.session("0930-1600", title="Trading Session", group="Time Filters")
timeZone = input.string("America/New_York", title="Time Zone", group="Time Filters")
forceEodClose = input.bool(true, title="Force End of Day Close?", group="Time Filters")
eodCloseTime = input.session("1545-1600", title="EOD Close Window", group="Time Filters")
// ==========================================
// 2. DEFINE THE TIME FILTER
// ==========================================
inSession = not na(time(timeframe.period, tradeSession, timeZone))
inEodWindow = not na(time(timeframe.period, eodCloseTime, timeZone))
// Allow entries only if we are in the session AND not in the closing window
canTrade = inSession and not (forceEodClose and inEodWindow)
// ==========================================
// 3. DEFINE THE INDICATORS
// ==========================================
ema20 = ta.ema(close, 20)
rsiValue = ta.rsi(close, 14)
volSma20 = ta.sma(volume, 20)
// ==========================================
// 4. DEFINE THE EXACT ENTRY RULES
// ==========================================
// LONG: Price > EMA, RSI > 50, Volume spike, AND it's a valid time to trade
enterLong = (close > ema20) and (rsiValue > 50) and (volume > volSma20) and canTrade
// SHORT: Price < EMA, RSI < 50, Volume spike, AND it's a valid time to trade
enterShort = (close < ema20) and (rsiValue < 50) and (volume > volSma20) and canTrade
// ==========================================
// 5. EXECUTE TRADES & SET EXITS
// ==========================================
// Enter Long
if (enterLong and strategy.position_size == 0)
strategy.entry("Long", strategy.long)
// Enter Short
if (enterShort and strategy.position_size == 0)
strategy.entry("Short", strategy.short)
// Calculate dynamic SL/TP levels depending on trade direction
longStopPrice = strategy.position_avg_price * (1 - slPercent)
longTakeProfit = strategy.position_avg_price * (1 + tpPercent)
shortStopPrice = strategy.position_avg_price * (1 + slPercent)
shortTakeProfit = strategy.position_avg_price * (1 - tpPercent)
// Send the SL/TP exit orders
if (strategy.position_size > 0)
strategy.exit("Exit Long", from_entry="Long", stop=longStopPrice, limit=longTakeProfit)
if (strategy.position_size < 0)
strategy.exit("Exit Short", from_entry="Short", stop=shortStopPrice, limit=shortTakeProfit)
// Force Close at End of Day
if (forceEodClose and inEodWindow)
strategy.close("Long", comment="EOD Close")
strategy.close("Short", comment="EOD Close")
// ==========================================
// 6. CHART VISUALS
// ==========================================
// Plot the 20 EMA
plot(ema20, color=color.blue, title="20 EMA", linewidth=2)
// Highlight the background green for Longs, red for Shorts
bgcolor(enterLong ? color.new(color.green, 85) : na, title="Long Entry Met")
bgcolor(enterShort ? color.new(color.red, 85) : na, title="Short Entry Met")
// Highlight the trading session background
bgcolor(inSession ? color.new(color.gray, 95) : na, title="Session Active")
// Highlight the EOD Close window in a subtle orange to see when it flattens
bgcolor((forceEodClose and inEodWindow) ? color.new(color.orange, 85) : na, title="EOD Close Window")
// Determine which level to plot based on position direction
activeTP = strategy.position_size > 0 ? longTakeProfit : (strategy.position_size < 0 ? shortTakeProfit : na)
activeSL = strategy.position_size > 0 ? longStopPrice : (strategy.position_size < 0 ? shortStopPrice : na)
// Draw visual lines for SL and TP while in a trade
plot(activeTP, color=color.green, style=plot.style_linebr, linewidth=2, title="Active TP Level")
plot(activeSL, color=color.red, style=plot.style_linebr, linewidth=2, title="Active SL Level")
Re: Write Entry Rules So Specific a Stranger Could Follow Them
Posted: Wed Sep 23, 2026 8:57 am
by PTScalper
How the Flatten Window Works
1.) By default, the EOD Close Window is set to the last 15 minutes of the standard market session (1545-1600).
2.) If a trade is currently open when the clock strikes 15:45, the script will immediately execute a market close order, abandoning the Take Profit and Stop Loss limits.
3.) The canTrade condition simultaneously ensures that if an otherwise perfect entry setup occurs at 15:50, the bot will completely ignore it, ensuring you are 100% cash when the closing bell rings.
4.) You will see an orange vertical highlight on the chart exactly when this closure window is active.
Re: Write Entry Rules So Specific a Stranger Could Follow Them
Posted: Wed Sep 23, 2026 8:58 am
by PTScalper
By removing the Take Profit and switching to a Trailing Stop, you are upgrading your system from predicting where the market will stop, to simply riding the trend until it mathematically proves it has reversed.
To do this accurately in Pine Script using percentages, we must write custom logic that tracks the absolute highest price (or lowest, for shorts) reached while the trade is open, and dynamically move the stop loss behind it.
Re: Write Entry Rules So Specific a Stranger Could Follow Them
Posted: Wed Sep 23, 2026 8:59 am
by PTScalper
Here is the updated script. The fixed Take Profit is gone. Instead, the strategy sets an initial 1% Stop Loss, and then strictly trails the price by 1.5% as it moves in your favor.
Code: Select all
//@version=5
strategy("The Complete Stranger Rule - Trailing Stop", overlay=true, initial_capital=1000, default_qty_type=strategy.percent_of_equity, default_qty_value=10)
// ==========================================
// 1. SETTINGS INPUTS (Adjustable)
// ==========================================
slPercent = input.float(1.0, title="Initial Stop Loss (%)", step=0.1, group="Risk Management") / 100
trailPercent = input.float(1.5, title="Trailing Distance (%)", step=0.1, group="Risk Management") / 100
// Session Time Inputs
tradeSession = input.session("0930-1600", title="Trading Session", group="Time Filters")
timeZone = input.string("America/New_York", title="Time Zone", group="Time Filters")
forceEodClose = input.bool(true, title="Force End of Day Close?", group="Time Filters")
eodCloseTime = input.session("1545-1600", title="EOD Close Window", group="Time Filters")
// ==========================================
// 2. DEFINE THE TIME FILTER
// ==========================================
inSession = not na(time(timeframe.period, tradeSession, timeZone))
inEodWindow = not na(time(timeframe.period, eodCloseTime, timeZone))
canTrade = inSession and not (forceEodClose and inEodWindow)
// ==========================================
// 3. DEFINE THE INDICATORS
// ==========================================
ema20 = ta.ema(close, 20)
rsiValue = ta.rsi(close, 14)
volSma20 = ta.sma(volume, 20)
// ==========================================
// 4. DEFINE THE EXACT ENTRY RULES
// ==========================================
enterLong = (close > ema20) and (rsiValue > 50) and (volume > volSma20) and canTrade
enterShort = (close < ema20) and (rsiValue < 50) and (volume > volSma20) and canTrade
// ==========================================
// 5. EXECUTE TRADES & MANAGE TRAILING STOP
// ==========================================
// We use a 'var' float to remember the stop price continuously across multiple candles
var float stopLevel = na
// Reset the stop level completely when we are not in a trade
if (strategy.position_size == 0)
stopLevel := na
// Enter Long & Set Initial Hard Stop
if (enterLong and strategy.position_size == 0)
strategy.entry("Long", strategy.long)
stopLevel := close * (1 - slPercent)
strategy.exit("Exit Long", from_entry="Long", stop=stopLevel)
// Enter Short & Set Initial Hard Stop
if (enterShort and strategy.position_size == 0)
strategy.entry("Short", strategy.short)
stopLevel := close * (1 + slPercent)
strategy.exit("Exit Short", from_entry="Short", stop=stopLevel)
// Dynamically Trail the Long Stop
if (strategy.position_size > 0)
// Calculate where the trailing stop should be based on the current candle's high
newTrailLevel = high * (1 - trailPercent)
// math.max ensures the stopLevel can ONLY move up, never down
stopLevel := math.max(stopLevel, newTrailLevel)
strategy.exit("Exit Long", from_entry="Long", stop=stopLevel)
// Dynamically Trail the Short Stop
if (strategy.position_size < 0)
// Calculate where the trailing stop should be based on the current candle's low
newTrailLevel = low * (1 + trailPercent)
// math.min ensures the stopLevel can ONLY move down, never up
stopLevel := math.min(stopLevel, newTrailLevel)
strategy.exit("Exit Short", from_entry="Short", stop=stopLevel)
// Force Close at End of Day (overrides trailing stops)
if (forceEodClose and inEodWindow)
strategy.close("Long", comment="EOD Close")
strategy.close("Short", comment="EOD Close")
// ==========================================
// 6. CHART VISUALS
// ==========================================
plot(ema20, color=color.blue, title="20 EMA", linewidth=2)
bgcolor(enterLong ? color.new(color.green, 85) : na, title="Long Entry Met")
bgcolor(enterShort ? color.new(color.red, 85) : na, title="Short Entry Met")
bgcolor(inSession ? color.new(color.gray, 95) : na, title="Session Active")
bgcolor((forceEodClose and inEodWindow) ? color.new(color.orange, 85) : na, title="EOD Close Window")
// Draw a bold fuchsia line tracking your Trailing Stop exactly as it moves
plot(strategy.position_size != 0 ? stopLevel : na, color=color.fuchsia, style=plot.style_linebr, linewidth=2, title="Trailing Stop Level")
Re: Write Entry Rules So Specific a Stranger Could Follow Them
Posted: Wed Sep 23, 2026 8:59 am
by PTScalper
How the Ratchet Math Works
The secret to a proper trailing stop is that it behaves like a ratchet—it can tighten, but it can never loosen.
Look at the Long management section: stopLevel := math.max(stopLevel, newTrailLevel).
Every 5 minutes, the script calculates a new theoretical stop based on that candle's absolute high.
The math.max function compares the current stop level to the new theoretical stop level, and strictly assigns whichever number is higher. If price pulls back, the current stop stays locked in place.
You will now see a single fuchsia line on the chart whenever you enter a trade. It will start at your 1% risk level, and mechanically step behind the price as the trend runs.
Re: Write Entry Rules So Specific a Stranger Could Follow Them
Posted: Wed Sep 23, 2026 8:59 am
by PTScalper
This is the holy grail of professional risk management. Fixed position sizing (like "buy 10 shares" or "use 10% of my account") is dangerous because a 5% stop loss hurts you five times more than a 1% stop loss.
By using Fixed Fractional Position Sizing, the algorithm mathematically adjusts the number of shares it buys on every single trade based on your exact stop loss distance. Whether the stop loss is 1% away or 5% away, if it gets hit, you will only ever lose exactly 1% of your total account equity.
Re: Write Entry Rules So Specific a Stranger Could Follow Them
Posted: Wed Sep 23, 2026 9:00 am
by PTScalper
Here is the fully professional-grade system. Notice that default_qty_type has been completely removed from the strategy declaration, and a new dynamic math calculation drives the qty parameter on your entries.
Code: Select all
//@version=5
strategy("The Complete Stranger Rule - Pro Sizing", overlay=true, initial_capital=1000)
// ==========================================
// 1. SETTINGS INPUTS
// ==========================================
accountRisk = input.float(1.0, title="Account Risk Per Trade (%)", step=0.1, group="Risk Management") / 100
slPercent = input.float(1.0, title="Initial Stop Loss Distance (%)", step=0.1, group="Risk Management") / 100
trailPercent = input.float(1.5, title="Trailing Distance (%)", step=0.1, group="Risk Management") / 100
// Session Time Inputs
tradeSession = input.session("0930-1600", title="Trading Session", group="Time Filters")
timeZone = input.string("America/New_York", title="Time Zone", group="Time Filters")
forceEodClose = input.bool(true, title="Force End of Day Close?", group="Time Filters")
eodCloseTime = input.session("1545-1600", title="EOD Close Window", group="Time Filters")
// ==========================================
// 2. DEFINE THE TIME FILTER
// ==========================================
inSession = not na(time(timeframe.period, tradeSession, timeZone))
inEodWindow = not na(time(timeframe.period, eodCloseTime, timeZone))
canTrade = inSession and not (forceEodClose and inEodWindow)
// ==========================================
// 3. DEFINE THE INDICATORS
// ==========================================
ema20 = ta.ema(close, 20)
rsiValue = ta.rsi(close, 14)
volSma20 = ta.sma(volume, 20)
// ==========================================
// 4. DEFINE THE EXACT ENTRY RULES
// ==========================================
enterLong = (close > ema20) and (rsiValue > 50) and (volume > volSma20) and canTrade
enterShort = (close < ema20) and (rsiValue < 50) and (volume > volSma20) and canTrade
// ==========================================
// 5. CALCULATE DYNAMIC POSITION SIZING
// ==========================================
// 1. How much money are we willing to lose? (e.g., $1000 * 1% = $10)
riskAmount = strategy.equity * accountRisk
// 2. How much do we lose per 1 share/unit if the stop is hit? (e.g., $100 price * 1% SL = $1 risk per share)
riskPerUnit = close * slPercent
// 3. How many shares can we buy? (e.g., $10 / $1 = 10 shares)
// We use an 'if' check to avoid division by zero errors
tradeQty = riskPerUnit > 0 ? (riskAmount / riskPerUnit) : 0
// ==========================================
// 6. EXECUTE TRADES & MANAGE TRAILING STOP
// ==========================================
var float stopLevel = na
if (strategy.position_size == 0)
stopLevel := na
// Enter Long using dynamic quantity
if (enterLong and strategy.position_size == 0)
strategy.entry("Long", strategy.long, qty=tradeQty)
stopLevel := close * (1 - slPercent)
strategy.exit("Exit Long", from_entry="Long", stop=stopLevel)
// Enter Short using dynamic quantity
if (enterShort and strategy.position_size == 0)
strategy.entry("Short", strategy.short, qty=tradeQty)
stopLevel := close * (1 + slPercent)
strategy.exit("Exit Short", from_entry="Short", stop=stopLevel)
// Dynamically Trail the Long Stop
if (strategy.position_size > 0)
newTrailLevel = high * (1 - trailPercent)
stopLevel := math.max(stopLevel, newTrailLevel)
strategy.exit("Exit Long", from_entry="Long", stop=stopLevel)
// Dynamically Trail the Short Stop
if (strategy.position_size < 0)
newTrailLevel = low * (1 + trailPercent)
stopLevel := math.min(stopLevel, newTrailLevel)
strategy.exit("Exit Short", from_entry="Short", stop=stopLevel)
// Force Close at End of Day
if (forceEodClose and inEodWindow)
strategy.close("Long", comment="EOD Close")
strategy.close("Short", comment="EOD Close")
// ==========================================
// 7. CHART VISUALS
// ==========================================
plot(ema20, color=color.blue, title="20 EMA", linewidth=2)
bgcolor(enterLong ? color.new(color.green, 85) : na, title="Long Entry Met")
bgcolor(enterShort ? color.new(color.red, 85) : na, title="Short Entry Met")
bgcolor(inSession ? color.new(color.gray, 95) : na, title="Session Active")
bgcolor((forceEodClose and inEodWindow) ? color.new(color.orange, 85) : na, title="EOD Close Window")
plot(strategy.position_size != 0 ? stopLevel : na, color=color.fuchsia, style=plot.style_linebr, linewidth=2, title="Trailing Stop Level")
Re: Write Entry Rules So Specific a Stranger Could Follow Them
Posted: Wed Sep 23, 2026 9:00 am
by PTScalper
Note on Leverage and Backtesting
Because this system strictly dictates position size based on risk rather than capital, you may run into a situation where the script calculates a position size that exceeds 100% of your account balance.
Example: If you risk 1% of your account, but your Stop Loss is incredibly tight (only 0.5% away), the script will correctly calculate that you need to buy a position worth 200% of your equity to reach that $10 risk threshold.
If you see trades suddenly being rejected or skipped in the Strategy Tester, open the TradingView settings for the script, go to the Properties tab, and increase the Margin Long/Short allowances so the backtester doesn't block the leveraged trades.