A trend continuation strategy that filters setups with ADX, rate of change, smoothed balance of power, an ATR expansion band, EMA 20 and 50 alignment and DI alignment.
// This Pine Script® code is subject to the terms of the
// Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
//
//@version=6
strategy(
title = "LMSE-Lite Trend Continuation Risk Engine — Fixed",
shorttitle = "LMSELite FIX",
overlay = true,
pyramiding = 0,
process_orders_on_close = true,
calc_on_every_tick = true,
calc_on_order_fills = true,
initial_capital = 50000,
default_qty_type = strategy.fixed,
default_qty_value = 1,
commission_type = strategy.commission.percent,
commission_value = 0.02,
slippage = 1,
max_labels_count = 200)
// ═══════════════════════════════════════════════════════════════════
// INPUT GROUPS
// ═══════════════════════════════════════════════════════════════════
const string GRP_SIGNAL = "01 — Signal Filters"
const string GRP_TIMING = "02 — Entry Timing"
const string GRP_FREQ = "03 — Trade Frequency"
const string GRP_SESSION = "04 — Trading Session"
const string GRP_SIZE = "05 — Position Sizing"
const string GRP_RISK = "06 — Risk Management"
const string GRP_TRAIL = "07 — Trailing Stop"
const string GRP_VISUAL = "08 — Visuals"
const string GRP_ALERTS = "09 — Alerts"
// ═══════════════════════════════════════════════════════════════════
// SIGNAL INPUTS
// ═══════════════════════════════════════════════════════════════════
int adxLen = input.int(
14,
"ADX Length",
minval = 2,
group = GRP_SIGNAL)
float adxMin = input.float(
20.0,
"ADX Minimum",
minval = 1.0,
step = 0.5,
group = GRP_SIGNAL)
int rocLen = input.int(
14,
"ROC Length",
minval = 2,
group = GRP_SIGNAL)
int bopLen = input.int(
21,
"BOP Smoothing",
minval = 2,
group = GRP_SIGNAL)
int atrLen = input.int(
14,
"ATR Length",
minval = 2,
group = GRP_SIGNAL)
int atrBaseLen = input.int(
50,
"ATR Baseline",
minval = 10,
group = GRP_SIGNAL)
float atrFactor = input.float(
0.80,
"Minimum ATR Expansion",
minval = 0.10,
step = 0.05,
group = GRP_SIGNAL)
float atrMaxFactor = input.float(
2.00,
"Maximum ATR Expansion",
minval = 0.50,
step = 0.05,
group = GRP_SIGNAL)
float minDQStrength = input.float(
0.25,
"Minimum DQ Strength",
minval = 0.0,
maxval = 1.0,
step = 0.05,
group = GRP_SIGNAL)
bool requireEMAAlignment = input.bool(
true,
"Require EMA 20 / EMA 50 Alignment",
group = GRP_SIGNAL)
bool requireDIAlignment = input.bool(
true,
"Require DI Alignment",
group = GRP_SIGNAL)
bool requirePriceEMA = input.bool(
true,
"Require Price Beyond EMA 20",
group = GRP_SIGNAL)
bool blockHighFailure = input.bool(
false,
"Block High-Failure Setups",
group = GRP_SIGNAL)
float pFailCap = input.float(
0.45,
"Failure Probability Cap",
minval = 0.0,
maxval = 1.0,
step = 0.05,
group = GRP_SIGNAL)
// ═══════════════════════════════════════════════════════════════════
// ENTRY TIMING INPUTS
// ═══════════════════════════════════════════════════════════════════
string entryTriggerMode = input.string(
"Pullback / Reclaim",
"Entry Trigger",
options = [
"EMA Cross",
"Pullback / Reclaim",
"Breakout",
"Cross Or Pullback",
"Pullback Or Breakout",
"Any",
"Liquidity Sweep"
],
group = GRP_TIMING)
int setupConfirmBars = input.int(
1,
"Setup Confirmation Bars",
minval = 1,
maxval = 10,
group = GRP_TIMING)
int maximumEntryDelayBars = input.int(
0,
"Maximum Entry Delay — Bars",
minval = 0,
maxval = 3,
tooltip = "0 requires entry on the first valid trigger bar. 1 allows only the next bar.",
group = GRP_TIMING)
bool requireFreshDelayedTrigger = input.bool(
true,
"Require Fresh Trigger On Delayed Entry",
tooltip = "A delayed entry must produce a new breakout or reclaim instead of entering passively.",
group = GRP_TIMING)
float maxEntryExtensionATR = input.float(
1.00,
"Maximum Entry Extension — ATR",
minval = 0.10,
maxval = 5.0,
step = 0.05,
tooltip = "Rejects entries too far from EMA 20.",
group = GRP_TIMING)
float pullbackToleranceATR = input.float(
0.25,
"Pullback EMA Tolerance — ATR",
minval = 0.0,
maxval = 2.0,
step = 0.05,
group = GRP_TIMING)
int breakoutLookback = input.int(
5,
"Breakout Lookback",
minval = 1,
maxval = 50,
group = GRP_TIMING)
// --- Liquidity Sweep entry (Entry Trigger = "Liquidity Sweep") ---
// Ported from the "Liquidity Entry Zones [trade_w_samet]" indicator.
// Reuses the ATR / EMA 20 / EMA 50 already computed below — no separate
// length inputs are needed. "No counter-trend" is enforced at
// confirmation time using LMSE-Lite's own Directional Quality regime
// (dq / dqStrength) plus the local EMA stack — see the LIQUIDITY SWEEP
// ENTRY ENGINE section for the full mechanism.
int sweepPivotLength = input.int(
5,
"Sweep: Swing Pivot Length",
minval = 1,
group = GRP_TIMING)
int sweepStoredLevels = input.int(
20,
"Sweep: Stored Liquidity Levels",
minval = 5,
maxval = 100,
group = GRP_TIMING)
float sweepMinDistanceAtr = input.float(
0.10,
"Sweep: Minimum Sweep Distance / ATR",
minval = 0.01,
step = 0.01,
group = GRP_TIMING)
string sweepReclaimRule = input.string(
"Close Back Inside",
"Sweep: Reclaim Rule",
options = [
"Close Back Inside",
"Strong Reclaim"
],
group = GRP_TIMING)
float sweepMinWickPercent = input.float(
0.35,
"Sweep: Minimum Wick %",
minval = 0.0,
maxval = 1.0,
step = 0.01,
group = GRP_TIMING)
float sweepMaxBodyPercent = input.float(
0.65,
"Sweep: Maximum Body %",
minval = 0.05,
maxval = 1.0,
step = 0.01,
group = GRP_TIMING)
float sweepMinRangeAtr = input.float(
0.20,
"Sweep: Minimum Candle Range / ATR",
minval = 0.01,
step = 0.01,
group = GRP_TIMING)
bool sweepRequireBullishBody = input.bool(
true,
"Sweep: Long Confirmation Must Be Bullish",
group = GRP_TIMING)
bool sweepRequireBearishBody = input.bool(
true,
"Sweep: Short Confirmation Must Be Bearish",
group = GRP_TIMING)
int sweepConfirmationWindow = input.int(
2,
"Sweep: Max Bars After Sweep For Confirmation",
minval = 0,
maxval = 10,
group = GRP_TIMING)
bool sweepRequireMidlineBreak = input.bool(
true,
"Sweep: Require Sweep Candle Midline Break",
group = GRP_TIMING)
int sweepSignalSpacingBars = input.int(
10,
"Sweep: Minimum Bars Between Sweep Signals",
minval = 0,
group = GRP_TIMING)
// ═══════════════════════════════════════════════════════════════════
// FREQUENCY INPUTS
// ═══════════════════════════════════════════════════════════════════
int cooldownBars = input.int(
20,
"Cooldown Bars After Trade Closes",
minval = 0,
maxval = 200,
group = GRP_FREQ)
int maxTradesPerDay = input.int(
2,
"Maximum Trades Per NY Day",
minval = 1,
maxval = 20,
group = GRP_FREQ)
bool requireSetupReset = input.bool(
true,
"Require Setup Reset Before Re-entry",
group = GRP_FREQ)
// ═══════════════════════════════════════════════════════════════════
// SESSION INPUTS
// ═══════════════════════════════════════════════════════════════════
string tradeSession = input.session(
"0935-1555",
"Entry Session",
tooltip = "New York time.",
group = GRP_SESSION)
string sessionTimezone = input.string(
"America/New_York",
"Session Timezone",
group = GRP_SESSION)
bool closeAtSessionEnd = input.bool(
true,
"Close Position At Session End",
group = GRP_SESSION)
// ═══════════════════════════════════════════════════════════════════
// POSITION SIZING
// ═══════════════════════════════════════════════════════════════════
float baseQty = input.float(
1.0,
"Base Contracts",
minval = 1.0,
step = 1.0,
group = GRP_SIZE)
bool allowLong = input.bool(
true,
"Allow Longs",
group = GRP_SIZE)
bool allowShort = input.bool(
true,
"Allow Shorts",
group = GRP_SIZE)
string sizingMode = input.string(
"Fixed",
"Sizing Mode",
options = [
"Fixed",
"DQ Linear",
"DQ Piecewise",
"Risk %",
"Risk $"
],
group = GRP_SIZE)
float minMult = input.float(
0.25,
"Minimum DQ Multiplier",
minval = 0.05,
step = 0.05,
group = GRP_SIZE)
float maxMult = input.float(
1.50,
"Maximum DQ Multiplier",
minval = 0.25,
step = 0.05,
group = GRP_SIZE)
float riskPerTradePct = input.float(
0.50,
"Risk Per Trade %",
minval = 0.05,
maxval = 10.0,
step = 0.05,
group = GRP_SIZE)
float maxRiskDollars = input.float(
500.0,
"Maximum Risk $",
minval = 1.0,
step = 25.0,
group = GRP_SIZE)
// ═══════════════════════════════════════════════════════════════════
// RISK MANAGEMENT
// ═══════════════════════════════════════════════════════════════════
float stopATR = input.float(
1.25,
"ATR Stop",
minval = 0.1,
step = 0.1,
group = GRP_RISK)
float highFailureStopMultiplier = input.float(
0.70,
"High-Failure Stop Multiplier",
minval = 0.10,
maxval = 1.0,
step = 0.05,
group = GRP_RISK)
float tp1R = input.float(
1.0,
"TP1 Reward / Risk",
minval = 0.25,
step = 0.25,
group = GRP_RISK)
float tp2R = input.float(
3.0,
"TP2 Reward / Risk",
minval = 0.50,
step = 0.25,
group = GRP_RISK)
float tp1Qty = input.float(
50.0,
"TP1 Quantity %",
minval = 1.0,
maxval = 99.0,
step = 1.0,
group = GRP_RISK)
bool useBreakEven = input.bool(
true,
"Move Stop To Break-Even After TP1",
group = GRP_RISK)
int breakEvenOffsetTicks = input.int(
0,
"Break-Even Offset — Ticks",
minval = 0,
maxval = 100,
group = GRP_RISK)
int maximumHoldingBars = input.int(
80,
"Maximum Holding Bars",
minval = 1,
maxval = 1000,
group = GRP_RISK)
// ═══════════════════════════════════════════════════════════════════
// TRAILING STOP
// ═══════════════════════════════════════════════════════════════════
bool useTrail = input.bool(
true,
"Use Persistence Trail After TP1",
group = GRP_TRAIL)
float lowPersistence = input.float(
8.0,
"Low Persistence",
minval = 1.0,
group = GRP_TRAIL)
float highPersistence = input.float(
20.0,
"High Persistence",
minval = 2.0,
group = GRP_TRAIL)
float tightTrailATR = input.float(
1.0,
"Tight Trail ATR",
minval = 0.1,
step = 0.1,
group = GRP_TRAIL)
float baseTrailATR = input.float(
1.5,
"Base Trail ATR",
minval = 0.1,
step = 0.1,
group = GRP_TRAIL)
float looseTrailATR = input.float(
2.0,
"Loose Trail ATR",
minval = 0.1,
step = 0.1,
group = GRP_TRAIL)
// ═══════════════════════════════════════════════════════════════════
// VISUALS
// ═══════════════════════════════════════════════════════════════════
bool showSignals = input.bool(
true,
"Show Entry Signals",
group = GRP_VISUAL)
bool showSetupMarkers = input.bool(
false,
"Show Raw Setup Markers",
group = GRP_VISUAL)
bool showSweepMarkers = input.bool(
true,
"Show Raw Sweep Markers",
group = GRP_VISUAL)
bool showTradeLevels = input.bool(
true,
"Show Active Trade Levels",
group = GRP_VISUAL)
bool showDashboard = input.bool(
true,
"Show Dashboard",
group = GRP_VISUAL)
string dashPos = input.string(
"Top Right",
"Dashboard Position",
options = [
"Top Right",
"Top Left",
"Bottom Right",
"Bottom Left"
],
group = GRP_VISUAL)
string dashFont = input.string(
"Phone",
"Dashboard Font Size",
options = [
"Compact",
"Phone",
"Large"
],
group = GRP_VISUAL)
// ═══════════════════════════════════════════════════════════════════
// ALERTS
// ═══════════════════════════════════════════════════════════════════
bool enableDynamicAlerts = input.bool(
true,
"Enable Dynamic alert() Calls",
group = GRP_ALERTS)
// ═══════════════════════════════════════════════════════════════════
// COLORS
// ═══════════════════════════════════════════════════════════════════
color C_NAVY = color.rgb(8, 16, 31)
color C_CARD = color.rgb(20, 32, 53)
color C_ALT = color.rgb(27, 41, 65)
color C_BLUE = color.rgb(75, 145, 247)
color C_PURPLE = color.rgb(156, 90, 235)
color C_GREEN = color.rgb(34, 197, 94)
color C_ORANGE = color.rgb(245, 158, 11)
color C_RED = color.rgb(239, 68, 68)
color C_GRAY = color.rgb(100, 116, 139)
color C_WHITE = color.rgb(245, 248, 252)
// ═══════════════════════════════════════════════════════════════════
// HELPERS
// ═══════════════════════════════════════════════════════════════════
f_clamp(float value, float minimum, float maximum) =>
math.max(
minimum,
math.min(maximum, value))
f_norm(float value, float minimum, float maximum) =>
f_clamp(
(value - minimum) /
math.max(maximum - minimum, 0.000001),
0.0,
1.0)
f_price(float value) =>
na(value)
? "—"
: str.tostring(value, format.mintick)
f_number(float value) =>
na(value)
? "—"
: str.tostring(value, "#.00")
// ═══════════════════════════════════════════════════════════════════
// INDICATORS
// ═══════════════════════════════════════════════════════════════════
float atr = ta.atr(atrLen)
float atrBase = ta.sma(atr, atrBaseLen)
float atrExpansion =
not na(atrBase) and atrBase > 0.0
? atr / atrBase
: na
[plusDI, minusDI, adx] =
ta.dmi(adxLen, adxLen)
float roc =
ta.roc(close, rocLen)
float candleRange =
math.max(
high - low,
syminfo.mintick)
float bopRaw =
(close - open) /
candleRange
float bop =
ta.ema(bopRaw, bopLen)
float emaFast =
ta.ema(close, 20)
float emaSlow =
ta.ema(close, 50)
bool dataReady =
not na(atrExpansion) and
not na(adx) and
not na(roc) and
not na(bop) and
not na(emaFast) and
not na(emaSlow)
// ═══════════════════════════════════════════════════════════════════
// DIRECTIONAL QUALITY
// ═══════════════════════════════════════════════════════════════════
float trendScore =
f_norm(
adx,
adxMin,
adxMin + 25.0)
float atrScore =
f_norm(
atrExpansion,
atrFactor,
atrFactor + 0.80)
float rocScore =
f_norm(
math.abs(roc),
0.0,
0.60)
float bopScore =
f_norm(
math.abs(bop),
0.0,
0.40)
float emaSeparation =
atr > 0.0
? math.abs(emaFast - emaSlow) / atr
: 0.0
float emaStrength =
f_norm(
emaSeparation,
0.05,
0.50)
float direction =
roc > 0.0 and bop > 0.0
? 1.0
: roc < 0.0 and bop < 0.0
? -1.0
: 0.0
float quality =
0.30 * trendScore +
0.25 * atrScore +
0.20 * rocScore +
0.15 * bopScore +
0.10 * emaStrength
float dq =
f_clamp(
direction * quality,
-1.0,
1.0)
float dqStrength =
math.abs(dq)
// ═══════════════════════════════════════════════════════════════════
// FAILURE AND PERSISTENCE PROXIES
// ═══════════════════════════════════════════════════════════════════
float chopRisk =
adx < adxMin
? 0.35
: 0.0
float weakVolRisk =
atrExpansion < atrFactor
? 0.25
: 0.0
float hotVolRisk =
atrExpansion > atrMaxFactor
? 0.20
: 0.0
float momentumConflict =
(
roc > 0.0 and bop < 0.0
) or (
roc < 0.0 and bop > 0.0
)
? 0.25
: 0.0
float emaConflict =
direction > 0.0 and close < emaFast
? 0.15
: direction < 0.0 and close > emaFast
? 0.15
: 0.0
float weakQualityRisk =
(1.0 - dqStrength) * 0.20
float pFailLite =
f_clamp(
chopRisk +
weakVolRisk +
hotVolRisk +
momentumConflict +
emaConflict +
weakQualityRisk,
0.0,
1.0)
float persistence =
f_clamp(
5.0 +
trendScore * 12.0 +
atrScore * 8.0 -
pFailLite * 8.0,
1.0,
30.0)
// ═══════════════════════════════════════════════════════════════════
// POSITION SIZING
// ═══════════════════════════════════════════════════════════════════
float riskMultiplier =
sizingMode == "Fixed" or
sizingMode == "Risk %" or
sizingMode == "Risk $"
? 1.0
: sizingMode == "DQ Linear"
? f_clamp(
minMult +
dqStrength *
(maxMult - minMult),
minMult,
maxMult)
: dqStrength < 0.15
? 0.25
: dqStrength < 0.25
? 0.50
: dqStrength < 0.40
? 1.00
: dqStrength < 0.60
? 1.25
: 1.50
float dqQty =
math.max(
1.0,
math.round(
baseQty *
riskMultiplier))
float pointValue =
not na(syminfo.pointvalue) and
syminfo.pointvalue > 0.0
? syminfo.pointvalue
: 1.0
bool useDollarSizing =
sizingMode == "Risk %" or
sizingMode == "Risk $"
float riskBudget =
sizingMode == "Risk %"
? strategy.equity *
riskPerTradePct /
100.0
: maxRiskDollars
// ═══════════════════════════════════════════════════════════════════
// SESSION AND DAILY LIMITS
// ═══════════════════════════════════════════════════════════════════
bool inTradeSession =
not na(
time(
timeframe.period,
tradeSession,
sessionTimezone))
bool sessionEndBar =
not inTradeSession and
inTradeSession[1]
int dayIdentifier =
year(time, sessionTimezone) * 10000 +
month(time, sessionTimezone) * 100 +
dayofmonth(time, sessionTimezone)
bool newTradingDay =
barstate.isfirst or
dayIdentifier != dayIdentifier[1]
var int tradesToday = 0
if newTradingDay
tradesToday := 0
bool dailyTradeLimitPass =
tradesToday < maxTradesPerDay
// ═══════════════════════════════════════════════════════════════════
// COOLDOWN
// ═══════════════════════════════════════════════════════════════════
var int lastClosedTradeBar = na
int barsSinceClosedTrade =
na(lastClosedTradeBar)
? 1000000
: bar_index -
lastClosedTradeBar
bool cooldownPass =
barsSinceClosedTrade >= cooldownBars
int cooldownRemaining =
cooldownPass
? 0
: math.max(
cooldownBars -
barsSinceClosedTrade,
0)
// ═══════════════════════════════════════════════════════════════════
// SETUP CONDITIONS
// ═══════════════════════════════════════════════════════════════════
bool trendRegimePass =
dataReady and
adx >= adxMin and
atrExpansion >= atrFactor and
atrExpansion <= atrMaxFactor
bool longEMAAligned =
not requireEMAAlignment or
emaFast > emaSlow
bool shortEMAAligned =
not requireEMAAlignment or
emaFast < emaSlow
bool longDIAligned =
not requireDIAlignment or
plusDI > minusDI
bool shortDIAligned =
not requireDIAlignment or
minusDI > plusDI
bool longPriceAligned =
not requirePriceEMA or
close > emaFast
bool shortPriceAligned =
not requirePriceEMA or
close < emaFast
bool failurePass =
not blockHighFailure or
pFailLite <= pFailCap
bool commonSetupPass =
inTradeSession and
dailyTradeLimitPass and
cooldownPass and
trendRegimePass and
failurePass
bool longSetupState =
allowLong and
commonSetupPass and
roc > 0.0 and
bop > 0.0 and
dq > 0.0 and
dqStrength >= minDQStrength and
longEMAAligned and
longDIAligned and
longPriceAligned
bool shortSetupState =
allowShort and
commonSetupPass and
roc < 0.0 and
bop < 0.0 and
dq < 0.0 and
dqStrength >= minDQStrength and
shortEMAAligned and
shortDIAligned and
shortPriceAligned
// ═══════════════════════════════════════════════════════════════════
// SETUP CONFIRMATION AND LATCHING
// ═══════════════════════════════════════════════════════════════════
var int longSetupCount = 0
var int shortSetupCount = 0
var bool longSetupLatched = false
var bool shortSetupLatched = false
var int longSetupReadyBar = na
var int shortSetupReadyBar = na
if barstate.isconfirmed
longSetupCount :=
longSetupState
? longSetupCount + 1
: 0
shortSetupCount :=
shortSetupState
? shortSetupCount + 1
: 0
bool newLongSetupReady =
longSetupCount >= setupConfirmBars and
longSetupCount[1] < setupConfirmBars
bool newShortSetupReady =
shortSetupCount >= setupConfirmBars and
shortSetupCount[1] < setupConfirmBars
if newLongSetupReady
longSetupLatched := true
longSetupReadyBar := bar_index
if newShortSetupReady
shortSetupLatched := true
shortSetupReadyBar := bar_index
if not longSetupState
longSetupLatched := false
longSetupReadyBar := na
if not shortSetupState
shortSetupLatched := false
shortSetupReadyBar := na
int longSetupAge =
longSetupLatched and
not na(longSetupReadyBar)
? bar_index -
longSetupReadyBar
: -1
int shortSetupAge =
shortSetupLatched and
not na(shortSetupReadyBar)
? bar_index -
shortSetupReadyBar
: -1
bool longEntryWindowOpen =
longSetupLatched and
longSetupAge >= 0 and
longSetupAge <= maximumEntryDelayBars
bool shortEntryWindowOpen =
shortSetupLatched and
shortSetupAge >= 0 and
shortSetupAge <= maximumEntryDelayBars
// ═══════════════════════════════════════════════════════════════════
// INDEPENDENT RE-ARMING
// ═══════════════════════════════════════════════════════════════════
var bool longArmed = true
var bool shortArmed = true
if not longSetupState
longArmed := true
if not shortSetupState
shortArmed := true
// ═══════════════════════════════════════════════════════════════════
// ENTRY TRIGGERS
// ═══════════════════════════════════════════════════════════════════
float emaExtensionATR =
atr > 0.0
? (close - emaFast) / atr
: na
bool longExtensionPass =
not na(emaExtensionATR) and
emaExtensionATR >= 0.0 and
emaExtensionATR <= maxEntryExtensionATR
bool shortExtensionPass =
not na(emaExtensionATR) and
emaExtensionATR <= 0.0 and
-emaExtensionATR <= maxEntryExtensionATR
bool longEMACross =
ta.crossover(
emaFast,
emaSlow) and
close > emaFast
bool shortEMACross =
ta.crossunder(
emaFast,
emaSlow) and
close < emaFast
bool longPullbackReclaim =
low <=
emaFast +
atr * pullbackToleranceATR and
close > emaFast and
close > open and
close > close[1]
bool shortPullbackReclaim =
high >=
emaFast -
atr * pullbackToleranceATR and
close < emaFast and
close < open and
close < close[1]
float priorBreakoutHigh =
ta.highest(
high[1],
breakoutLookback)
float priorBreakoutLow =
ta.lowest(
low[1],
breakoutLookback)
bool longBreakout =
close > priorBreakoutHigh and
close > open
bool shortBreakout =
close < priorBreakoutLow and
close < open
bool longSelectedTrigger =
entryTriggerMode == "EMA Cross"
? longEMACross
: entryTriggerMode == "Pullback / Reclaim"
? longPullbackReclaim
: entryTriggerMode == "Breakout"
? longBreakout
: entryTriggerMode == "Cross Or Pullback"
? longEMACross or
longPullbackReclaim
: entryTriggerMode == "Pullback Or Breakout"
? longPullbackReclaim or
longBreakout
: longEMACross or
longPullbackReclaim or
longBreakout
bool shortSelectedTrigger =
entryTriggerMode == "EMA Cross"
? shortEMACross
: entryTriggerMode == "Pullback / Reclaim"
? shortPullbackReclaim
: entryTriggerMode == "Breakout"
? shortBreakout
: entryTriggerMode == "Cross Or Pullback"
? shortEMACross or
shortPullbackReclaim
: entryTriggerMode == "Pullback Or Breakout"
? shortPullbackReclaim or
shortBreakout
: shortEMACross or
shortPullbackReclaim or
shortBreakout
// EMA Cross mode is evaluated directly because waiting for a setup
// counter after the cross can make the signal late.
bool directLongCrossSetup =
allowLong and
commonSetupPass and
longEMAAligned and
longDIAligned and
longPriceAligned and
longEMACross
bool directShortCrossSetup =
allowShort and
commonSetupPass and
shortEMAAligned and
shortDIAligned and
shortPriceAligned and
shortEMACross
// ═══════════════════════════════════════════════════════════════════
// LIQUIDITY SWEEP ENTRY ENGINE
// ═══════════════════════════════════════════════════════════════════
// Ported from the "Liquidity Entry Zones [trade_w_samet]" indicator.
// Reuses the ATR / EMA 20 / EMA 50 already computed in the INDICATORS
// section above — no separate sweep-specific lengths are needed. This
// section always runs regardless of entryTriggerMode (cheap: a handful
// of pivots and a bounded array scan), matching how the other trigger
// types above are also always computed.
//
// "No counter-trend" is enforced entirely inside sweepBuyConfirmed /
// sweepSellConfirmed below: a sweep can only confirm once BOTH the
// local EMA 20 / EMA 50 stack AND LMSE-Lite's own Directional Quality
// regime (dq / dqStrength) already agree with the sweep's direction.
// Raw sweep detection (validBuySweep / validSellSweep) stays
// trend-agnostic, exactly like the source indicator — the trend gate
// is applied only at confirmation.
// ═══════════════════════════════════════════════════════════════════
float sweepCandleRange = high - low
float sweepCandleBody = math.abs(close - open)
float sweepUpperWick = high - math.max(open, close)
float sweepLowerWick = math.min(open, close) - low
float sweepBodyPercent = sweepCandleRange > 0 ? sweepCandleBody / sweepCandleRange : 0.0
float sweepUpperWickPercent = sweepCandleRange > 0 ? sweepUpperWick / sweepCandleRange : 0.0
float sweepLowerWickPercent = sweepCandleRange > 0 ? sweepLowerWick / sweepCandleRange : 0.0
float sweepMinDistancePx = atr > 0.0 ? sweepMinDistanceAtr * atr : na
float sweepMinRangePx = atr > 0.0 ? sweepMinRangeAtr * atr : na
float sweepPivotHigh = ta.pivothigh(high, sweepPivotLength, sweepPivotLength)
float sweepPivotLow = ta.pivotlow(low, sweepPivotLength, sweepPivotLength)
var float[] sweepStoredHighLevels = array.new_float()
var int[] sweepStoredHighBars = array.new_int()
var float[] sweepStoredLowLevels = array.new_float()
var int[] sweepStoredLowBars = array.new_int()
if not na(sweepPivotHigh)
array.push(sweepStoredHighLevels, sweepPivotHigh)
array.push(sweepStoredHighBars, bar_index - sweepPivotLength)
if array.size(sweepStoredHighLevels) > sweepStoredLevels
array.shift(sweepStoredHighLevels)
array.shift(sweepStoredHighBars)
if not na(sweepPivotLow)
array.push(sweepStoredLowLevels, sweepPivotLow)
array.push(sweepStoredLowBars, bar_index - sweepPivotLength)
if array.size(sweepStoredLowLevels) > sweepStoredLevels
array.shift(sweepStoredLowLevels)
array.shift(sweepStoredLowBars)
float sweptHighLevel = na
int sweptHighBar = na
float sweptLowLevel = na
int sweptLowBar = na
int sweepHighLevelCount = array.size(sweepStoredHighLevels)
if sweepHighLevelCount > 0
for i = sweepHighLevelCount - 1 to 0
float highLevel = array.get(sweepStoredHighLevels, i)
int highBar = array.get(sweepStoredHighBars, i)
if highBar < bar_index and high > highLevel and not na(sweepMinDistancePx) and (high - highLevel) >= sweepMinDistancePx
sweptHighLevel := highLevel
sweptHighBar := highBar
break
int sweepLowLevelCount = array.size(sweepStoredLowLevels)
if sweepLowLevelCount > 0
for i = sweepLowLevelCount - 1 to 0
float lowLevel = array.get(sweepStoredLowLevels, i)
int lowBar = array.get(sweepStoredLowBars, i)
if lowBar < bar_index and low < lowLevel and not na(sweepMinDistancePx) and (lowLevel - low) >= sweepMinDistancePx
sweptLowLevel := lowLevel
sweptLowBar := lowBar
break
bool sweepBearishReclaim =
not na(sweptHighLevel) and
(
sweepReclaimRule == "Close Back Inside" ?
close < sweptHighLevel :
close < sweptHighLevel and close < (high + low) / 2.0
)
bool sweepBullishReclaim =
not na(sweptLowLevel) and
(
sweepReclaimRule == "Close Back Inside" ?
close > sweptLowLevel :
close > sweptLowLevel and close > (high + low) / 2.0
)
bool validSellSweep =
not na(sweptHighLevel) and
sweepBearishReclaim and
sweepUpperWickPercent >= sweepMinWickPercent and
sweepBodyPercent <= sweepMaxBodyPercent and
not na(sweepMinRangePx) and
sweepCandleRange >= sweepMinRangePx
bool validBuySweep =
not na(sweptLowLevel) and
sweepBullishReclaim and
sweepLowerWickPercent >= sweepMinWickPercent and
sweepBodyPercent <= sweepMaxBodyPercent and
not na(sweepMinRangePx) and
sweepCandleRange >= sweepMinRangePx
var int sweepPendingBullBar = na
var float sweepPendingBullMid = na
var int sweepPendingBearBar = na
var float sweepPendingBearMid = na
if validBuySweep
sweepPendingBullBar := bar_index
sweepPendingBullMid := (high + low) / 2.0
if validSellSweep
sweepPendingBearBar := bar_index
sweepPendingBearMid := (high + low) / 2.0
bool sweepBullWindowOpen = not na(sweepPendingBullBar) and (bar_index - sweepPendingBullBar <= sweepConfirmationWindow)
bool sweepBearWindowOpen = not na(sweepPendingBearBar) and (bar_index - sweepPendingBearBar <= sweepConfirmationWindow)
// "No counter-trend" gate: local EMA 20 / EMA 50 stack.
bool sweepLocalLongOk = close > emaFast and close > emaSlow
bool sweepLocalShortOk = close < emaFast and close < emaSlow
// "No counter-trend" gate: LMSE-Lite's own Directional Quality regime.
bool sweepMacroLongOk = dq > 0.0 and dqStrength >= minDQStrength
bool sweepMacroShortOk = dq < 0.0 and dqStrength >= minDQStrength
bool sweepBullBodyOk = not sweepRequireBullishBody or close > open
bool sweepBearBodyOk = not sweepRequireBearishBody or close < open
bool sweepBullMidOk = not sweepRequireMidlineBreak or close > sweepPendingBullMid
bool sweepBearMidOk = not sweepRequireMidlineBreak or close < sweepPendingBearMid
bool sweepBuyConfirmed =
sweepBullWindowOpen and
sweepBullBodyOk and
sweepLocalLongOk and
sweepMacroLongOk and
sweepBullMidOk
bool sweepSellConfirmed =
sweepBearWindowOpen and
sweepBearBodyOk and
sweepLocalShortOk and
sweepMacroShortOk and
sweepBearMidOk
var int sweepLastSignalBar = na
bool sweepSpacingOK = na(sweepLastSignalBar) or (bar_index - sweepLastSignalBar > sweepSignalSpacingBars)
bool sweepBuySignal = sweepBuyConfirmed and sweepSpacingOK
bool sweepSellSignal = sweepSellConfirmed and sweepSpacingOK and not sweepBuySignal
if sweepBuySignal or sweepSellSignal
sweepLastSignalBar := bar_index
if sweepBuySignal or (not na(sweepPendingBullBar) and bar_index - sweepPendingBullBar > sweepConfirmationWindow)
sweepPendingBullBar := na
sweepPendingBullMid := na
if sweepSellSignal or (not na(sweepPendingBearBar) and bar_index - sweepPendingBearBar > sweepConfirmationWindow)
sweepPendingBearBar := na
sweepPendingBearMid := na
// Liquidity Sweep mode is evaluated directly, the same way EMA Cross
// is above, because the sweep already carries its own time-boxed
// confirmation window (sweepConfirmationWindow) — waiting for a
// separate setup counter on top of that would make an already-timed
// signal late.
bool directLongSweepSetup =
allowLong and
commonSetupPass and
longEMAAligned and
longDIAligned and
longPriceAligned and
sweepBuySignal
bool directShortSweepSetup =
allowShort and
commonSetupPass and
shortEMAAligned and
shortDIAligned and
shortPriceAligned and
sweepSellSignal
bool delayedLongTriggerFresh =
longSetupAge == 0 or
(
longSetupAge == 1 and
(
longPullbackReclaim or
longBreakout
)
)
bool delayedShortTriggerFresh =
shortSetupAge == 0 or
(
shortSetupAge == 1 and
(
shortPullbackReclaim or
shortBreakout
)
)
bool longFreshTriggerPass =
not requireFreshDelayedTrigger or
delayedLongTriggerFresh
bool shortFreshTriggerPass =
not requireFreshDelayedTrigger or
delayedShortTriggerFresh
bool longTriggerQualified =
entryTriggerMode == "EMA Cross"
? directLongCrossSetup
: entryTriggerMode == "Liquidity Sweep"
? directLongSweepSetup
: longEntryWindowOpen and
longSelectedTrigger and
longFreshTriggerPass
bool shortTriggerQualified =
entryTriggerMode == "EMA Cross"
? directShortCrossSetup
: entryTriggerMode == "Liquidity Sweep"
? directShortSweepSetup
: shortEntryWindowOpen and
shortSelectedTrigger and
shortFreshTriggerPass
// ═══════════════════════════════════════════════════════════════════
// CANDIDATE STOPS AND ORDER SIZE
// ═══════════════════════════════════════════════════════════════════
float rawLongStop =
close -
atr * stopATR
float rawShortStop =
close +
atr * stopATR
float adjustedLongStop =
pFailLite > pFailCap
? close -
(close - rawLongStop) *
highFailureStopMultiplier
: rawLongStop
float adjustedShortStop =
pFailLite > pFailCap
? close +
(rawShortStop - close) *
highFailureStopMultiplier
: rawShortStop
float candidateLongRisk =
close -
adjustedLongStop
float candidateShortRisk =
adjustedShortStop -
close
float longRiskQty =
useDollarSizing and
candidateLongRisk > syminfo.mintick
? math.floor(
riskBudget /
(
candidateLongRisk *
pointValue
))
: dqQty
float shortRiskQty =
useDollarSizing and
candidateShortRisk > syminfo.mintick
? math.floor(
riskBudget /
(
candidateShortRisk *
pointValue
))
: dqQty
bool longSizePass =
not useDollarSizing or
longRiskQty >= 1.0
bool shortSizePass =
not useDollarSizing or
shortRiskQty >= 1.0
float longOrderQty =
useDollarSizing
? longRiskQty
: dqQty
float shortOrderQty =
useDollarSizing
? shortRiskQty
: dqQty
// ═══════════════════════════════════════════════════════════════════
// BLOCKER DIAGNOSTICS
// ═══════════════════════════════════════════════════════════════════
string longBlocker =
not allowLong ? "LONGS OFF" :
not inTradeSession ? "SESSION" :
not dailyTradeLimitPass ? "TRADE LIMIT" :
not cooldownPass ? "COOLDOWN" :
not dataReady ? "DATA" :
adx < adxMin ? "ADX LOW" :
atrExpansion < atrFactor ? "ATR LOW" :
atrExpansion > atrMaxFactor ? "ATR HOT" :
roc <= 0.0 ? "ROC" :
bop <= 0.0 ? "BOP" :
dq <= 0.0 ? "DQ DIRECTION" :
dqStrength < minDQStrength ? "DQ WEAK" :
not longEMAAligned ? "EMA ALIGN" :
not longDIAligned ? "DI ALIGN" :
not longPriceAligned ? "PRICE / EMA" :
not failurePass ? "FAIL RISK" :
entryTriggerMode != "EMA Cross" and
entryTriggerMode != "Liquidity Sweep" and
not longEntryWindowOpen ? "NO FRESH SETUP" :
not longTriggerQualified ? "NO TRIGGER" :
not longExtensionPass ? "ENTRY EXTENDED" :
requireSetupReset and
not longArmed ? "REARM" :
not longSizePass ? "SIZE" :
strategy.position_size != 0 ? "POSITION OPEN" :
"CLEAR"
string shortBlocker =
not allowShort ? "SHORTS OFF" :
not inTradeSession ? "SESSION" :
not dailyTradeLimitPass ? "TRADE LIMIT" :
not cooldownPass ? "COOLDOWN" :
not dataReady ? "DATA" :
adx < adxMin ? "ADX LOW" :
atrExpansion < atrFactor ? "ATR LOW" :
atrExpansion > atrMaxFactor ? "ATR HOT" :
roc >= 0.0 ? "ROC" :
bop >= 0.0 ? "BOP" :
dq >= 0.0 ? "DQ DIRECTION" :
dqStrength < minDQStrength ? "DQ WEAK" :
not shortEMAAligned ? "EMA ALIGN" :
not shortDIAligned ? "DI ALIGN" :
not shortPriceAligned ? "PRICE / EMA" :
not failurePass ? "FAIL RISK" :
entryTriggerMode != "EMA Cross" and
entryTriggerMode != "Liquidity Sweep" and
not shortEntryWindowOpen ? "NO FRESH SETUP" :
not shortTriggerQualified ? "NO TRIGGER" :
not shortExtensionPass ? "ENTRY EXTENDED" :
requireSetupReset and
not shortArmed ? "REARM" :
not shortSizePass ? "SIZE" :
strategy.position_size != 0 ? "POSITION OPEN" :
"CLEAR"
// ═══════════════════════════════════════════════════════════════════
// FINAL ENTRY SIGNALS
// ═══════════════════════════════════════════════════════════════════
bool flat =
strategy.position_size == 0
bool longEntry =
barstate.isconfirmed and
flat and
longTriggerQualified and
longExtensionPass and
longSizePass and
(
not requireSetupReset or
longArmed
)
bool shortEntry =
barstate.isconfirmed and
flat and
shortTriggerQualified and
shortExtensionPass and
shortSizePass and
(
not requireSetupReset or
shortArmed
) and
not longEntry
// ═══════════════════════════════════════════════════════════════════
// TRADE STATE
// ═══════════════════════════════════════════════════════════════════
var float pendingStop = na
var float entryPrice = na
var float initialRisk = na
var float longStop = na
var float shortStop = na
var float tp1Price = na
var float tp2Price = na
var bool tp1Hit = false
var bool breakEvenActive = false
var bool trailingActive = false
var float highestSinceEntry = na
var float lowestSinceEntry = na
var int entryBar = na
// ═══════════════════════════════════════════════════════════════════
// ENTRIES
// ═══════════════════════════════════════════════════════════════════
if longEntry
pendingStop := adjustedLongStop
tradesToday += 1
longArmed := false
longSetupLatched := false
longSetupReadyBar := na
strategy.entry(
"Long",
strategy.long,
qty = longOrderQty,
comment = "LMSE Long")
if enableDynamicAlerts
alert(
"🔵 BULLISH — LONG ENTRY\n" +
"BIAS: BULLISH ▲\n" +
syminfo.ticker +
" | " +
timeframe.period +
"\nDQ: " +
str.tostring(dq, "#.00") +
"\nADX: " +
str.tostring(adx, "#.0") +
"\nATR Exp: " +
str.tostring(atrExpansion, "#.00") +
"\nCandidate stop: " +
str.tostring(
adjustedLongStop,
format.mintick),
alert.freq_once_per_bar_close)
if shortEntry
pendingStop := adjustedShortStop
tradesToday += 1
shortArmed := false
shortSetupLatched := false
shortSetupReadyBar := na
strategy.entry(
"Short",
strategy.short,
qty = shortOrderQty,
comment = "LMSE Short")
if enableDynamicAlerts
alert(
"🟣 BEARISH — SHORT ENTRY\n" +
"BIAS: BEARISH ▼\n" +
syminfo.ticker +
" | " +
timeframe.period +
"\nDQ: " +
str.tostring(dq, "#.00") +
"\nADX: " +
str.tostring(adx, "#.0") +
"\nATR Exp: " +
str.tostring(atrExpansion, "#.00") +
"\nCandidate stop: " +
str.tostring(
adjustedShortStop,
format.mintick),
alert.freq_once_per_bar_close)
// ═══════════════════════════════════════════════════════════════════
// FILL DETECTION
// ═══════════════════════════════════════════════════════════════════
bool longFill =
strategy.position_size > 0 and
strategy.position_size[1] <= 0
bool shortFill =
strategy.position_size < 0 and
strategy.position_size[1] >= 0
if longFill
entryPrice :=
strategy.position_avg_price
longStop :=
not na(pendingStop)
? pendingStop
: entryPrice -
atr * stopATR
initialRisk :=
entryPrice -
longStop
tp1Price :=
entryPrice +
initialRisk * tp1R
tp2Price :=
entryPrice +
initialRisk * tp2R
highestSinceEntry := high
lowestSinceEntry := low
entryBar := bar_index
tp1Hit := false
breakEvenActive := false
trailingActive := false
if shortFill
entryPrice :=
strategy.position_avg_price
shortStop :=
not na(pendingStop)
? pendingStop
: entryPrice +
atr * stopATR
initialRisk :=
shortStop -
entryPrice
tp1Price :=
entryPrice -
initialRisk * tp1R
tp2Price :=
entryPrice -
initialRisk * tp2R
highestSinceEntry := high
lowestSinceEntry := low
entryBar := bar_index
tp1Hit := false
breakEvenActive := false
trailingActive := false
// ═══════════════════════════════════════════════════════════════════
// TP1 DETECTION
// ═══════════════════════════════════════════════════════════════════
if strategy.position_size > 0 and
not tp1Hit and
not na(tp1Price) and
high >= tp1Price
tp1Hit := true
if strategy.position_size < 0 and
not tp1Hit and
not na(tp1Price) and
low <= tp1Price
tp1Hit := true
// ═══════════════════════════════════════════════════════════════════
// BREAK-EVEN AND TRAILING MANAGEMENT
// ═══════════════════════════════════════════════════════════════════
float breakEvenOffset =
breakEvenOffsetTicks *
syminfo.mintick
float trailMultiplier =
persistence < lowPersistence
? tightTrailATR
: persistence > highPersistence
? looseTrailATR
: baseTrailATR
if strategy.position_size > 0
highestSinceEntry :=
math.max(
nz(highestSinceEntry, high),
high)
lowestSinceEntry :=
math.min(
nz(lowestSinceEntry, low),
low)
if tp1Hit and useBreakEven
longStop :=
math.max(
longStop,
entryPrice +
breakEvenOffset)
breakEvenActive := true
if tp1Hit and useTrail
float proposedLongTrail =
highestSinceEntry -
atr * trailMultiplier
longStop :=
math.max(
longStop,
proposedLongTrail)
trailingActive := true
if strategy.position_size < 0
highestSinceEntry :=
math.max(
nz(highestSinceEntry, high),
high)
lowestSinceEntry :=
math.min(
nz(lowestSinceEntry, low),
low)
if tp1Hit and useBreakEven
shortStop :=
math.min(
shortStop,
entryPrice -
breakEvenOffset)
breakEvenActive := true
if tp1Hit and useTrail
float proposedShortTrail =
lowestSinceEntry +
atr * trailMultiplier
shortStop :=
math.min(
shortStop,
proposedShortTrail)
trailingActive := true
// ═══════════════════════════════════════════════════════════════════
// EXITS
// ═══════════════════════════════════════════════════════════════════
if strategy.position_size > 0
strategy.exit(
"L-TP1",
from_entry = "Long",
qty_percent = tp1Qty,
stop = longStop,
limit = tp1Price)
strategy.exit(
"L-TP2",
from_entry = "Long",
qty_percent = 100.0 - tp1Qty,
stop = longStop,
limit = tp2Price)
if strategy.position_size < 0
strategy.exit(
"S-TP1",
from_entry = "Short",
qty_percent = tp1Qty,
stop = shortStop,
limit = tp1Price)
strategy.exit(
"S-TP2",
from_entry = "Short",
qty_percent = 100.0 - tp1Qty,
stop = shortStop,
limit = tp2Price)
// ═══════════════════════════════════════════════════════════════════
// TIME AND SESSION EXITS
// ═══════════════════════════════════════════════════════════════════
int barsInTrade =
strategy.position_size != 0 and
not na(entryBar)
? bar_index -
entryBar
: 0
if strategy.position_size != 0 and
barsInTrade >= maximumHoldingBars
strategy.close_all(
comment = "LMSE Time Stop",
immediately = true)
if closeAtSessionEnd and
sessionEndBar and
strategy.position_size != 0
strategy.close_all(
comment = "LMSE Session Close",
immediately = true)
// ═══════════════════════════════════════════════════════════════════
// CLOSED-TRADE RESET
// ═══════════════════════════════════════════════════════════════════
bool positionJustClosed =
strategy.position_size == 0 and
strategy.position_size[1] != 0
if positionJustClosed
lastClosedTradeBar := bar_index
pendingStop := na
entryPrice := na
initialRisk := na
longStop := na
shortStop := na
tp1Price := na
tp2Price := na
highestSinceEntry := na
lowestSinceEntry := na
entryBar := na
tp1Hit := false
breakEvenActive := false
trailingActive := false
// ═══════════════════════════════════════════════════════════════════
// PLOTS
// ═══════════════════════════════════════════════════════════════════
plot(
emaFast,
"EMA 20",
color = color.new(C_BLUE, 10),
linewidth = 2)
plot(
emaSlow,
"EMA 50",
color = color.new(C_ORANGE, 10),
linewidth = 2)
float activeStop =
strategy.position_size > 0
? longStop
: strategy.position_size < 0
? shortStop
: na
plot(
showTradeLevels and
strategy.position_size != 0
? entryPrice
: na,
"Active Entry",
color = color.white,
linewidth = 1,
style = plot.style_linebr)
plot(
showTradeLevels
? activeStop
: na,
"Active Stop",
color = C_RED,
linewidth = 2,
style = plot.style_linebr)
plot(
showTradeLevels and
strategy.position_size != 0
? tp1Price
: na,
"TP1",
color = color.new(C_GREEN, 35),
linewidth = 1,
style = plot.style_linebr)
plot(
showTradeLevels and
strategy.position_size != 0
? tp2Price
: na,
"TP2",
color = C_GREEN,
linewidth = 2,
style = plot.style_linebr)
plotshape(
showSignals and longEntry,
title = "Long Entry",
style = shape.labelup,
location = location.belowbar,
color = C_BLUE,
textcolor = color.white,
text = "LONG",
size = size.small)
plotshape(
showSignals and shortEntry,
title = "Short Entry",
style = shape.labeldown,
location = location.abovebar,
color = C_PURPLE,
textcolor = color.white,
text = "SHORT",
size = size.small)
plotshape(
showSetupMarkers and longSetupState,
title = "Raw Long Setup",
style = shape.circle,
location = location.belowbar,
color = color.new(C_BLUE, 60),
size = size.tiny)
plotshape(
showSetupMarkers and shortSetupState,
title = "Raw Short Setup",
style = shape.circle,
location = location.abovebar,
color = color.new(C_PURPLE, 60),
size = size.tiny)
plotshape(
showSweepMarkers and validBuySweep,
title = "Raw Bull Sweep",
style = shape.circle,
location = location.belowbar,
color = color.new(C_GREEN, 40),
size = size.tiny)
plotshape(
showSweepMarkers and validSellSweep,
title = "Raw Bear Sweep",
style = shape.circle,
location = location.abovebar,
color = color.new(C_RED, 40),
size = size.tiny)
// ═══════════════════════════════════════════════════════════════════
// DASHBOARD
// ═══════════════════════════════════════════════════════════════════
resolvedDashboardPosition =
dashPos == "Top Left"
? position.top_left
: dashPos == "Bottom Right"
? position.bottom_right
: dashPos == "Bottom Left"
? position.bottom_left
: position.top_right
dashboardTextSize =
dashFont == "Large"
? size.normal
: dashFont == "Phone"
? size.small
: size.tiny
var table dashboard = table.new(
position = resolvedDashboardPosition,
columns = 2,
rows = 17,
bgcolor = C_NAVY,
border_width = 1,
border_color = color.rgb(55, 72, 95),
frame_width = 2,
frame_color = C_BLUE)
f_dashboardRow(
int row,
string labelText,
string valueText,
color valueBackground) =>
table.cell(
dashboard,
0,
row,
labelText,
bgcolor =
row % 2 == 0
? C_CARD
: C_ALT,
text_color = C_WHITE,
text_size = dashboardTextSize,
text_halign = text.align_left)
table.cell(
dashboard,
1,
row,
valueText,
bgcolor = valueBackground,
text_color = color.white,
text_size = dashboardTextSize,
text_halign = text.align_right)
string positionText =
strategy.position_size > 0
? "LONG"
: strategy.position_size < 0
? "SHORT"
: "FLAT"
color positionColor =
strategy.position_size > 0
? C_BLUE
: strategy.position_size < 0
? C_PURPLE
: C_GRAY
string directionalBias =
dq > 0.0
? "LONG"
: dq < 0.0
? "SHORT"
: "MIXED"
color directionalColor =
dq > 0.0
? C_BLUE
: dq < 0.0
? C_PURPLE
: C_ORANGE
string activeBlocker =
dq > 0.0
? longBlocker
: dq < 0.0
? shortBlocker
: "NO DIRECTION"
color blockerColor =
activeBlocker == "CLEAR"
? C_GREEN
: activeBlocker == "NO DIRECTION" or
activeBlocker == "NO FRESH SETUP" or
activeBlocker == "NO TRIGGER"
? C_GRAY
: activeBlocker == "COOLDOWN"
? C_ORANGE
: C_RED
string setupText =
longSetupLatched
? "L " +
str.tostring(longSetupAge) +
"/" +
str.tostring(maximumEntryDelayBars)
: shortSetupLatched
? "S " +
str.tostring(shortSetupAge) +
"/" +
str.tostring(maximumEntryDelayBars)
: "—"
color setupColor =
longSetupLatched
? C_BLUE
: shortSetupLatched
? C_PURPLE
: C_GRAY
string managementText =
strategy.position_size == 0
? "INACTIVE"
: trailingActive
? "TRAILING"
: breakEvenActive
? "BREAK-EVEN"
: tp1Hit
? "TP1 HIT"
: "INITIAL RISK"
color managementColor =
strategy.position_size == 0
? C_GRAY
: trailingActive
? C_GREEN
: breakEvenActive
? C_BLUE
: tp1Hit
? C_GREEN
: C_ORANGE
string sessionText =
inTradeSession
? "OPEN"
: "CLOSED"
color sessionColor =
inTradeSession
? C_GREEN
: C_RED
string cooldownText =
cooldownPass
? "READY"
: str.tostring(cooldownRemaining) +
" BARS"
color cooldownColor =
cooldownPass
? C_GREEN
: C_ORANGE
string activeLevelsText =
f_price(activeStop) +
" / " +
f_price(tp1Price)
// Surfaces the "Enable Dynamic alert() Calls" toggle on the dashboard —
// if this is off, entry labels can still plot but no alert() message
// will ever be sent, which looks identical to a broken alert.
string alertsStatusText =
not enableDynamicAlerts
? "OFF"
: "ON"
color alertsStatusColor =
not enableDynamicAlerts
? C_RED
: C_GREEN
string sweepTrendText =
sweepLocalLongOk
? "ABOVE 20/50"
: sweepLocalShortOk
? "BELOW 20/50"
: "MIXED"
color sweepTrendColor =
sweepLocalLongOk
? C_BLUE
: sweepLocalShortOk
? C_PURPLE
: C_GRAY
if showDashboard and barstate.islast
table.clear(
dashboard,
0,
0,
1,
16)
f_dashboardRow(
0,
"LMSE-LITE",
"LIVE",
C_BLUE)
f_dashboardRow(
1,
"POSITION",
positionText,
positionColor)
f_dashboardRow(
2,
"BIAS",
directionalBias,
directionalColor)
f_dashboardRow(
3,
"BLOCKER",
activeBlocker,
blockerColor)
f_dashboardRow(
4,
"SETUP AGE",
setupText,
setupColor)
f_dashboardRow(
5,
"SESSION",
sessionText,
sessionColor)
f_dashboardRow(
6,
"TRADES",
str.tostring(tradesToday) +
"/" +
str.tostring(maxTradesPerDay),
dailyTradeLimitPass
? C_CARD
: C_RED)
f_dashboardRow(
7,
"ADX",
str.tostring(adx, "#.0") +
" / " +
str.tostring(adxMin, "#.0"),
adx >= adxMin
? C_GREEN
: C_RED)
f_dashboardRow(
8,
"ATR EXP",
f_number(atrExpansion),
atrExpansion >= atrFactor and
atrExpansion <= atrMaxFactor
? C_GREEN
: C_ORANGE)
f_dashboardRow(
9,
"ROC / BOP",
str.tostring(roc, "#.00") +
" / " +
str.tostring(bop, "#.00"),
directionalColor)
f_dashboardRow(
10,
"DQ",
str.tostring(dq, "#.00"),
dqStrength >= minDQStrength
? directionalColor
: C_RED)
f_dashboardRow(
11,
"FAIL RISK",
str.tostring(pFailLite, "#.00"),
pFailLite <= pFailCap
? C_GREEN
: C_RED)
f_dashboardRow(
12,
"PERSISTENCE",
str.tostring(persistence, "#.0"),
persistence >= highPersistence
? C_GREEN
: persistence <= lowPersistence
? C_ORANGE
: C_CARD)
f_dashboardRow(
13,
"COOLDOWN",
cooldownText,
cooldownColor)
f_dashboardRow(
14,
"STOP / TP1",
activeLevelsText,
managementColor)
f_dashboardRow(
15,
"ALERTS",
alertsStatusText,
alertsStatusColor)
f_dashboardRow(
16,
"SWEEP TREND",
sweepTrendText,
sweepTrendColor)
if not showDashboard and barstate.islast
table.clear(
dashboard,
0,
0,
1,
16)
// ═══════════════════════════════════════════════════════════════════
// ALERT CONDITIONS
//
// IMPORTANT — how to actually receive these notifications:
// When you create the TradingView alert, set "Condition" to this
// script, then pick ONE of:
// • "Any alert() function call" — fires the dynamic alert() messages
// above, which state the live bias (BULLISH/BEARISH), DQ, ADX,
// ATR expansion and candidate stop. This is the recommended option
// if you want full context per trade.
// • One of the named conditions below (e.g. "LMSE Long Entry
// (Bullish)") — fires a fixed static message tied to that specific
// condition only.
// Picking "Order fills" instead of one of the above will NOT trigger
// on these entry signals, and alerts never fire retroactively for
// bars that already closed before the alert was created — only from
// the moment the alert is created onward.
// ═══════════════════════════════════════════════════════════════════
alertcondition(
longEntry,
title = "LMSE Long Entry (Bullish)",
message = "🔵 BULLISH — LMSE-Lite LONG entry — {{ticker}} {{interval}}")
alertcondition(
shortEntry,
title = "LMSE Short Entry (Bearish)",
message = "🟣 BEARISH — LMSE-Lite SHORT entry — {{ticker}} {{interval}}")
alertcondition(
longEntry or shortEntry,
title = "LMSE Any Entry (Check Chart For Bias)",
message = "LMSE-Lite entry — {{ticker}} {{interval}} — see chart/dashboard for BULLISH or BEARISH bias")
alertcondition(
positionJustClosed,
title = "LMSE Position Closed",
message = "LMSE-Lite position closed — {{ticker}} {{interval}}")
alertcondition(
dqStrength >= 0.60,
title = "LMSE High DQ",
message = "LMSE-Lite high directional quality — {{ticker}}")
alertcondition(
pFailLite > pFailCap,
title = "LMSE High Failure Risk",
message = "LMSE-Lite high failure risk — {{ticker}}")
// ═══════════════════════════════════════════════════════════════════
// DATA WINDOW
// ═══════════════════════════════════════════════════════════════════
plot(
dq,
"DQ",
display = display.data_window)
plot(
dqStrength,
"DQ Strength",
display = display.data_window)
plot(
pFailLite,
"Failure Proxy",
display = display.data_window)
plot(
persistence,
"Persistence",
display = display.data_window)
plot(
atrExpansion,
"ATR Expansion",
display = display.data_window)
plot(
emaExtensionATR,
"EMA Extension ATR",
display = display.data_window)
plot(
float(longSetupAge),
"Long Setup Age",
display = display.data_window)
plot(
float(shortSetupAge),
"Short Setup Age",
display = display.data_window)
Overview
Entries can use pullback and reclaim, breakout or liquidity sweep triggers, with limits on entry delay and extension in ATR. Optional failure probability blocking is available. Groups cover trade frequency, session, position sizing, risk management and a trailing stop. It calculates on every tick, so live signals may differ.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
ADX Length
int
14
adxLen
ADX Minimum
float
20.0
adxMin
ROC Length
int
14
rocLen
BOP Smoothing
int
21
bopLen
ATR Length
int
14
atrLen
ATR Baseline
int
50
atrBaseLen
Minimum ATR Expansion
float
0.80
atrFactor
Maximum ATR Expansion
float
2.00
atrMaxFactor
Minimum DQ Strength
float
0.25
minDQStrength
Require EMA 20 / EMA 50 Alignment
bool
true
requireEMAAlignment
Require DI Alignment
bool
true
requireDIAlignment
Require Price Beyond EMA 20
bool
true
requirePriceEMA
Show all 40 settings
Setting
Type
Default
Variable
Block High-Failure Setups
bool
false
blockHighFailure
Failure Probability Cap
float
0.45
pFailCap
Entry Trigger
string
Pullback / Reclaim
entryTriggerMode
Setup Confirmation Bars
int
1
setupConfirmBars
Maximum Entry Delay — Bars
int
0
maximumEntryDelayBars
Require Fresh Trigger On Delayed Entry
bool
true
requireFreshDelayedTrigger
Maximum Entry Extension — ATR
float
1.00
maxEntryExtensionATR
Pullback EMA Tolerance — ATR
float
0.25
pullbackToleranceATR
Breakout Lookback
int
5
breakoutLookback
Sweep: Swing Pivot Length
int
5
sweepPivotLength
Sweep: Stored Liquidity Levels
int
20
sweepStoredLevels
Sweep: Minimum Sweep Distance / ATR
float
0.10
sweepMinDistanceAtr
Sweep: Reclaim Rule
string
Close Back Inside
sweepReclaimRule
Sweep: Minimum Wick %
float
0.35
sweepMinWickPercent
Sweep: Maximum Body %
float
0.65
sweepMaxBodyPercent
Sweep: Minimum Candle Range / ATR
float
0.20
sweepMinRangeAtr
Sweep: Long Confirmation Must Be Bullish
bool
true
sweepRequireBullishBody
Sweep: Short Confirmation Must Be Bearish
bool
true
sweepRequireBearishBody
Sweep: Max Bars After Sweep For Confirmation
int
2
sweepConfirmationWindow
Sweep: Require Sweep Candle Midline Break
bool
true
sweepRequireMidlineBreak
Sweep: Minimum Bars Between Sweep Signals
int
10
sweepSignalSpacingBars
Cooldown Bars After Trade Closes
int
20
cooldownBars
Maximum Trades Per NY Day
int
2
maxTradesPerDay
Require Setup Reset Before Re-entry
bool
true
requireSetupReset
Entry Session
session
0935-1555
tradeSession
Session Timezone
string
America/New_York
sessionTimezone
Close Position At Session End
bool
true
closeAtSessionEnd
Base Contracts
float
1.0
baseQty
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.
This strategy overlays a trend moving average and Supertrend bands directly on the price chart while calculating Stochastic RSI values internally. Long positions trigger when price exceeds the moving average, Supertrend signals bullish momentum, and the StochR
This trading strategy combines three Exponential Moving Averages (8, 14, and 50 periods by default) with Stochastic RSI and Average True Range (ATR). It enters a long position when EMA 1 is above EMA 2, EMA 2 is above EMA 3, and the Stochastic RSI %K line cros
This strategy combines exponential moving averages (EMA 9, 21, 50), RSI, MACD, and Supertrend indicators to enter long positions. It triggers trades using six dynamic setups based on momentum breakouts, EMA crossovers, and pullbacks. Position sizing is compute
This strategy identifies trend reversals through market structure changes (CHoCH) filtered by MACD momentum. It initiates long positions on bullish structure breaks when MACD is positive and above its signal line, and short positions on bearish breaks when MAC
CombinedBinHAndClucV6 is a trading strategy based on the popular BinHV45 and ClucMay72018 algorithms. It calculates dual Bollinger Bands, Exponential Moving Averages, Relative Strength Index, Average True Range, and volume metrics across primary and one-hour h
LuxAlgo Hybrid Gold Scalper is a price-chart strategy aimed at gold. It stacks a fast, slow, trend and 200-period bias EMA to mark trend direction, then filters strength with RSI, ADX and an intraday VWAP. Swing highs and lows are marked from pivot length. Set