mean reversion-strategy.pine

 avatar
unknown
plain_text
2 months ago
17 kB
6
Indexable
//@version=6
strategy("Mean Reversion Mirror", overlay = true, initial_capital = 5000)

// === Lot Precision ===
lot_precision     = input.int(title = "Lot Precision", defval = 3, minval = 0, maxval = 8)
show_base_labels  = input.bool(title = "Show Base Order Label", defval = true)
show_small_table  = input.bool(title = "Show Mini Table", defval = true)

// === Direction Toggles ===
enable_long  = input.bool(title = "Enable LONG",  defval = true)
enable_short = input.bool(title = "Enable SHORT", defval = true)

roundQty(q) =>
    factor = math.pow(10.0, lot_precision)
    raw    = math.ceil(q * factor) / factor
    math.max(1.0 / factor, raw)

// === Modes ===
STK   = input.bool(title = "Stock Mode (units instead of quantity)", defval = false)
PLotD = input.bool(title = "Show Dynamic Levels",                    defval = false)

// === Manual Levels (manual LONG / SHORT) ===
use_manual_long  = input.bool(false, "Enable Manual LONG Entries")
use_manual_short = input.bool(false, "Enable Manual SHORT Entries")

manual_long_price_in  = input.float(0.0, "Manual LONG Price",  step = 0.1)
manual_short_price_in = input.float(0.0, "Manual SHORT Price", step = 0.1)
reset_manual_levels   = input.bool(false, "Reset Manual Levels")

var float manual_long_price  = na
var float manual_short_price = na
var line  long_line  = na
var line  short_line = na
var bool  reset_done = false

if reset_manual_levels and not reset_done
    if not na(long_line)
        line.delete(long_line)
    if not na(short_line)
        line.delete(short_line)
    manual_long_price  := na
    manual_short_price := na
    long_line  := na
    short_line := na
    reset_done := true
if not reset_manual_levels
    reset_done := false

if use_manual_long and manual_long_price_in > 0 and not reset_manual_levels
    if na(manual_long_price) or manual_long_price != manual_long_price_in
        if not na(long_line)
            line.delete(long_line)
        manual_long_price := manual_long_price_in
        x1 = bar_index > 5000 ? bar_index - 5000 : 0
        long_line := line.new(x1, manual_long_price, bar_index, manual_long_price, extend = extend.right, color = color.new(color.green, 0))
else
    if not na(long_line)
        line.delete(long_line)
    long_line := na
    manual_long_price := na

if use_manual_short and manual_short_price_in > 0 and not reset_manual_levels
    if na(manual_short_price) or manual_short_price != manual_short_price_in
        if not na(short_line)
            line.delete(short_line)
        manual_short_price := manual_short_price_in
        x1s = bar_index > 5000 ? bar_index - 5000 : 0
        short_line := line.new(x1s, manual_short_price, bar_index, manual_short_price, extend = extend.right, color = color.new(color.red, 0))
else
    if not na(short_line)
        line.delete(short_line)
    short_line := na
    manual_short_price := na

if not na(long_line)
    line.set_x2(long_line, bar_index)
if not na(short_line)
    line.set_x2(short_line, bar_index)

// === Deviations (common for LONG and SHORT) ===
deviation  = input.float(title = "Deviation 1 (%)", defval = 1.3,  minval = 0.01, maxval = 100, step = 0.1)  / 100
deviation1 = input.float(title = "Deviation 2 (%)", defval = 7.5,  minval = 0.01, maxval = 100, step = 0.1)  / 100
deviation2 = input.float(title = "Deviation 3 (%)", defval = 13.3, minval = 0.01, maxval = 100, step = 0.1)  / 100
deviation3 = input.float(title = "Deviation 4 (%)", defval = 21.1, minval = 0.01, maxval = 100, step = 0.1)  / 100
deviation4 = input.float(title = "Deviation 5 (%)", defval = 33.7, minval = 0.01, maxval = 100, step = 0.1)  / 100
deviation5 = input.float(title = "Deviation 6 (%) — Last Chance", defval = 54.0, minval = 0.01, maxval = 100, step = 0.1) / 100

