← กลับหน้ารายการ

RSI Ladder TP Strategy v1.0

Strategy ผู้เขียน: ORYXA Profit Factor: 721.974

ลิงก์ TradingView

เปิดใน TradingView

Equity Chart

Equity chart

เปิดรูปเต็มขนาด

คำอธิบาย

Overview

This strategy is an RSI-based reversal entry system with a ladder-style take-profit mechanism.
It supports Long-only, Short-only, or Both directions and provides optional Average Entry Price, Stop Loss, and Take Profit reference lines on the chart.

Entry Rules

Long Entry: RSI crosses above the Oversold level (default: 20).

Short Entry: RSI crosses below the Overbought level (default: 80).

Optional: If enabled, the script will close the current position when an opposite signal appears before opening a new one.

Exit Rules (Ladder Take Profit)

Take profit is placed as a ladder using tpLevels and tpStepPct.

Example (default tpStepPct = 1%, tpLevels = 10):

TP1 at +1%, TP2 at +2%, … TP10 at +10% (relative to current average entry price).

Each TP level closes tpClosePct of the remaining position, meaning it scales out geometrically:

If tpClosePct = 50% → remaining position becomes 50%, then 25%, then 12.5%, etc.

Stop Loss

Optional stop loss is placed at slPct (%) away from the average entry price:

Long: avg * (1 - slPct%)

Short: avg * (1 + slPct%)

Visual Lines

Average Entry Price Line: current strategy.position_avg_price

Stop Loss Line: based on slPct

Next TP Line: shows the estimated next TP level based on current profit%

All TP Lines: optional (can clutter the chart)

==============================================================

Recommended Use


This strategy is best used on markets with strong mean-reversion behavior.



For exchanges/bots that do not support hedge mode in a single strategy, run two separate instances:



One set to Long Only



One set to Short Only

รูป Preview

Preview

Pine Script Source

// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ORYXA

//@version=6
strategy(
     title="RSI Ladder Take Profit Strategy v1.0 (Long/Short Selectable) + Avg Price/TP/SL Lines",
     overlay=true,
     commission_type=strategy.commission.percent,
     commission_value=0.0,
     calc_on_every_tick=false
)

//=====================
// Input Settings
//=====================
grpSignal = "Entry/Exit Signals"
rsiLen    = input.int(14, "RSI Length", group=grpSignal, minval=1)
ob        = input.float(80, "Overbought (Cross Down → Short)", group=grpSignal, step=0.5)
os        = input.float(20, "Oversold (Cross Up → Long)", group=grpSignal, step=0.5)
tradeSide = input.string("Long Only", "Trade Direction", options=["Both", "Long Only", "Short Only"], group=grpSignal)
closeOnOpp = input.bool(false, "Close Existing Position on Opposite Signal", group=grpSignal)

grpTP = "Ladder Take Profit (Scaling Out)"
tpStepPct  = input.float(1.0, "TP Step Distance (%)", group=grpTP, step=0.1, minval=0.01)
tpClosePct = input.float(50.0, "Close % Per TP Step (of Remaining Position)", group=grpTP, step=1.0, minval=0.1, maxval=100.0)
tpLevels   = input.int(10, "TP Levels (1%,2%,3%...)", group=grpTP, minval=1, maxval=50)

grpSL = "Stop Loss"
useSL = input.bool(false, "Enable Stop Loss", group=grpSL)
slPct = input.float(10.0, "Stop Loss Distance (%)", group=grpSL, step=0.1, minval=0.01)

grpLines = "Line Display"
showAvgLine   = input.bool(true, "Show Average Entry Price Line", group=grpLines)
showSLLine    = input.bool(true, "Show Stop Loss Line", group=grpLines)
showNextTP    = input.bool(true, "Show 'Next' TP Line", group=grpLines)
showAllTP     = input.bool(false, "Show All TP Level Lines (Many Lines)", group=grpLines)

//=====================
// RSI & Signals
//=====================
rsi = ta.rsi(close, rsiLen)

// Strategy conditions:
// RSI crosses down 80 → Short
// RSI crosses up 20  → Long
shortSignal = ta.crossunder(rsi, ob)
longSignal  = ta.crossover(rsi, os)

