Strategy Code Example - Risk Management


For my own future reference, and for anyone else who needs it.

Pine script strategy code can be confusing and awkward, so I finally sat down and had a little think about it and put something together that actually works (i think...)

Code is commented where I felt might be necessary (pretty much everything..) and covers:
  • Take Profit
  • Stop Loss
  • Trailing Stop
  • Trailing Stop Offset
...and details how to handle the input values for these in a way that allows them to be disabled if set to 0, without breaking the strategy.exit functionality or requiring a silly amount of statement nesting.

Also shows how to use functions (or variables/series) to execute trade entries and exits.

Remove from Favorite Scripts Add to Favorite Scripts

strategy(title = "Strategy Code Example", shorttitle = "Strategy Code Example", overlay = true, pyramiding = 0, default_qty_type = strategy.percent_of_equity, default_qty_value = 10, currency = currency.GBP)

// Revision:        1
// Author:          @JayRogers

// short ma
maFastSource   = input(defval = open, title = "Fast MA Source")
maFastLength   = input(defval = 14, title = "Fast MA Period", minval = 1)
// long ma
maSlowSource   = input(defval = open, title = "Slow MA Source")
maSlowLength   = input(defval = 21, title = "Slow MA Period", minval = 1)

tradeInvert     = input(defval = false, title = "Invert Trade Direction?")
// the risk management inputs
inpTakeProfit   = input(defval = 1000, title = "Take Profit", minval = 0)
inpStopLoss     = input(defval = 200, title = "Stop Loss", minval = 0)
inpTrailStop    = input(defval = 200, title = "Trailing Stop Loss", minval = 0)
inpTrailOffset  = input(defval = 0, title = "Trailing Stop Loss Offset", minval = 0)

// if an input is less than 1, assuming not wanted so we assign 'na' value to disable it.
useTakeProfit   = inpTakeProfit  >= 1 ? inpTakeProfit  : na
useStopLoss     = inpStopLoss    >= 1 ? inpStopLoss    : na
useTrailStop    = inpTrailStop   >= 1 ? inpTrailStop   : na
useTrailOffset  = inpTrailOffset >= 1 ? inpTrailOffset : na

// === SERIES SETUP ===
/// a couple of ma's..
maFast = ema(maFastSource, maFastLength)
maSlow = ema(maSlowSource, maSlowLength)

// === PLOTTING ===
fast = plot(maFast, title = "Fast MA", color = green, linewidth = 2, style = line, transp = 50)
slow = plot(maSlow, title = "Slow MA", color = red, linewidth = 2, style = line, transp = 50)

// === LOGIC ===
// is fast ma above slow ma?
aboveBelow = maFast >= maSlow ? true : false
// are we inverting our trade direction?
tradeDirection = tradeInvert ? aboveBelow ? false : true : aboveBelow ? true : false

enterLong() => not tradeDirection[1] and tradeDirection // functions can be used to wrap up and work out complex conditions
exitLong() => tradeDirection[1] and not tradeDirection
strategy.entry(id = "Long", long = true, when = enterLong()) // use function or simple condition to decide when to get in
strategy.close(id = "Long", when = exitLong()) // ...and when to get out
enterShort() => tradeDirection[1] and not tradeDirection
exitShort() => not tradeDirection[1] and tradeDirection
strategy.entry(id = "Short", long = false, when = enterShort())
strategy.close(id = "Short", when = exitShort())

// finally, make use of all the earlier values we got prepped
strategy.exit("Exit Long", from_entry = "Long", profit = useTakeProfit, loss = useStopLoss, trail_points = useTrailStop, trail_offset = useTrailOffset)
strategy.exit("Exit Short", from_entry = "Short", profit = useTakeProfit, loss = useStopLoss, trail_points = useTrailStop, trail_offset = useTrailOffset)
This trailing stop is massively flawed. If you have a 20 pip trailing stop, it finds the next candle whose highest (long) or lowest (short) value is greater than 20 pips, and uses that as the final value. So if you long and the next candle's high is +70 pips, then you've just profited 70 pips!
+1 Reply
Really appreciate the organization in this script. Great model.
+1 Reply
hello, what kind of function do i use in this part?
strategy.entry(id = "Long", long = true, when = enterLong()) // use function or simple condition to decide when to get in
strategy.close(id = "Long", when = exitLong()) // ...and when to get out

Im having a little trouble with the script because it duplicates some trades. Does any one know how to fix it?
Thanks a Ton man, i will remember you in my whole life..this post is my turning point in my trading journey. God Bless you!
+6 Reply
Hey do you find issues with the trailing stop in backtesting?