// === Buy Levels ($) ===
unitsLevel1 = input.float(title = "Level 1 ($)", defval = 100)
unitsLevel2 = input.float(title = "Level 2 ($)", defval = 200)
unitsLevel3 = input.float(title = "Level 3 ($)", defval = 300)
unitsLevel4 = input.float(title = "Level 4 ($)", defval = 650)
unitsLevel5 = input.float(title = "Level 5 ($)", defval = 850)
unitsLevel6 = input.float(title = "Level 6 ($) — Last Chance", defval = 0.0, minval = 0.0)

// === MA ===
maType   = input.string(title = "MA Type", defval = "WMA", options = ["WMA","SMA","RMA","EMA","HMA"])
maLength = input.int(title = "MA Period", defval = 20, minval = 2)

ma = switch maType
    "EMA" => ta.ema(close, maLength)
    "SMA" => ta.sma(close, maLength)
    "RMA" => ta.rma(close, maLength)
    "WMA" => ta.wma(close, maLength)
    "HMA" => ta.hma(close, maLength)
    => na

// === Dynamic LONG Levels ===
L1 = ma * (1 - deviation)
L2 = ma * (1 - deviation1)
L3 = ma * (1 - deviation2)
L4 = ma * (1 - deviation3)
L5 = ma * (1 - deviation4)
L6 = ma * (1 - deviation5)

// === Dynamic SHORT Levels ===
S1 = ma * (1 + deviation)
S2 = ma * (1 + deviation1)
S3 = ma * (1 + deviation2)
S4 = ma * (1 + deviation3)
S5 = ma * (1 + deviation4)
S6 = ma * (1 + deviation5)

// === Static LONG Levels ===
s2 = 0.0
s2 := na(s2[1]) ? na : s2[1]

s3 = 0.0
s3 := na(s3[1]) ? na : s3[1]

s4 = 0.0
s4 := na(s4[1]) ? na : s4[1]

s5 = 0.0
s5 := na(s5[1]) ? na : s5[1]

s6 = 0.0
s6 := na(s6[1]) ? na : s6[1]

// === Static SHORT Levels ===
s2s = 0.0
s2s := na(s2s[1]) ? na : s2s[1]

s3s = 0.0
s3s := na(s3s[1]) ? na : s3s[1]

s4s = 0.0
s4s := na(s4s[1]) ? na : s4s[1]

s5s = 0.0
s5s := na(s5s[1]) ? na : s5s[1]

s6s = 0.0
s6s := na(s6s[1]) ? na : s6s[1]

// === Take-Profit ===
take_profit_long  = input.float(title = "LONG Take-Profit (%)",  defval = 2, step = 0.01, minval = 0.0) / 100
take_profit_short = input.float(title = "SHORT Take-Profit (%)", defval = 2, step = 0.01, minval = 0.0) / 100

take_profit_level_long  = strategy.position_avg_price * (1 + take_profit_long)
take_profit_level_short = strategy.position_avg_price * (1 - take_profit_short)

// === Trailing ===
takeProfitTrailingEnabled      = input.bool(title = "Enable Trailing", defval = true)
trailingTakeProfitDistancePerc = input.float(title = "Trailing Distance (%)", defval = 1.0, minval = 0.01, maxval = 100, step = 0.01) / 100

longTrailingTakeProfitStepTicks  = (take_profit_level_long  - strategy.position_avg_price) / syminfo.mintick
shortTrailingTakeProfitStepTicks = (strategy.position_avg_price - take_profit_level_short) / syminfo.mintick

// === Exits ===
if enable_long and strategy.position_size > 0
    strategy.exit("TP-LONG",
        limit        = takeProfitTrailingEnabled ? na : take_profit_level_long,
        trail_price  = takeProfitTrailingEnabled ? take_profit_level_long : na,
        trail_offset = takeProfitTrailingEnabled ? longTrailingTakeProfitStepTicks : na)