// Direction switches
allowLong  = tradeSide == "Both" or tradeSide == "Long Only"
allowShort = tradeSide == "Both" or tradeSide == "Short Only"

//=====================
// Position Info
//=====================
posSize = strategy.position_size
isLong  = posSize > 0
isShort = posSize < 0
avg     = strategy.position_avg_price

//=====================
// Entries / Close on Opposite Signal
//=====================
if longSignal and allowLong
    if closeOnOpp and isShort
        strategy.close(id="S", comment="Close Short on Opposite Signal")
    strategy.entry(id="L", direction=strategy.long, comment="RSI Cross Up Oversold → Long")

if shortSignal and allowShort
    if closeOnOpp and isLong
        strategy.close(id="L", comment="Close Long on Opposite Signal")
    strategy.entry(id="S", direction=strategy.short, comment="RSI Cross Down Overbought → Short")

//=====================
// Ladder TP / Stop Loss (Average price updates after pyramiding)
//=====================

// Long: SL + ladder TP
if isLong
    // Stop Loss (close 100%)
    if useSL
        longSL = avg * (1 - slPct/100.0)
        strategy.exit(id="L-SL", from_entry="L", stop=longSL, qty_percent=100, comment="Long Stop Loss")

    // Ladder TP (qty_percent applies to remaining position)
    for i = 1 to tpLevels
        tpPrice = avg * (1 + (tpStepPct * i)/100.0)
        strategy.exit(
            id="L-TP" + str.tostring(i),
            from_entry="L",
            limit=tpPrice,
            qty_percent=tpClosePct,
            comment="Long TP Level " + str.tostring(i)
        )

// Short: SL + ladder TP
if isShort
    if useSL
        shortSL = avg * (1 + slPct/100.0)
        strategy.exit(id="S-SL", from_entry="S", stop=shortSL, qty_percent=100, comment="Short Stop Loss")

    for i = 1 to tpLevels
        tpPrice = avg * (1 - (tpStepPct * i)/100.0)
        strategy.exit(
            id="S-TP" + str.tostring(i),
            from_entry="S",
            limit=tpPrice,
            qty_percent=tpClosePct,
            comment="Short TP Level " + str.tostring(i)
        )

//=====================
// Lines: Average Price / Stop Loss / Take Profit
//=====================

// Average entry price line
avgLine = (isLong or isShort) ? avg : na
plot(showAvgLine ? avgLine : na, title="Average Entry Price", linewidth=2)

// Stop loss line
longSLLine  = (isLong and useSL)  ? avg * (1 - slPct/100.0) : na
shortSLLine = (isShort and useSL) ? avg * (1 + slPct/100.0) : na
slLine = isLong ? longSLLine : isShort ? shortSLLine : na
plot(showSLLine ? slLine : na, title="Stop Loss", linewidth=2)

// "Next" TP line (to avoid too many lines)
// Next level is estimated by current profit% relative to average entry price
profitPct =
     isLong  ? (close/avg - 1) * 100 :
     isShort ? (1 - close/avg) * 100 :
     na

nextLevel = (isLong or isShort) ? int(math.floor(nz(profitPct, 0) / tpStepPct)) + 1 : na
nextLevelClamped = (isLong or isShort) ? math.min(math.max(nextLevel, 1), tpLevels) : na

nextTPLine =
     isLong  ? avg * (1 + (tpStepPct * nextLevelClamped)/100.0) :
     isShort ? avg * (1 - (tpStepPct * nextLevelClamped)/100.0) :
     na

plot(showNextTP ? nextTPLine : na, title="Next Take Profit Level", linewidth=2)

// Show all TP level lines (optional)
tp1 = (isLong or isShort) ? (isLong ? avg*(1 + tpStepPct/100.0) : avg*(1 - tpStepPct/100.0)) : na
plot(showAllTP ? tp1 : na, title="TP Level 1", linewidth=1)