I find it gives a false value for the exit. If the trailing stop is triggered, it reports the trade close as either high or low of the bar, seemingly depending if you are long or short - giving wildly succesful backtest results , but false ones.

Anyone else get this?
+1 Reply
Objredline BobVanders
@BobVanders, I'm having a similar issue it sounds like:

strategy.exit("Exit long", from_entry="Long", qty = 20, stop = (close-R_value), comment = "xxx"

The problem is, say I pyramid entered in 3 times 20 shares, but only one of the pyramid entries satisfies the stop condition. The List of Trades will show all 3 pyramid entries were exited. However on the plot, it will only show one -20 qty "xxx" exit.

With trail_points and trail_offset, it is the same problem exiting the entire set of pyramid buys.

In addition with trail_points and _trail_offset, either I'm not understanding what these two parameters mean, or it's not calculating it right. I understand it as this: strategy.exit context: trail_points = 1000, trail_offset=200. As: once position is up 10%, it will sell if it then falls 2%. Can someone shed light on if this understanding is correct?
ekoronin Objredline
@Objredline, actually this is incorrect. The trailing points and the offse are calculated in ticks according to the documentation. Meaning one tick is 0.00001 in forex in 5 digit brker. Thus 1000 points is 100 pips TP, and 200 is 20 pips SL.
Hope this helps
Tick is 0.01 in JPY and stocks. But what is a tick in crypto I wonder till this same moment.... is it 0.00000001 ?
@ekoronin, Thank you. That helps a lot actually. Can you tell me where is the documentation you read that explains the ticks/pips used in forex? I didn't know that at all.

And yes, still trying to understand how it all maps to crypto.
ekoronin buffetbeijing
@buffetbeijing, the docs are available at https://www.tradingview.com/study-script-reference/
or you can ctrl-left-click on any function/variable in the PineEditor code window - it will bring up a built-in documentation window which can co-exist with the editor. Search for strategy.exit() for explanation of the trailing_points parameter as follows:
- trail_points (float) An optional parameter. Trailing stop activation level (profit specified in ticks). ...

For ticks I use syminfo.mintick in the code to correctly determine the ticks. Suppose I have a SL = high-low, then in ticks this will be SL/syminfo.mintick.
Hope this helps.

PS. I cannot make the trailing stop working for me, I think TD has implemented a slightly different concept of the trailing than generally taught, and I lack understanding thereof. I am missing what the tail_point as in stop activation level is and what is it for, as well as trail_offset?
In my mind I want to start trailing immediately with a specified SL=Y a soon as I call strategy.entry(). Or suppose I want to start trailing with Sl=Y as soon as I moved up (or down) an amount X with the Sl=Y

Can anyone give me an example that works?

In this example, I use price rather points parameters, with NaN (default) trail_offset:
stop_loss = 3*atr(5)
stop_price_buy = close - stop_loss //my stop loss price for long
strategy.exit("Exit Buy", from_entry="Buy", stop=stop_price_buy, trail_price=stop_price_buy, comment="Exit Buy SL")

My idea is I want to start trailing from the level of the initial stop loss. And the code opens and immediately closes the order , so i think I don't quite capture how to use these parameters.

In this example I use ticks rather than price
stop_loss = 3*atr(5)
strategy.exit("Exit Buy", from_entry="Buy", loss=stop_loss/syminfo.mintick, trail_points=stop_loss/syminfo.mintick, trail_offset=0, comment="Exit Buy SL")

Bu the effect is that the price moves up for the stop_loss number of ticks and takes profit, closes the order which is not what I want at all. SO I am a little confused and have to spend time experimenting with it further.
+1 Reply
jatw88 BobVanders
@BobVanders, I am still having the same problem.
EN English
EN English (UK)
EN English (IN)
DE Deutsch
FR Français
ES Español
IT Italiano
PL Polski
TR Türkçe
RU Русский
PT Português
ID Bahasa Indonesia
MS Bahasa Melayu
TH ภาษาไทย
VI Tiếng Việt
JA 日本語
KO 한국어
ZH 简体中文
ZH 繁體中文
AR العربية
Home Stock Screener Forex Signal Finder Cryptocurrency Signal Finder Economic Calendar How It Works Chart Features House Rules Moderators Website & Broker Solutions Widgets Stock Charting Library Feature Request Blog & News FAQ Help & Wiki Twitter
Profile Profile Settings Account and Billing My Support Tickets Contact Support Ideas Published Followers Following Private Messages Chat Sign Out