if enable_short and strategy.position_size < 0
    strategy.exit("TP-SHORT",
        limit        = takeProfitTrailingEnabled ? na : take_profit_level_short,
        trail_price  = takeProfitTrailingEnabled ? take_profit_level_short : na,
        trail_offset = takeProfitTrailingEnabled ? shortTrailingTakeProfitStepTicks : na)

// === TP and Average Price Visualization ===
plot(strategy.position_size > 0 ? take_profit_level_long  : na, style = plot.style_linebr, linewidth = 2, color = color.new(color.green, 0), title = "TP LONG")
plot(strategy.position_size < 0 ? take_profit_level_short : na, style = plot.style_linebr, linewidth = 2, color = color.new(color.red,   0), title = "TP SHORT")
plot(strategy.position_avg_price, style = plot.style_linebr, linewidth = 2, color = color.black, title = "Avg Price")

// === Manual Entry Conditions as Base Order ===
long_level_entry  = use_manual_long  and enable_long  and strategy.opentrades == 0 and strategy.position_size == 0 and not na(manual_long_price)  and close <= manual_long_price
short_level_entry = use_manual_short and enable_short and strategy.opentrades == 0 and strategy.position_size == 0 and not na(manual_short_price) and close >= manual_short_price

// === LONG Entry Logic B1–B6 ===

// Manual LONG as base entry
if long_level_entry
    qtym = STK ? unitsLevel1 : roundQty(unitsLevel1 / close)
    strategy.order("MB1", strategy.long, qtym)
    s2 := L2
    if not na(long_line)
        line.delete(long_line)
        long_line := na
    manual_long_price := na

// B1 LONG
if enable_long and strategy.opentrades == 0 and strategy.position_size == 0 and close < L1
    qty1 = STK ? unitsLevel1 : roundQty(unitsLevel1 / close)
    strategy.order("B1", strategy.long, qty1)
    s2 := L2

    if show_base_labels
        label.new(bar_index, low, "B1: " + str.tostring(qty1),
            style = label.style_label_up, color = color.green)

// B2 LONG
if enable_long and strategy.opentrades == 1 and strategy.position_size > 0 and close < s2
    qty2 = STK ? unitsLevel2 : roundQty(unitsLevel2 / close)
    strategy.order("B2", strategy.long, qty2)
    s3 := L3

// B3 LONG
if enable_long and strategy.opentrades == 2 and strategy.position_size > 0 and close < s3
    qty3 = STK ? unitsLevel3 : roundQty(unitsLevel3 / close)
    strategy.order("B3", strategy.long, qty3)
    s4 := L4

// B4 LONG
if enable_long and strategy.opentrades == 3 and strategy.position_size > 0 and close < s4
    qty4 = STK ? unitsLevel4 : roundQty(unitsLevel4 / close)
    strategy.order("B4", strategy.long, qty4)
    s5 := L5

// B5 LONG
if enable_long and strategy.opentrades == 4 and strategy.position_size > 0 and close < s5
    qty5 = STK ? unitsLevel5 : roundQty(unitsLevel5 / close)
    strategy.order("B5", strategy.long, qty5)
    s6 := L6

// B6 LONG — last chance
if enable_long and unitsLevel6 > 0 and strategy.opentrades == 5 and strategy.position_size > 0 and close < s6
    qty6 = STK ? unitsLevel6 : roundQty(unitsLevel6 / close)
    strategy.order("B6", strategy.long, qty6)

// === SHORT Entry Logic S1–S6 ===

// Manual SHORT as base entry
if short_level_entry
    qtyms = STK ? unitsLevel1 : roundQty(unitsLevel1 / close)
    strategy.order("MS1", strategy.short, qtyms)
    s2s := S2
    if not na(short_line)
        line.delete(short_line)
        short_line := na
    manual_short_price := na

// S1 SHORT
if enable_short and strategy.opentrades == 0 and strategy.position_size == 0 and close > S1
    qty1s = STK ? unitsLevel1 : roundQty(unitsLevel1 / close)
    strategy.order("S1", strategy.short, qty1s)
    s2s := S2

    if show_base_labels
        label.new(bar_index, high, "S1: " + str.tostring(qty1s),
            style = label.style_label_down, color = color.red)