//=====================
// All TP levels (valid plot usage)
//=====================
tp2  = (isLong ? avg*(1 + tpStepPct*2/100)  : isShort ? avg*(1 - tpStepPct*2/100)  : na)
tp3  = (isLong ? avg*(1 + tpStepPct*3/100)  : isShort ? avg*(1 - tpStepPct*3/100)  : na)
tp4  = (isLong ? avg*(1 + tpStepPct*4/100)  : isShort ? avg*(1 - tpStepPct*4/100)  : na)
tp5  = (isLong ? avg*(1 + tpStepPct*5/100)  : isShort ? avg*(1 - tpStepPct*5/100)  : na)
tp6  = (isLong ? avg*(1 + tpStepPct*6/100)  : isShort ? avg*(1 - tpStepPct*6/100)  : na)
tp7  = (isLong ? avg*(1 + tpStepPct*7/100)  : isShort ? avg*(1 - tpStepPct*7/100)  : na)
tp8  = (isLong ? avg*(1 + tpStepPct*8/100)  : isShort ? avg*(1 - tpStepPct*8/100)  : na)
tp9  = (isLong ? avg*(1 + tpStepPct*9/100)  : isShort ? avg*(1 - tpStepPct*9/100)  : na)
tp10 = (isLong ? avg*(1 + tpStepPct*10/100) : isShort ? avg*(1 - tpStepPct*10/100) : na)

plot(showAllTP ? tp1  : na, title="TP Level 1", linewidth=1)
plot(showAllTP ? tp2  : na, title="TP Level 2", linewidth=1)
plot(showAllTP ? tp3  : na, title="TP Level 3", linewidth=1)
plot(showAllTP ? tp4  : na, title="TP Level 4", linewidth=1)
plot(showAllTP ? tp5  : na, title="TP Level 5", linewidth=1)
plot(showAllTP ? tp6  : na, title="TP Level 6", linewidth=1)
plot(showAllTP ? tp7  : na, title="TP Level 7", linewidth=1)
plot(showAllTP ? tp8  : na, title="TP Level 8", linewidth=1)
plot(showAllTP ? tp9  : na, title="TP Level 9", linewidth=1)
plot(showAllTP ? tp10 : na, title="TP Level 10", linewidth=1)


//=====================
// RSI Display (hidden; keep for debugging)
//=====================
plot(rsi, title="RSI", linewidth=1, display=display.none)
hline(ob, "Overbought", display=display.none)
hline(os, "Oversold", display=display.none)


// ———————————————————— Backtest
// Define the variable "Equity" and assign it the value of "strategy.equity"
float Equity = strategy.equity
// Define the variable "Balance" and assign it the sum of "strategy.initial_capital" and "strategy.netprofit"
float Balance = strategy.initial_capital + strategy.netprofit
// Define the variable "RealizedPnL" and assign it the value of "strategy.netprofit"
float RealizedPnL = strategy.netprofit
// Define the variable "Floating" and assign it the value of "strategy.openprofit"
float Floating = strategy.openprofit
// Calculate the percentage of "Floating" relative to "Balance" and assign it to "PFloating"
float PFloating = Floating / Balance * 100
// Calculate the percentage of "RealizedPnL" relative to "strategy.initial_capital" and assign it to "PRealizedPnL"
float PRealizedPnL = RealizedPnL / strategy.initial_capital * 100
// Calculate the sum of "Floating" and "RealizedPnL" and assign it to "URealizedPnL"
float URealizedPnL = Floating + RealizedPnL
// Calculate the percentage of "URealizedPnL" relative to "strategy.initial_capital" and assign it to "PURealizedPnL"
float PURealizedPnL = URealizedPnL / strategy.initial_capital * 100
// Calculate the profit factor by dividing "strategy.grossprofit" by "strategy.grossloss" and assign it to "ProfitFactor"
float ProfitFactor = strategy.grossprofit / strategy.grossloss
// Calculate the position size by multiplying "strategy.position_size" and "strategy.position_avg_price" and assign it to "PositionSize"
float PositionSize = strategy.position_size * strategy.position_avg_price
// Calculate the cash by subtracting the product of "nz(PositionSize)" and "marginRate" from "Balance" and assign it to "Cash"
float Cash = Balance - nz(PositionSize) * 0.015
// Calculate the profitability by dividing "strategy.wintrades" by the sum of "strategy.wintrades" and "strategy.losstrades", multiplying by 100, and assign it to "Profitability"
float Profitability = strategy.wintrades / (strategy.wintrades + strategy.losstrades) * 100
// Calculate the leverage parameter by dividing the absolute value of "PositionSize" by "Balance" and assign it to "LeverageParameter"
float LeverageParameter = math.abs(nz(PositionSize / Balance))
// Calculate the trading time by subtracting "strategy.closedtrades.entry_time(0)" from "time_close" and assign it to "TradingTime"
int TradingTime = time_close - strategy.closedtrades.entry_time(0)

