BreakEven & Trailing Profit: complete function
Forums › ProRealTime English forum › ProOrder support › BreakEven & Trailing Profit: complete function
- This topic has 119 replies, 22 voices, and was last updated 6 months ago by robertogozzi.
Tagged: BreakEven, Profit, stop, trailing, trailingstop
-
-
11/12/2021 at 6:41 AM #181482
It’s lines 45 and 50.
There’s no MyEquity.01/05/2022 at 3:56 PM #184646Thank you robertogozzi for this excellent code! I’ve adopt it as my new standard.
Through various backtests, I observed that with a single set of parameters, you can leave sizeable chunk of money on the table for (P10 trades) high stake trades. So, I thought of making staged parameters, i.e. parameters change after a certain level of profit to take the maximum juice. Please don’t pay attention to the performance of the System itself, it was just quick and dirty one for the test.
To test the concept, I run the simulation on 10k (1) with the original code (right hand side picture), and (2) with my suggested code below (left hand side) . We can see with the original code the sum of the difference between MFE and actual performance is 432, i.e. loss of opportunity to make another 432. On the left hand side, the same difference makes only 236. So with is a tighter trailing system after a certain threshold of gain, we generate +196 of additional profit (45% of the 432!), but gained less on certain trades, but overall we are +100 over the base case. Another side benefit is the drawdown which went from -383 to -224. This is I think a proof of concept, but optimisation needs to take place on a much larger units >100k.
Now, my coding skills are far from being perfect, so anyone who can please review the change and suggest improvements. Obviously, we can continue the serie and create Threshold1, Threshold2, etc. to reduce the difference between MFE and actual performance as the profits grow.
Staged Trailing123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145// NewTrade is true whenever a new trade is opened, be it://// - a trade when there was none previously// - a trade that has changed direction due to a Stop & Reverse (it's Long and previously was Short and viceversa)//// This will be useful to reset variables to their initial values after a trade has been opened.//NewTrade = (OnMarket AND Not OnMarket[1]) OR (LongOnMarket AND ShortOnMarket[1]) OR (LongOnMarket[1] AND ShortOnMarket)//// Reset variables to their initial value when a new trade shows//IF Not OnMarket OR NewTrade THEN //reset to default values when a new trade has been opened (or none is OnMarket)PerCentTP = 2.0 //2.0% is TPPerCentStart = 0.2 //0.2% is the Trailing Stop trigger levelPerCentStep = 0.2 //0.2% is each subsequent stepPerCentSaved = 0.1 //0.1% is how much profit has to be saved when trailing starts and every stepMultiplier = 1.5 //1.5 is how much PerCentSaved is incremented each trailing step// 1.5 is a 50% increment, so that:// 0.1% becomes 0.15%, then// 0.15% becomes 0.225%, then// 0.225% becomes 0.3375%, etc...PerCentTP1 = PerCentTP //2.0 //2.0% is TPPerCentStart1 = PerCentStart //0.2 //0.2% is the Trailing Stop trigger levelPerCentStep1 = 0.2 //0.2% is each subsequent stepPerCentSaved1 = 0.1 //0.1% is how much profit has to be saved when trailing starts and every stepMultiplier1 = 1.5 //1.5 is how much PerCentSaved is incremented each trailing stepDistance = 4//6 //6 pip distance from current price (if required by the broker)MySL = 0MySL1 = 0ProfitPerCent = 0ENDIF//// The trailing stop can operate only when OnMarket//IF OnMarket THEN//// before the trailing stop is triggered some calculations need to be done, accordin to settings//IF MySL = 0 THENPCent = PositionPrice * PerCentTP / 100PStart = PositionPrice * PerCentStart / 100PStep = PositionPrice * PerCentStep / 100PSaved = PositionPrice * PerCentSaved / 100ENDIF//// check if Trailing Stop has to be triggered//IF MySL = 0 THENIF LongOnMarket THENIF (close - PositionPrice) >= PStart THENMySL = min(close,PositionPrice + PSaved)PSaved = PSaved * MultiplierENDIFELSIF ShortOnMarket THENIF (PositionPrice - close) >= PStart THENMySL = max(close,PositionPrice - PSaved)PSaved = PSaved * MultiplierENDIFENDIFELSE//// check if another Step has been triggered//IF LongOnMarket THENIF (close - MySL) >= PStep THENMySL = min(close,MySL + PSaved)PSaved = PSaved * MultiplierENDIFELSIF ShortOnMarket THENIF (MySL - close) >= PStep THENMySL = max(close,MySL - PSaved)PSaved = PSaved * MultiplierENDIFENDIFENDIF//// place Pending STOP orders//IF MySL > 0 THENIF (MySL = close) OR (abs(MySL - close) < Distance) THEN //exit immediately in case MySL has reached// the current price or there's not enough DISTANCESELL AT MARKETEXITSHORT AT MARKETELSESELL AT MySL STOPEXITSHORT AT MySL STOPENDIFENDIF/////////IF (longonmarket and (close-tradeprice)>=limit1) or (shortonmarket and (tradeprice-close)>=limit1) thenIF MySL1 = 0 THENPCent1 = PositionPrice * PerCentTP1 / 100PStart1 = PositionPrice * PerCentStart1 / 100PStep1 = PositionPrice * PerCentStep1 / 100PSaved1 = PositionPrice * PerCentSaved1 / 100ENDIF//// check if Trailing Stop has to be triggered//IF MySL1 = 0 THENIF LongOnMarket THENIF (close - PositionPrice) >= PStart1 THENMySL1 = min(close,PositionPrice + PSaved1)PSaved1 = PSaved1 * Multiplier1ENDIFELSIF ShortOnMarket THENIF (PositionPrice - close) >= PStart1 THENMySL1 = max(close,PositionPrice - PSaved1)PSaved1 = PSaved1 * Multiplier1ENDIFENDIFELSE//// check if another Step has been triggered//IF LongOnMarket THENIF (close - MySL1) >= PStep1 THENMySL1 = min(close,MySL1 + PSaved1)PSaved1 = PSaved1 * Multiplier1ENDIFELSIF ShortOnMarket THENIF (MySL1 - close) >= PStep1 THENMySL1 = max(close,MySL1 - PSaved1)PSaved1 = PSaved1 * Multiplier1ENDIFENDIFENDIF//// place Pending STOP orders//IF MySL1 > 0 THENIF (MySL1 = close) OR (abs(MySL1 - close) < Distance) THEN //exit immediately in case MySL has reached// the current price or there's not enough DISTANCESELL AT MARKETEXITSHORT AT MARKETELSESELL AT MySL1 STOPEXITSHORT AT MySL1 STOPENDIFENDIFENDIF////////ENDIF01/06/2022 at 6:54 PM #184779Good job Khaled, it actually can be improved like any other code.
I improved mine this way:
- when the strategy takes too long to reach the target, it might mean it could soon retrace, so I added code to multiply the percentage (or the number of pips) saved by a factor of 1.2 (or 1,5, or so) every, say, 100 or 200 candles; doing so will ensure that a retracement will still end in a higher profit;
- when the profit reaches 75% target, I use another multiplier to lock in more profits.
You can think of any kind of improvement. This may imply having a trailing stop management longer more than the strategy itself, but this is not an issue in most cases.
1 user thanked author for this post.
01/21/2022 at 11:34 AM #186149I had a short position where the trailing stop never got moved yesterday and I can’t find why.
It opened at 14711.4 (close before it opened was at 14712.8), lowest close was at 14620.2 and TS was set at 0.4%.
TrailStartShort: 14712.8*0.4/100 = 58.9
14711.4-58.9 = 14652.5It should have kicked in ~30p before the lowest close. What am I missing here?
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127//------------------------------------------------------------------------------------------------------------------------------------------------// Trailing Start//------------------------------------------------------------------------------------------------------------------------------------------------DirectionSwitch = (LongOnMarket AND ShortOnMarket[1]) OR (LongOnMarket[1] AND ShortOnMarket) //True when there's been a change in the direction (likely to be due to a Stop & Reverse)//IF Not OnMarket OR DirectionSwitch THEN//// when NOT OnMarket or thare's been a change in direction, reset values to their default settings//StartPerCentLong = 0.4 //0.25% to start triggering Trailing StopStartPerCentShort = 0.4StepPerCent = 10 //50% (of the 0.25% above) as a Trailing Step (set to 100 to make StepSize=TrailStart, set to 200 to make it twice TrailStart)BasePerCent = 1.0 //0.1-1 Profit percentage to keep when setting BreakEvenPerCentInc = 0.8 // 0.1-1 PerCent increment after each StepSize chunk//TrailStartLong = (close / PipSize) * StartPerCentLong / 100 //use current price (CLOSE) for calculationsTrailStartShort = (close / PipSize) * StartPerCentShort / 100 //use current price (CLOSE) for calculationsStepSizeLong = TrailStartLong * StepPerCent / 100StepSizeShort = TrailStartShort * StepPerCent / 100//RoundTO = -0.5 //-0.5 rounds always to Lower integer, +0.4 rounds always to Higher integer, 0 defaults PRT behaviourPriceDistance = 7 * pipsize //7 minimun distance from current pricey1 = 0 //reset to 0y2 = 0 //reset to 0ProfitPerCent = BasePerCent //reset to desired default value//PositionCount = 0SellPrice = 0SellPriceX = 0ExitPrice = 9999999ExitPriceX = 9999999ELSE//------------------------------------------------------// --- Update Stop Loss after accumulating new positions//------------------------------------------------------//PositionCount = max(PositionCount,abs(CountOfPosition))//// update Stop Loss only when PositionPrice has changed (actually when increased, we don't move it if there's been some positions exited)////IF PositionCount <> PositionCount[1] AND (ExitPrice + SellPrice)<>9999999 THEN //go on only if Trailing Stop had already started trailingIF PositionPrice <> PositionPrice[1] AND (ExitPrice + SellPrice) <> 9999999 THEN //go on only if Trailing Stop had already started trailingIF LongOnMarket THENq1 = PositionPrice + ((Close - PositionPrice) * ProfitPerCent) //calculate new SLSellPriceX = max(max(SellPriceX,SellPrice),q1)SellPrice = max(max(SellPriceX,SellPrice),PositionPrice + (y1 * pipsize)) //set exit price to whatever grants greater profits, comopared to the previous oneELSIF ShortOnMarket THENr1 = PositionPrice - ((PositionPrice - Close) * ProfitPerCent) //calculate new SLExitPriceX = min(min(ExitPriceX,ExitPrice),r1)ExitPrice = min(min(ExitPriceX,ExitPrice),PositionPrice - (y2 * pipsize)) //set exit price to whatever grants greater profits, comopared to the previous oneENDIFENDIF// --- Update ENDENDIF//IF LongOnMarket AND Close > (PositionPrice + (y1 * pipsize)) THEN //LONG positions//// compute the value of the Percentage of profits, if any, to lock in for LONG trades//x1 = (Close - PositionPrice) / pipsize //convert price to pipsIF x1 >= TrailStartLong THEN // go ahead only if N+ pipsDiff1 = abs(TrailStartLong - x1) //difference from current profit and TrailStartChunks1 = max(0,round((Diff1 / StepSizeLong) + RoundTO)) //number of STEPSIZE chunksProfitPerCent = BasePerCent + (BasePerCent * (Chunks1 * PerCentInc)) //compute new size of ProfitPerCentProfitPerCent = max(ProfitPerCent[1],min(100,ProfitPerCent)) //make sure ProfitPerCent doess not exceed 100%y1 = max(x1 * ProfitPerCent, y1) //y1 = % of max profitENDIFELSIF ShortOnMarket AND Close < (PositionPrice - (y2 * pipsize)) THEN //SHORT positions//// compute the value of the Percentage of profits, if any, to lock in for SHORT trades//x2 = (PositionPrice - Close) / pipsize //convert price to pipsIF x2 >= TrailStartShort THEN // go ahead only if N+ pipsDiff2 = abs(TrailStartShort - x2) //difference from current profit and TrailStartChunks2 = max(0,round((Diff2 / StepSizeShort) + RoundTO)) //number of STEPSIZE chunksProfitPerCent = BasePerCent + (BasePerCent * (Chunks2 * PerCentInc)) //compute new size of ProfitPerCentProfitPerCent = max(ProfitPerCent[1],min(100,ProfitPerCent)) //make sure ProfitPerCent doess not exceed 100%y2 = max(x2 * ProfitPerCent, y2) //y2 = % of max profitENDIFENDIF//------------------------------------------------------------------------------// manage actual Exit, if needed//------------------------------------------------------------------------------IF y1 THEN //Place pending STOP order when y1 > 0 (LONG positions)SellPrice = max(SellPrice,PositionPrice + (y1 * pipsize)) //convert pips to price//// check the minimun distance between ExitPrice and current price//IF abs(close - SellPrice) > PriceDistance THEN//// place either a LIMIT or STOP pending order according to current price positioning//IF close >= SellPrice THENSELL AT SellPrice STOPELSESELL AT SellPrice LIMITENDIFELSE////sell AT MARKET when EXITPRICE does not meet the broker's minimun distance from current price//SELL AT MarketENDIFENDIFIF y2 THEN //Place pending STOP order when y2 > 0 (SHORT positions)ExitPrice = min(ExitPrice,PositionPrice - (y2 * pipsize)) //convert pips to price//// check the minimun distance between ExitPrice and current price//IF abs(close - ExitPrice) > PriceDistance THEN//// place either a LIMIT or STOP pending order according to current price positioning//IF close <= ExitPrice THENEXITSHORT AT ExitPrice STOPELSEEXITSHORT AT ExitPrice LIMITENDIFELSE////ExitShort AT MARKET when EXITPRICE does not meet the broker's minimun distance from current price//EXITSHORT AT MarketENDIFENDIF01/21/2022 at 12:54 PM #186177Please post the code, otherwise it’s impossible to tell.
What istrument and TF were you trading?
1 user thanked author for this post.
01/21/2022 at 2:43 PM #186195Instrument: Nasdaq
TF: 3min
TZ: UTC-5The below code will replicate it. The trade opened 20:54 US/Eastern on January 20.
But as I state in the code below, if I put “date = 20220121”, it opens the trade on 19th instead for some reason.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136defparam cumulateorders = falsedefparam preloadbars = 50000// Should be january 20, be if I put 20220120 it opens on 19th insteadif date = 20220121 and time = 205400 thensellshort 1 contract at marketset stop %loss 1.3endif//------------------------------------------------------------------------------------------------------------------------------------------------// Trailing Start//------------------------------------------------------------------------------------------------------------------------------------------------DirectionSwitch = (LongOnMarket AND ShortOnMarket[1]) OR (LongOnMarket[1] AND ShortOnMarket) //True when there's been a change in the direction (likely to be due to a Stop & Reverse)//IF Not OnMarket OR DirectionSwitch THEN//// when NOT OnMarket or thare's been a change in direction, reset values to their default settings//StartPerCentLong = 0.4 //0.25% to start triggering Trailing StopStartPerCentShort = 0.4StepPerCent = 10 //50% (of the 0.25% above) as a Trailing Step (set to 100 to make StepSize=TrailStart, set to 200 to make it twice TrailStart)BasePerCent = 1.0 //0.1-1 Profit percentage to keep when setting BreakEvenPerCentInc = 0.8 // 0.1-1 PerCent increment after each StepSize chunk//TrailStartLong = (close / PipSize) * StartPerCentLong / 100 //use current price (CLOSE) for calculationsTrailStartShort = (close / PipSize) * StartPerCentShort / 100 //use current price (CLOSE) for calculationsStepSizeLong = TrailStartLong * StepPerCent / 100StepSizeShort = TrailStartShort * StepPerCent / 100//RoundTO = -0.5 //-0.5 rounds always to Lower integer, +0.4 rounds always to Higher integer, 0 defaults PRT behaviourPriceDistance = 7 * pipsize //7 minimun distance from current pricey1 = 0 //reset to 0y2 = 0 //reset to 0ProfitPerCent = BasePerCent //reset to desired default value//PositionCount = 0SellPrice = 0SellPriceX = 0ExitPrice = 9999999ExitPriceX = 9999999ELSE//------------------------------------------------------// --- Update Stop Loss after accumulating new positions//------------------------------------------------------//PositionCount = max(PositionCount,abs(CountOfPosition))//// update Stop Loss only when PositionPrice has changed (actually when increased, we don't move it if there's been some positions exited)////IF PositionCount <> PositionCount[1] AND (ExitPrice + SellPrice)<>9999999 THEN //go on only if Trailing Stop had already started trailingIF PositionPrice <> PositionPrice[1] AND (ExitPrice + SellPrice) <> 9999999 THEN //go on only if Trailing Stop had already started trailingIF LongOnMarket THENq1 = PositionPrice + ((Close - PositionPrice) * ProfitPerCent) //calculate new SLSellPriceX = max(max(SellPriceX,SellPrice),q1)SellPrice = max(max(SellPriceX,SellPrice),PositionPrice + (y1 * pipsize)) //set exit price to whatever grants greater profits, comopared to the previous oneELSIF ShortOnMarket THENr1 = PositionPrice - ((PositionPrice - Close) * ProfitPerCent) //calculate new SLExitPriceX = min(min(ExitPriceX,ExitPrice),r1)ExitPrice = min(min(ExitPriceX,ExitPrice),PositionPrice - (y2 * pipsize)) //set exit price to whatever grants greater profits, comopared to the previous oneENDIFENDIF// --- Update ENDENDIF//IF LongOnMarket AND Close > (PositionPrice + (y1 * pipsize)) THEN //LONG positions//// compute the value of the Percentage of profits, if any, to lock in for LONG trades//x1 = (Close - PositionPrice) / pipsize //convert price to pipsIF x1 >= TrailStartLong THEN // go ahead only if N+ pipsDiff1 = abs(TrailStartLong - x1) //difference from current profit and TrailStartChunks1 = max(0,round((Diff1 / StepSizeLong) + RoundTO)) //number of STEPSIZE chunksProfitPerCent = BasePerCent + (BasePerCent * (Chunks1 * PerCentInc)) //compute new size of ProfitPerCentProfitPerCent = max(ProfitPerCent[1],min(100,ProfitPerCent)) //make sure ProfitPerCent doess not exceed 100%y1 = max(x1 * ProfitPerCent, y1) //y1 = % of max profitENDIFELSIF ShortOnMarket AND Close < (PositionPrice - (y2 * pipsize)) THEN //SHORT positions//// compute the value of the Percentage of profits, if any, to lock in for SHORT trades//x2 = (PositionPrice - Close) / pipsize //convert price to pipsIF x2 >= TrailStartShort THEN // go ahead only if N+ pipsDiff2 = abs(TrailStartShort - x2) //difference from current profit and TrailStartChunks2 = max(0,round((Diff2 / StepSizeShort) + RoundTO)) //number of STEPSIZE chunksProfitPerCent = BasePerCent + (BasePerCent * (Chunks2 * PerCentInc)) //compute new size of ProfitPerCentProfitPerCent = max(ProfitPerCent[1],min(100,ProfitPerCent)) //make sure ProfitPerCent doess not exceed 100%y2 = max(x2 * ProfitPerCent, y2) //y2 = % of max profitENDIFENDIF//------------------------------------------------------------------------------// manage actual Exit, if needed//------------------------------------------------------------------------------IF y1 THEN //Place pending STOP order when y1 > 0 (LONG positions)SellPrice = max(SellPrice,PositionPrice + (y1 * pipsize)) //convert pips to price//// check the minimun distance between ExitPrice and current price//IF abs(close - SellPrice) > PriceDistance THEN//// place either a LIMIT or STOP pending order according to current price positioning//IF close >= SellPrice THENSELL AT SellPrice STOPELSESELL AT SellPrice LIMITENDIFELSE////sell AT MARKET when EXITPRICE does not meet the broker's minimun distance from current price//SELL AT MarketENDIFENDIFIF y2 THEN //Place pending STOP order when y2 > 0 (SHORT positions)ExitPrice = min(ExitPrice,PositionPrice - (y2 * pipsize)) //convert pips to price//// check the minimun distance between ExitPrice and current price//IF abs(close - ExitPrice) > PriceDistance THEN//// place either a LIMIT or STOP pending order according to current price positioning//IF close <= ExitPrice THENEXITSHORT AT ExitPrice STOPELSEEXITSHORT AT ExitPrice LIMITENDIFELSE////ExitShort AT MARKET when EXITPRICE does not meet the broker's minimun distance from current price//EXITSHORT AT MarketENDIFENDIF01/21/2022 at 3:42 PM #186208Isn’t it line 87 above that is the culprit?
The + should be a – ?
With original +, it sets ExitPrice way past the current price.
01/21/2022 at 5:36 PM #186216Change line 23 as:
1BasePerCent = 0.1 //10% (1=100%)01/21/2022 at 5:38 PM #186217You can also append these lines:
12graphonprice ExitPrice coloured(255,0,0,255)graphonprice SellPrice coloured(0,128,0,155)to plot the trailing stop on your chart while backtesting.
01/21/2022 at 6:50 PM #186234Alright, I think I got it sorted now.
I basically wanted a quick trailing stop (almost a TP), sort of. But if you add a PerCentInc on top of a high BasePerCent, you go past the current price when it’s triggered and price have to chase the stop instead of it trailing you or going straight to an exit. That was my problem.
I also think I have misunderstood how it works, it’s quite clear now when you add the lines and tested different values.
123StartPerCent = 0.4 //0.4% to start triggering Trailing StopBasePerCent = 0.5 //50.0% Profit percentage to keep when setting BerakEvenPerCentInc = 0.5 //50.0% PerCent increment after each StepSize chunkTrailStartShort: 14712.8*0.4/100 = 58.9
14711.4-58.9 = 14652.5I thought it would keep 50% (BasePerCent) of the 58.9, so once it hits 14652.5 it sets the first SL at 14682.0. After that you factor in StepPerCent and PercentInc. But both values are used when it initially sets the SL.
For example with the example above (0.5 and 0.5). If you use “2” for StepPerCent, it sets it way past the price (see pic). 100 sets it pretty close to the +50%.
Not sure if I’m any wiser, but I now I know what the problem was 😉
1 user thanked author for this post.
02/11/2022 at 4:54 PM #18810902/11/2022 at 4:56 PM #18811002/13/2022 at 2:16 PM #188188It’s a trailing stop code snippet, what do you mean by Would it be posssible to make a version of it without trailing stoploss Only use the Limit-line (takeprofit)?
02/13/2022 at 2:34 PM #18819102/13/2022 at 5:56 PM #188196The line I marked in post #188110 is takeorofit-line and dynamic?
My guess is that you ran in to the same problem I did. If you have too high start, base and increase (in some combination), it becomes a trailing take profit after an increase.
-
AuthorPosts
Find exclusive trading pro-tools on