// S2 SHORT
if enable_short and strategy.opentrades == 1 and strategy.position_size < 0 and close > s2s
    qty2s = STK ? unitsLevel2 : roundQty(unitsLevel2 / close)
    strategy.order("S2", strategy.short, qty2s)
    s3s := S3

// S3 SHORT
if enable_short and strategy.opentrades == 2 and strategy.position_size < 0 and close > s3s
    qty3s = STK ? unitsLevel3 : roundQty(unitsLevel3 / close)
    strategy.order("S3", strategy.short, qty3s)
    s4s := S4

// S4 SHORT
if enable_short and strategy.opentrades == 3 and strategy.position_size < 0 and close > s4s
    qty4s = STK ? unitsLevel4 : roundQty(unitsLevel4 / close)
    strategy.order("S4", strategy.short, qty4s)
    s5s := S5

// S5 SHORT
if enable_short and strategy.opentrades == 4 and strategy.position_size < 0 and close > s5s
    qty5s = STK ? unitsLevel5 : roundQty(unitsLevel5 / close)
    strategy.order("S5", strategy.short, qty5s)
    s6s := S6

// S6 SHORT — last chance
if enable_short and unitsLevel6 > 0 and strategy.opentrades == 5 and strategy.position_size < 0 and close > s6s
    qty6s = STK ? unitsLevel6 : roundQty(unitsLevel6 / close)
    strategy.order("S6", strategy.short, qty6s)

// === Dynamic LONG Levels Graphics ===
l_ma = plot(ma, color = color.new(color.red, 0), linewidth = 3, title = "MA")

l_b1 = plot(PLotD ? L1 : na, color = color.new(color.red,   0), linewidth = 1, title = "L1")
l_b2 = plot(PLotD ? L2 : na, color = color.new(color.black, 0), linewidth = 1, title = "L2")
l_b3 = plot(PLotD ? L3 : na, color = color.new(color.black, 0), linewidth = 1, title = "L3")
l_b4 = plot(PLotD ? L4 : na, color = color.new(color.black, 0), linewidth = 1, title = "L4")
l_b5 = plot(PLotD ? L5 : na, color = color.new(color.black, 0), linewidth = 1, title = "L5")

fill(l_ma, l_b1, color = color.new(color.gray,   50))
fill(l_b1, l_b2, color = color.new(color.orange, 90))
fill(l_b2, l_b3, color = color.new(color.orange, 85))
fill(l_b3, l_b4, color = color.new(color.orange, 80))
fill(l_b4, l_b5, color = color.new(color.orange, 85))

// === Dynamic SHORT Levels Graphics ===
s_b1 = plot(PLotD ? S1 : na, color = color.new(color.maroon,  0), linewidth = 1, title = "S1")
s_b2 = plot(PLotD ? S2 : na, color = color.new(color.maroon,  0), linewidth = 1, title = "S2")
s_b3 = plot(PLotD ? S3 : na, color = color.new(color.maroon,  0), linewidth = 1, title = "S3")
s_b4 = plot(PLotD ? S4 : na, color = color.new(color.maroon,  0), linewidth = 1, title = "S4")
s_b5 = plot(PLotD ? S5 : na, color = color.new(color.maroon,  0), linewidth = 1, title = "S5")

fill(s_b1, s_b2, color = color.new(color.red,   90))
fill(s_b2, s_b3, color = color.new(color.red,   85))
fill(s_b3, s_b4, color = color.new(color.red,   80))
fill(s_b4, s_b5, color = color.new(color.red,   75))

// === L6 — dotted ===
plot_L6 = plot(PLotD ? L6 : na, color = color.new(color.blue, 0), linewidth = 2, title = "L6 — Last Chance")

var line l6_line = na
if barstate.islast and PLotD
    line.delete(l6_line)
    l6_line := line.new(bar_index - 1, L6, bar_index, L6, extend = extend.right)
    line.set_style(l6_line, line.style_dotted)
    line.set_color(l6_line, color.new(color.blue, 0))
    line.set_width(l6_line, 2)