// ————— Creating the Table
var InfoPanel = table.new(position.middle_left, 2, 10, na, color.new(color.white, 80), 1, color.new(color.white, 80), 1)

// Define a function for the table formatting
ftable(_table_id, _column, _row, _text, _text_color) =>
    table.cell(_table_id, _column, _row, _text, 0, 0, _text_color, text.align_left, text.align_center, size.tiny, na)

// Function to convert time in milliseconds to string format
tfString(int timeInMs) =>
    float s = timeInMs / 1000
    float m = s / 60
    float h = m / 60
    float d = h / 24
    float mo = d / 30.416
    int tm = math.floor(m % 60)
    int tr = math.floor(h % 24)
    int td = math.floor(d % 30.416)
    int tmo = math.floor(mo % 12)
    int ys = math.floor(d / 365)
    string result = switch 
        d == 30 and tr == 10 and tm == 30 => '1M'
        d == 7 and tr == 0 and tm == 0 => '1W'
        =>
            string yStr = bool(ys) ? str.tostring(ys) + 'Y ' : ''
            string moStr = bool(tmo) ? str.tostring(tmo) + 'M ' : ''
            string dStr = bool(td) ? str.tostring(td) + 'D ' : ''
            string hStr = bool(tr) ? str.tostring(tr) + 'H ' : ''
            string mStr = bool(tm) ? str.tostring(tm) + 'min' : ''
            yStr + moStr + dStr + hStr + mStr
    result

ftable(InfoPanel, 0, 0, 'Equity: ', color.new(color.white, 50))
ftable(InfoPanel, 0, 1, 'Position: ', color.new(color.white, 50))
ftable(InfoPanel, 0, 2, 'Cash: ', color.new(color.white, 50))
ftable(InfoPanel, 0, 3, 'Floating: ', color.new(color.white, 50))
ftable(InfoPanel, 0, 4, 'Realized PnL: ', color.new(color.white, 50))
ftable(InfoPanel, 0, 5, 'Unrealized PnL: ', color.new(color.white, 50))
ftable(InfoPanel, 0, 6, 'Leverage: ', color.new(color.white, 50))
ftable(InfoPanel, 0, 7, 'Profitability: ', color.new(color.white, 50))
ftable(InfoPanel, 0, 8, 'Profit Factor: ', color.new(color.white, 50))
ftable(InfoPanel, 0, 9, 'Time of Trading: ', color.new(color.white, 50))

ftable(InfoPanel, 1, 0, str.tostring(Equity, '#.##') + ' ' + syminfo.currency, Equity >= 0 ? color.green : color.red)
ftable(InfoPanel, 1, 1, str.tostring(strategy.position_size, '#.#####') + ' ' + syminfo.basecurrency, strategy.position_size >= 0 ? color.green : color.red)
ftable(InfoPanel, 1, 2, str.tostring(Cash, '#.##') + ' ' + syminfo.currency, Cash >= 0 ? color.green : color.red)
ftable(InfoPanel, 1, 3, str.tostring(PFloating, '#.##') + ' %', PFloating >= 0 ? color.green : color.red)
ftable(InfoPanel, 1, 4, str.tostring(PRealizedPnL, '#.##') + ' %', PRealizedPnL >= 0 ? color.green : color.red)
ftable(InfoPanel, 1, 5, str.tostring(PURealizedPnL, '#.##') + ' %', PURealizedPnL >= 0 ? color.green : color.red)
ftable(InfoPanel, 1, 6, str.tostring(LeverageParameter, '#.##') + ' x', math.round(LeverageParameter, 1) <= 1 ? color.green : color.red)
ftable(InfoPanel, 1, 7, str.tostring(Profitability, '#.##') + ' %', Profitability >= 1 ? color.green : color.red)
ftable(InfoPanel, 1, 8, str.tostring(ProfitFactor, '#.###'), ProfitFactor >= 1 ? color.green : color.red)
ftable(InfoPanel, 1, 9, tfString(TradingTime), color.new(color.white, 50))