nop
nop

Reputation: 6321

Managing longs and short orders like LucF PineCoders Backtesting-Trading Engine

I'm trying to accomplish trade direction (Long/Short/Both) in study mode, just like LucF and PineCoders did here.

Issues:

I said overengineered, because his code includes pyramiding, slippage and other stuff that are now built-in TradingView, probably because back in 2019, PineScript didn't have such features.

The actual idea behind that indicator is to plot alerts and another script which backtests it using that indicator as a source.

//@version=4
//@author=TeamTrading1
study("Futures Strategy", overlay = true, precision = 6)

// —————————— Constants {

// ————— Input options
var string ON  = "On"
var string OFF = "Off"

var string TD1 = "Both"
var string TD2 = "Longs Only"
var string TD3 = "Shorts Only"

// ————— Color constants
var color C_AQUA        = #0080FFff
var color C_BLACK       = #000000ff
var color C_BLUE        = #013BCAff
var color C_CORAL       = #FF8080ff
var color C_GOLD        = #CCCC00ff
var color C_GRAY        = #808080ff
var color C_DARK_GREEN  = #006400ff
var color C_GREEN       = #008000ff
var color C_LIME        = #00FF00ff
var color C_MAROON      = #800000ff
var color C_ORANGE      = #FF8000ff
var color C_PINK        = #FF0080ff
var color C_DARK_RED    = #8B0000ff
var color C_RED         = #FF0000ff
var color C_VIOLET      = #AA00FFff
var color C_YELLOW      = #FFFF00ff
var color C_WHITE       = #FFFFFFff
var color C_UPTREND     = color.new(color.green, 80)
var color C_DOWNTREND   = color.new(color.red, 80)
var color C_HARDEXIT    = color.new(color.maroon, 25)
// }

// —————————— Inputs {

// ————— Entries
var string GP1 = "Entries"
string i_tradeDirection = input(TD1, "Trade Direction", options = [TD1, TD2, TD3], group = GP1)

// ————— User-selected trade directions
var bool doLongs  = (i_tradeDirection == TD2 or i_tradeDirection == TD1)
var bool doShorts = (i_tradeDirection == TD3 or i_tradeDirection == TD1)
// }

// —————————— Functions {

// ————— Functions rounding OHLC to tick precision
f_roundedToTickOHLC() =>
    float _op = round(open  / syminfo.mintick) * syminfo.mintick
    float _hi = round(high  / syminfo.mintick) * syminfo.mintick
    float _lo = round(low   / syminfo.mintick) * syminfo.mintick
    float _cl = round(close / syminfo.mintick) * syminfo.mintick
    [_op, _hi, _lo, _cl]

// ————— Function for a repainting/non-repainting version of the HTF data
f_security(_symbol, _resolution, _src, _repaint) =>
    security(_symbol, _resolution, _src[_repaint ? 0 : barstate.isrealtime ? 1 : 0])[_repaint ? 0 : barstate.isrealtime ? 0 : 1]
// }

// —————————— Calculations {

// ————— Get rounded prices
[rOpen, rHigh, rLow, rClose] = f_roundedToTickOHLC()

// ————— TV built-in MACD code
fastLength = 12
slowlength = 26
MACDLength = 9
MACD = ema(close, fastLength) - ema(close, slowlength)
aMACD = ema(MACD, MACDLength)

// ————— Filter
filterLong = MACD > 0
filterShort = MACD < 0

// ————— Entries
enterLong = crossover(MACD, 0)
enterShort = crossunder(MACD, 0)

// ————— Stops
atr = atr(14)
stopLong  = min(lowest(5), min(close, open) - atr * 1.5)
stopShort = max(highest(5), max(close, open) + atr * 1.5)

// ————— Exits
exitLong  = crossunder(MACD, aMACD) and MACD > 0
exitShort = crossover(MACD, aMACD) and MACD < 0

// ————— Determine if we have entered a trade and propagate state until we exit
longEntryTrigger = doLongs
shortEntryTrigger = doShorts

bool inLong = false
bool inShort = false

//stoppedCondition = ((inLong and rClose < InTradeStop[longEntryTrigger[1] ? 0 : 1]) or (InShort and rClose > InTradeStop[shortEntryTrigger[1] ? 0 : 1]))
exitTradeCondition = (inLong and exitLong) or (inShort and exitShort)
exitCondition = exitTradeCondition // stoppedCondition or exitTradeCondition