// === S6 — dotted ===
plot_S6 = plot(PLotD ? S6 : na, color = color.new(color.red, 0), linewidth = 2, title = "S6 — Last Chance")

var line s6_line = na
if barstate.islast and PLotD
    line.delete(s6_line)
    s6_line := line.new(bar_index - 1, S6, bar_index, S6, extend = extend.right)
    line.set_style(s6_line, line.style_dotted)
    line.set_color(s6_line, color.new(color.red, 0))
    line.set_width(s6_line, 2)

// === Static LONG Levels ===
st2 = plot(strategy.opentrades > 0 and strategy.position_size > 0 ? s2 : na, title = "Static 2 LONG", style = plot.style_linebr)
st3 = plot(strategy.opentrades > 1 and strategy.position_size > 0 ? s3 : na, title = "Static 3 LONG", style = plot.style_linebr)
st4 = plot(strategy.opentrades > 2 and strategy.position_size > 0 ? s4 : na, title = "Static 4 LONG", style = plot.style_linebr)
st5 = plot(strategy.opentrades > 3 and strategy.position_size > 0 ? s5 : na, title = "Static 5 LONG", style = plot.style_linebr)
st6 = plot(strategy.opentrades > 4 and strategy.position_size > 0 ? s6 : na, title = "Static 6 LONG", style = plot.style_linebr)

bot_color = input.color(title = "Static LONG Levels Color", defval = color.blue)

fill(st2, st3, color.new(bot_color, 80))
fill(st3, st4, color.new(bot_color, 75))
fill(st4, st5, color.new(bot_color, 70))
fill(st5, st6, color.new(bot_color, 65))

// === Static SHORT Levels ===
st2s = plot(strategy.opentrades > 0 and strategy.position_size < 0 ? s2s : na, title = "Static 2 SHORT", style = plot.style_linebr, color = color.new(color.red, 0))
st3s = plot(strategy.opentrades > 1 and strategy.position_size < 0 ? s3s : na, title = "Static 3 SHORT", style = plot.style_linebr, color = color.new(color.red, 0))
st4s = plot(strategy.opentrades > 2 and strategy.position_size < 0 ? s4s : na, title = "Static 4 SHORT", style = plot.style_linebr, color = color.new(color.red, 0))
st5s = plot(strategy.opentrades > 3 and strategy.position_size < 0 ? s5s : na, title = "Static 5 SHORT", style = plot.style_linebr, color = color.new(color.red, 0))
st6s = plot(strategy.opentrades > 4 and strategy.position_size < 0 ? s6s : na, title = "Static 6 SHORT", style = plot.style_linebr, color = color.new(color.red, 0))

fill(st2s, st3s, color.new(color.red, 80))
fill(st3s, st4s, color.new(color.red, 75))
fill(st4s, st5s, color.new(color.red, 70))
fill(st5s, st6s, color.new(color.red, 65))

// === Mini Table ===
if show_small_table
    sum_qty     = strategy.position_size
    sum_usd     = sum_qty * close
    open_trades = strategy.opentrades
    open_pnl    = strategy.openprofit
    eq          = strategy.equity

    var table mini = table.new(position.top_right, 5, 1, bgcolor = na)

    table.cell(mini, 0, 0, "Qty: "    + str.tostring(sum_qty),                  text_color = color.white)
    table.cell(mini, 1, 0, "USD: "    + str.tostring(sum_usd,  format.mintick), text_color = color.white)
    table.cell(mini, 2, 0, "Trades: " + str.tostring(open_trades),              text_color = color.white)
    table.cell(mini, 3, 0, "PnL: "    + str.tostring(open_pnl, format.mintick), text_color = open_pnl >= 0 ? color.green : color.red)
    table.cell(mini, 4, 0, "Equity: " + str.tostring(eq,       format.mintick), text_color = eq >= 0 ? color.green : color.red)
Editor is loading...
Leave a Comment