//@version=6
strategy("Swing Trading Pro (Cash-Based)",
overlay=true,
initial_capital=670608,
default_qty_type=strategy.cash,
default_qty_value=44707,
commission_type=strategy.commission.percent,
commission_value=0,
slippage=0,
pyramiding=4)
// 1. SWING TRADING CONFIGURATION
fastEmaLen = input.int(13, "Fast EMA", minval=5, maxval=20)
mediumEmaLen = input.int(48, "Medium EMA", minval=21, maxval=100)
slowEmaLen = input.int(200, "Slow EMA", minval=100, maxval=300)
// 2. CASH MANAGEMENT
initPosSize = input.float(44707, "Initial Position (₹)", minval=10000,
maxval=100000)
maxMartingale = 3
maxPyramiding = 3
inputDefStopLoss = input.float(6.0, "Stop Loss (%)", minval=6.0, maxval=10.0)
var float stopLossPct = inputDefStopLoss
// 3. SWING TARGETS
profitTarget1 = input.float(8.0, "First Target (%)", minval=6.0, maxval=25.0)
profitTarget2 = input.float(30.0, "Final Target (%)", minval=25.0, maxval=60.0)
partialPct = input.int(25, "Partial % at Target", minval=10, maxval=40)
// 4. CORE INDICATORS
fastEma = ta.ema(close, fastEmaLen)
mediumEma = ta.ema(close, mediumEmaLen)
slowEma = ta.ema(close, slowEmaLen)
weeklyClose = request.security(syminfo.tickerid, "W", close)
weeklyTrend = weeklyClose > ta.ema(weeklyClose, 10)
rsi = ta.rsi(close, 14)
volumeSpike = volume > ta.sma(volume, 20) * 1.5
// 5. TRADE CONDITIONS
bullishSwing = fastEma > mediumEma and mediumEma > slowEma and close > slowEma
bearishSwing = fastEma < mediumEma or close < slowEma
entryCondition = bullishSwing and weeklyTrend and rsi > 50 and volumeSpike
// 6. POSITION TRACKING WITH ACTUAL CASH
var float entryPrice = na
var int entryBar = na
var int martingaleSteps = 0
var int pyramidSteps = 0
var bool firstTargetHit = false
var string positionType = ""
var bool defenseActive = false
// Track actual cash used for each position
var float baseCash = 0.0
var float mg1Cash = 0.0
var float mg2Cash = 0.0
var float mg3Cash = 0.0
var float totalInvestment = 0.0
// 7. ADVANCED SAFEGUARDS
// 7.1 Volatility Filter
atr = ta.atr(14)
volatilityFilter = close > ta.lowest(low, 5) + (atr * 1.5)
// 7.2 Momentum Confirmation
rsiBearish = rsi < 50 and rsi < rsi[1]
momentumFilter = not (rsiBearish and close < close[1])
// 7.5 TREND STRENGTH CONFIRMATION
adxLength = input.int(14, "ADX Length", minval=10, maxval=20)
adxThreshold = input.int(25, "ADX Threshold", minval=20, maxval=30)
[diPlus, diMinus, adxValue] = ta.dmi(adxLength, adxLength)
strongTrend = adxValue > adxThreshold
// 7.6 EMA Slope Filter
emaSlopeLookback = input.int(5, "EMA Slope Lookback", minval=3, maxval=10)
mediumEmaRising = mediumEma > mediumEma[emaSlopeLookback]
longEmaRising = slowEma > slowEma[emaSlopeLookback * 2]
// 8. CASH-BASED POSITION SIZING
currentExposure() =>
strategy.position_size * close
// Pyramiding availability check
canAddPyramid() =>
pyramidSteps < maxPyramiding and (currentExposure() + initPosSize) <=
strategy.equity
// Martingale availability check
canAddMartingale() =>
// Calculate required cash
float requiredCash = 0.0
if martingaleSteps == 0
requiredCash := baseCash * 2
else if martingaleSteps == 1
requiredCash := (mg1Cash > 0 ? mg1Cash : baseCash) * 2
else if martingaleSteps == 2
requiredCash := (mg2Cash > 0 ? mg2Cash : mg1Cash) * 2
martingaleSteps < maxMartingale and (currentExposure() + requiredCash) <=
strategy.equity
// Entry System - cash-based with whole shares
if entryCondition and strategy.position_size == 0 and barstate.isconfirmed
// Calculate shares based on cash amount
targetShares = initPosSize / close
actualShares = math.floor(targetShares)
baseCashActual = actualShares * close
if actualShares >= 1
strategy.entry("Init", strategy.long, qty=actualShares)
entryPrice := close
entryBar := bar_index
martingaleSteps := 0
pyramidSteps := 0
firstTargetHit := false
positionType := ""
defenseActive := false
stopLossPct := inputDefStopLoss
baseCash := baseCashActual
totalInvestment := baseCashActual
mg1Cash := 0.0
mg2Cash := 0.0
mg3Cash := 0.0
// Update hold bars counter
var int holdBars = 0
if strategy.position_size > 0
holdBars := holdBars + 1
else
holdBars := 0
// Position PnL calculation
currentPnL = strategy.position_size > 0 ?
((close - strategy.position_avg_price) / strategy.position_avg_price) * 100 :
0
// Martingale entry with cash calculation
if strategy.position_size > 0 and positionType != "PY" and barstate.isconfirmed
if currentPnL <= -stopLossPct and canAddMartingale()
// Calculate cash to invest
cashToInvest = 0.0
if martingaleSteps == 0
cashToInvest := baseCash * 2
else if martingaleSteps == 1
cashToInvest := (mg1Cash > 0 ? mg1Cash : baseCash) * 2
else if martingaleSteps == 2
cashToInvest := (mg2Cash > 0 ? mg2Cash : mg1Cash) * 2
// Calculate shares based on cash amount
targetShares = cashToInvest / close
actualShares = math.floor(targetShares)
if actualShares >= 1
cashActual = actualShares * close
strategy.entry("MG"+str.tostring(martingaleSteps+1), strategy.long,
qty=actualShares)
// Record actual cash used
if martingaleSteps == 0
mg1Cash := cashActual
else if martingaleSteps == 1
mg2Cash := cashActual
else if martingaleSteps == 2
mg3Cash := cashActual
totalInvestment := totalInvestment + cashActual
martingaleSteps += 1
positionType := "MG"
// Pyramiding entry with cash calculation
if strategy.position_size > 0 and positionType != "MG" and barstate.isconfirmed
if currentPnL >= profitTarget1/3 and canAddPyramid()
// Calculate shares based on cash amount
targetShares = initPosSize / close
actualShares = math.floor(targetShares)
if actualShares >= 1
cashActual = actualShares * close
strategy.entry("PY"+str.tostring(pyramidSteps+1), strategy.long,
qty=actualShares)
pyramidSteps := pyramidSteps + 1
positionType := "PY"
totalInvestment := totalInvestment + cashActual
// Profit Taking
if strategy.position_size > 0 and not firstTargetHit and currentPnL >=
profitTarget1 and barstate.isconfirmed
strategy.close("Partial", qty_percent=partialPct)
firstTargetHit := true
// 9. DEFENSIVE PARTIAL EXITS
defenseLevel = input.float(2.5, "Defense Trigger (%)", minval=1.0, maxval=3.5)
if strategy.position_size > 0 and not defenseActive and
currentPnL <= -defenseLevel and barstate.isconfirmed
strategy.close("Defense", qty_percent=25)
defenseActive := true
stopLossPct := stopLossPct * 0.75 // Tighten SL by 25%
// Reset defense if recovery happens
if strategy.position_size > 0 and defenseActive and
currentPnL >= 0 and barstate.isconfirmed
defenseActive := false
stopLossPct := inputDefStopLoss // Restore original SL
// 10. SIMPLIFIED EXIT CONDITIONS
bearishSignal = fastEma < mediumEma or close < slowEma
minHoldPeriod = input.int(10, "Min Hold Bars", minval=3, maxval=30)
exitCondition = (currentPnL >= profitTarget2) or (bearishSignal and holdBars >=
minHoldPeriod)
// Main exit execution
if strategy.position_size > 0 and exitCondition and barstate.isconfirmed
strategy.close_all("Exit")
entryPrice := na
positionType := ""
martingaleSteps := 0
pyramidSteps := 0
firstTargetHit := false
defenseActive := false
stopLossPct := inputDefStopLoss
holdBars := 0
// 11. VISUALIZATION
plot(fastEma, "Fast EMA", color.blue)
plot(mediumEma, "Medium EMA", color.orange)
plot(slowEma, "Slow EMA", color.red, linewidth=2)
plotshape(series=strategy.position_size == 0 and entryCondition,
title="Entry", style=shape.triangleup, color=color.green, size=size.small)
// 12. RISK TABLE WITH ACTUAL CASH
var table riskTable = table.new(position.top_right, 3, 10,
bgcolor=color.new(color.gray, 90))
if barstate.islast
// Column headers
table.cell(riskTable, 0, 0, "Position", bgcolor=color.gray)
table.cell(riskTable, 1, 0, "Target Cash", bgcolor=color.gray)
table.cell(riskTable, 2, 0, "Actual Cash", bgcolor=color.gray)
// Base position
table.cell(riskTable, 0, 1, "Base", bgcolor=color.silver)
table.cell(riskTable, 1, 1, "₹" + str.tostring(math.round(initPosSize)))
table.cell(riskTable, 2, 1, baseCash > 0 ? "₹" +
str.tostring(math.round(baseCash)) : "—")
// Martingale steps
table.cell(riskTable, 0, 2, "MG1", bgcolor=color.silver)
table.cell(riskTable, 1, 2, "₹" + str.tostring(math.round(initPosSize * 2)))
table.cell(riskTable, 2, 2, mg1Cash > 0 ? "₹" +
str.tostring(math.round(mg1Cash)) : "—")
table.cell(riskTable, 0, 3, "MG2", bgcolor=color.silver)
table.cell(riskTable, 1, 3, "₹" + str.tostring(math.round(initPosSize * 4)))
table.cell(riskTable, 2, 3, mg2Cash > 0 ? "₹" +
str.tostring(math.round(mg2Cash)) : "—")
table.cell(riskTable, 0, 4, "MG3", bgcolor=color.silver)
table.cell(riskTable, 1, 4, "₹" + str.tostring(math.round(initPosSize * 8)))
table.cell(riskTable, 2, 4, mg3Cash > 0 ? "₹" +
str.tostring(math.round(mg3Cash)) : "—")
// CURRENT POSITION STATUS
currentStep = ""
if positionType == "MG"
currentStep := "MG" + str.tostring(martingaleSteps)
table.cell(riskTable, 0, 5, "Position Status:", bgcolor=color.blue)
table.cell(riskTable, 1, 5, positionType != "" ? positionType : "None",
bgcolor=color.blue)
table.cell(riskTable, 2, 5, currentStep, bgcolor=color.blue)
// DEFENSE STATUS
defenseStatus = defenseActive ? "Active" : "Inactive"
table.cell(riskTable, 0, 6, "Defense System:", bgcolor=color.purple)
table.cell(riskTable, 1, 6, defenseStatus, bgcolor=color.purple)
table.cell(riskTable, 2, 6, defenseActive ? "SL: " + str.tostring(stopLossPct,
"#.#") + "%" : "", bgcolor=color.purple)
// TOTAL INVESTMENT
table.cell(riskTable, 0, 7, "Total Invested:", bgcolor=color.navy)
table.cell(riskTable, 1, 7, "₹" + str.tostring(math.round(totalInvestment)),
bgcolor=color.navy)
table.cell(riskTable, 2, 7,
str.tostring((totalInvestment/strategy.initial_capital)*100, "#.##") + "%",
bgcolor=color.navy)
// CURRENT EXPOSURE
currExp = currentExposure()
table.cell(riskTable, 0, 8, "Current Exposure:", bgcolor=color.orange)
table.cell(riskTable, 1, 8, "₹" + str.tostring(math.round(currExp)),
bgcolor=color.orange)
table.cell(riskTable, 2, 8,
str.tostring((currExp/strategy.initial_capital)*100, "#.##") + "%",
bgcolor=color.orange)
// POSITION PROGRESS
positionProgress = ""
if positionType == "MG"
positionProgress := str.tostring(martingaleSteps) + "/3 MG Steps"
table.cell(riskTable, 0, 9, "Progress:", bgcolor=color.fuchsia)
table.cell(riskTable, 1, 9, positionProgress, bgcolor=color.fuchsia)
table.cell(riskTable, 2, 9, firstTargetHit ? "Target1 Hit" : "",
bgcolor=color.fuchsia)