inLong := longEntryTrigger[1] or (inLong[1] and not exitCondition[1])
inShort := shortEntryTrigger[1] or (inShort[1] and not exitCondition[1])

entryPrice = valuewhen(enterLong or enterShort, close, 0)

// }

// —————————— Plots {

// ————— Trend Background Colors
bgcolor(filterLong ? C_UPTREND : filterShort ? C_DOWNTREND : na, title = "Trend Background Colors")

// Entry Price Colors
plot(entryPrice, title = "Entry Price", color = color.blue, style = plot.style_circles, linewidth = 2)

// Hard Exit Colors
plot(stopLong, title = "Hard Exit Price", color = color.orange, style = plot.style_circles, linewidth = 2)

// ————— Entry Background Colors
plotshape(enterLong, title = "Main BUY", style = shape.triangleup, location = location.belowbar, color = color.green, size = size.large)
plotshape(enterShort, title = "Main SELL", style = shape.triangledown, location = location.abovebar, color = color.red, size = size.large)
plotshape(exitLong, title = "Close BUY", style = shape.diamond, location = location.abovebar, color = color.green, size = size.large)
plotshape(exitShort, title = "Close SELL", style = shape.diamond, location = location.belowbar, color = color.red, size = size.large)

// entry price = lime colored
// gray when not in a trade
// dark green when the candle close is below the entry price (in a loss)
// light green when the candle close is above the entry price (in a win position)
// dark red when the candle close is above the entry price (in a loss)
// light red when the candle close is below the entry price (in a win position)
var color c = na

// if signal == 0
//     c := c_NOT_IN_TRADE
// if signal == 1 and close < entryPrice
//     c := c_LONG_ABOVE_ENTRYPRICE
// else if signal == 1 and close > entryPrice
//     c := c_LONG_BELOW_ENTRYPRICE
// else if signal == -1 and close > entryPrice
//     c := c_SHORT_BELOW_ENTRYPRICE
// else if signal == -1 and close < entryPrice
//     c := c_SHORT_ABOVE_ENTRYPRICE

// barcolor(c, title = "Trade State Bar Coloring")

// —————————— Alerts {
alertcondition(enterLong, title = "Buy Alert", message = "Buy Alert")
alertcondition(enterShort, title = "Sell Alert", message = "Sell Alert")
alertcondition(exitLong, title = "Buy Alert", message = "Buy Alert")
alertcondition(exitShort, title = "Sell Alert", message = "Sell Alert")
// }

Upvotes: 0

Views: 472

Answers (1)

PineCoders-LucF
PineCoders-LucF

Reputation: 8779

This will get you started. We:

  • Follow the states of shorts/longs, which makes it possible to plot stop and entry levels only when we are in a trade.
  • Made the doLongs/doShorts inputs part of the entry conditions.
  • Added the breach of stops to the exit conditions.

Note that this logic does not replicate that of the Engine, as here you are entering on closes, whereas the Engine is entering on the next bar following the detection of the entry/exit conditions, which is more realistic. You can also adapt your code to proceed that way:

//@version=4
//@author=TeamTrading1
study("Futures Strategy", overlay = true, precision = 6)

// —————————— Constants {

// ————— Input options
var string ON  = "On"
var string OFF = "Off"

var string TD1 = "Both"
var string TD2 = "Longs Only"
var string TD3 = "Shorts Only"

// ————— Color constants
var color C_AQUA        = #0080FFff
var color C_BLACK       = #000000ff
var color C_BLUE        = #013BCAff
var color C_CORAL       = #FF8080ff
var color C_GOLD        = #CCCC00ff
var color C_GRAY        = #808080ff
var color C_DARK_GREEN  = #006400ff
var color C_GREEN       = #008000ff
var color C_LIME        = #00FF00ff
var color C_MAROON      = #800000ff
var color C_ORANGE      = #FF8000ff
var color C_PINK        = #FF0080ff
var color C_DARK_RED    = #8B0000ff
var color C_RED         = #FF0000ff
var color C_VIOLET      = #AA00FFff
var color C_YELLOW      = #FFFF00ff
var color C_WHITE       = #FFFFFFff
var color C_UPTREND     = color.new(color.green, 80)
var color C_DOWNTREND   = color.new(color.red, 80)
var color C_HARDEXIT    = color.new(color.maroon, 25)
// }

