How exactly does trail_price, trail_offset work in pinescript?
Asked Answered
M

1

6

Thank you all for your help so far. I have been coding many different strategies in pinescript so far, and I have read through pinescript manual and many google articles, but I am still confused as to how trailing stop work in pinescript.

For instance, for strategy.exit, I have a trail_price that marks the entry for trailing stop to activate. However, all my backtesting indicates that the trailing stops at the high of that specific candle bar, even if the trail_offset has not been hit. Is it just due to the fact that tradeview backtesting assumes that maximum profit is reached in one candle bar, even if subsequent candle bars continue to go in the direction you are aiming for?

For instance, here is an example of my strategy.exit. Strategy.exit("long_TP", "long", trail_price = entry_price + ATR, trail_offset = ATR, stop= entry_price - ATR). I noticed that I would earn 2x to 3x the trail_offset (in this case based off ATR, i.e., if ATR is 50 pips, I would earn 100 or even 150 pips), as long as the profit is taken before the close of that specific candle bar. Any subsequent candle bars, even if going long, and even if the trail_offset stop loss is not hit, is not taken into calculation (i.e., even if my ATR is 50 pips, I might earn 70 pips when the candle bar closes, even if subsequent candle bars continue to go long).

Are my assumptions incorrect (i.e., my code), or is this simply a limit of backtesting, since the program cannot know what is going inside the candle bar and only know the high, low, open, and close? However, I do wonder about this, because sometimes the trail_offset is not reached even with the low of the candle bar, so theoretically profits should continue to accumulate, not stopped out after the candle bar has closed.

Edit: I have added some more info for clarification- Here is a sample code with some explanation:

If condition == true
long = strategy.position_size[0] > strategy.position_size[1]  //go long if there is order entry
entry_price_long = valuewhen(long, open, 0) //entry price is the opening price, based off the closing price of the previous candle if condition is fulfilled
atr_long = valuewhen(long, atr, 0) //stop loss and 1st take profit based off the number of pips depending on average true range, period 14
long_TP = entry_price_long + atr_long //1st take profit limit
long_SL = entry_price_long - atr_long //stop loss

strategy.entry("long", strategy.long, when=go_long, comment="long", qty=positionSize) //enter a long position when condition fulfilled
if strategy.position_size[0] > strategy.position_size[1]
   strategy.exit("long_TP", "long", trail_price=long_TP, trail_offset=atr_long, stop=long_SL) //this is where I am confused. 

My strategy.exit states that long position is exited if the initial stop loss is hit. But if the market goes long as hoped, trailing stop is activated when the 1st take profit limit is hit, defined by the trail_price. The trail_offset (in # of pips) is based off the ATR. So if the trail_price is hit, profit should continually be taken with a trailing stop. But what happens in reality is that profit is taken as far as the high of that specific candle where I entered the trade. I have attached a picture for reference. Reference pic In the picture, we see that the 1st profit limit was reached and thus trailing is activated. The ATR was around 150 pips, so the distance from the entry price to the profit limit is around 150 pips. The trailing stop is set as ATR, so once the 1st profit limit is reached (profit=150pips), theoretically the trade should continue to take profit until the trailing stop is hit. But in the picture we see that in reality my position exited once the high of the candle is hit, without taking any further profits despite the continual uptrend (final profit=181pips). Why is this?

Thanks again for helping out. Thomas

Misname answered 22/1, 2021 at 4:45 Comment(5)
Could you post compilable script example demonstrating the problem?Trimetric
@AndreyD I have updated the question with some clarification. Thanks for commenting.Misname
I suggest to debug the problem with plots: add plot(long_TP), plot(long_SL), plot(atr_long) to the strategy and you can check correctness of strategy.exit parameters.Trimetric
@Misname did you set calc_on_every_tick=true or calc_on_every_tick=false or not set ? if set "on" , your results are normal I guess because it will reach the price to exit on the green candle, whereas if calc_on_every_tick=false or not set, it will wait for candle close price (this setting is not testable in backtest, only in realtime)Peppel
I have the same problem. I had overlooked that "trail_points" is specified in TICKS. From the manual: "(series int/float) An optional parameter. Trailing stop activation level (profit specified in ticks)." I did not have time to test it out in detail, though.Albritton
A
0

I am not sure if you had the same problem like me, but in my case I had overlooked that trail_offset must be specified in ticks! My example is surely not exemplary code, but it illustrates the solution. Key points:

  • Get syminfo.mintick (this seems to be the tick size in v5) and use it to calculate a tickFactor.
  • Set trailOffset to a value that makes intuitive sense when looking at the chart, 2 Yen in this case (using USDJPY as a symbol).
  • Set trail_offset as trailOffset * tickFactor. <<=== THIS!
  • A green line marks the level that triggers the activation of the trailing stop.
  • A red line shows the trailing stop.
  • Change the entry condition on line 18 as needed. The example looked interesting at the time of writing (2023-09-04).

Here is the Pine Script:

//@version=5
// Try it on USDJPY
strategy("Trailing Stop Example", overlay=true)

varip float calculatedTrailingStop = na

tickSize = syminfo.mintick
tickFactor = 1/tickSize

if barstate.islastconfirmedhistory
    label.new(bar_index, high, "Tick Size (mintick): " + str.tostring(tickSize), yloc = yloc.abovebar, textcolor = color.white)

entryPrice = 140
trailPrice = entryPrice * 1.01
trailOffset = 2 // 2 Yen trailing stop

// Simulate a long entry order
if bar_index == last_bar_index - 80
    strategy.entry("Long", strategy.long)

// Simulate a trailing stop order
strategy.exit("Trailing Stop", "Long", trail_price = trailPrice, trail_offset = trailOffset*tickFactor)

if strategy.position_size > 0
    calculatedTrailingStop := math.max(high - trailOffset, na(calculatedTrailingStop) ? 0 : calculatedTrailingStop)
else
    calculatedTrailingStop := na

// Plot the trailing stop activation level
plot(strategy.position_size > 0 ? trailPrice : na, color = color.green, style = plot.style_line)
// Plot the trailing stop price
plot(calculatedTrailingStop, color = color.red, style = plot.style_line)
Albritton answered 4/9, 2023 at 19:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.