// —————————— Inputs {

// ————— Entries
var string GP1 = "Entries"
string i_tradeDirection = input(TD1, "Trade Direction", options = [TD1, TD2, TD3], group = GP1)

// ————— User-selected trade directions
var bool doLongs  = (i_tradeDirection == TD2 or i_tradeDirection == TD1)
var bool doShorts = (i_tradeDirection == TD3 or i_tradeDirection == TD1)
// }

// —————————— Functions {

// ————— Functions rounding OHLC to tick precision
f_roundedToTickOHLC() =>
    float _op = round(open  / syminfo.mintick) * syminfo.mintick
    float _hi = round(high  / syminfo.mintick) * syminfo.mintick
    float _lo = round(low   / syminfo.mintick) * syminfo.mintick
    float _cl = round(close / syminfo.mintick) * syminfo.mintick
    [_op, _hi, _lo, _cl]

// ————— Function for a repainting/non-repainting version of the HTF data
f_security(_symbol, _resolution, _src, _repaint) =>
    security(_symbol, _resolution, _src[_repaint ? 0 : barstate.isrealtime ? 1 : 0])[_repaint ? 0 : barstate.isrealtime ? 0 : 1]
// }

// —————————— Calculations {

// ————— Get rounded prices
[rOpen, rHigh, rLow, rClose] = f_roundedToTickOHLC()

// ————— TV built-in MACD code
fastLength = 12
slowlength = 26
MACDLength = 9
MACD = ema(close, fastLength) - ema(close, slowlength)
aMACD = ema(MACD, MACDLength)

// ————— Filter
filterLong = MACD > 0
filterShort = MACD < 0

// ————— States
var float entryPrice = na
var bool inLong = false
var bool inShort = false
bool inTrade = inLong or inShort

// ————— Entries
enterLong  = doLongs  and not inTrade and crossover(MACD, 0)
enterShort = doShorts and not inTrade and crossunder(MACD, 0)

// ————— Stops
atr = atr(14)
stopLong  = min(lowest(5), min(close, open) - atr * 1.5)
stopShort = max(highest(5), max(close, open) + atr * 1.5)

// ————— Exits
exitLong  = inLong  and ((crossunder(MACD, aMACD) and MACD > 0) or close < stopLong[1])
exitShort = inShort and ((crossover(MACD, aMACD) and MACD < 0)  or close > stopShort[1])

if enterLong
    inLong := true
    entryPrice := close
else if enterShort
    inShort := true
    entryPrice := close
else if exitLong
    inLong := false
    entryPrice := na
else if exitShort
    inShort := false
    entryPrice := na

// }



// —————————— Plots {

// ————— Trend Background Colors
bgcolor(filterLong ? C_UPTREND : filterShort ? C_DOWNTREND : na, title = "Trend Background Colors")

// Entry Price Colors
plot(entryPrice, title = "Entry Price", color = color.blue, style = plot.style_circles, linewidth = 2)

// Hard Exit Colors
plot(inLong ? stopLong : inShort ? stopShort : na, title = "Hard Exit Price", color = color.orange, style = plot.style_circles, linewidth = 2)

// ————— Entry Background Colors
plotshape(enterLong, title = "Main BUY", style = shape.triangleup, location = location.belowbar, color = color.green, size = size.large)
plotshape(enterShort, title = "Main SELL", style = shape.triangledown, location = location.abovebar, color = color.red, size = size.large)
plotshape(exitLong, title = "Close BUY", style = shape.diamond, location = location.abovebar, color = color.green, size = size.large)
plotshape(exitShort, title = "Close SELL", style = shape.diamond, location = location.belowbar, color = color.red, size = size.large)

// —————————— Alerts {
alertcondition(enterLong, title = "Buy Alert", message = "Buy Alert")
alertcondition(enterShort, title = "Sell Alert", message = "Sell Alert")
alertcondition(exitLong, title = "Buy Alert", message = "Buy Alert")
alertcondition(exitShort, title = "Sell Alert", message = "Sell Alert")
// }

Upvotes: 1

Related Questions