ProRealCode - Trading & Coding with ProRealTime™
Great snippet Roberto. But . . . am I wrong that this code still allows for a loss, even if the Trailing Stop has been in positive area already? The screen capture should help here. On the far left is the position entry, white line gives entry price, red line is initial StopLoss. The orange circle is where the Trailing Stop enters the positive area for the first time. And since the candle close is above this level, it will be a Stop order. We feel safe. But at the next step of the Trailing Stop, due to a bigger Step size, we end up above the candle close, blue circle. This time, therefore, it will be a Limit order. If price will go down from now on, we will end up at the original StopLoss! That should not happen, given that we already decided once to trail into positive area. Maybe a “set stop …” in stead of the pending stop orders (dying at the end of the candle) would be better, it is like lifting the thin red line (original StopLoss) to the level of the thick red line in the capture.
@Roberto I found an exemple of a situation where indeed the returning of the price resulted in a loss, despite the Trailing already adjusted several times in positive area. So when flipping from Stop Order to Limit Order, I think it is necessary to adjust the level of the original StopLoss.
Can you post the whole code, or the link to my snippet?
Sure. The code is identical to your original snippet. Only the settings of StartPercentageLong etc. are modified by me, to fit with MicroGold futures.
Forgot to notice: there is also the situation that the first Trailing is immediately a Limit type of order. In that case there is no previous Trailing Stop order in the positive. Do you accept that price can return to the original StopLoss, or do you “invent” a safety net at for instance halfway current close and entry price?
Replace this line:
StepPerCent = 0.01 //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)
with this one:
StepPerCent = 50 //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)
or 20, etc…
The value 0.01 is so tiny that it raises issues in calculations.
Hello @Roberto. My guess is that you checked another version than the one I attached to my post. The attached version has the following section for Trailing stop settings:
StartPerCentLong = 0.25 //0.25% to start triggering Trailing Stop
StartPerCentShort = 0.20
StepPerCent = 0.15 //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 = 0.03 //0.1-1 Profit percentage to keep when setting BreakEven
PerCentInc = 0.1 // 0.1-1 PerCent increment after each StepSize chunk
In your original version, Il-Mio-Sistema3.itf, StepPerCent is set to 0.5 (according to the comment this means 50%). I lowered this to 0.15, not 0.01. But whatever value you enter here, this doesn’t prevent the problem I mentioned. So let’s forget about calculation issues.
The problem is a design problem, and here follows the code that causes it:
IF close >= SellPrice THEN
SELL AT SellPrice STOP
ELSE
SELL AT SellPrice LIMIT
ENDIF
As long as “close >= SellPrice” you’re safe, a Stop order is issued in positive area, once Trailing has been activated of course. But … if “close < SellPrice”, and this can happen (!), the Stop order is no longer re-animated at candle end, but a Limit order is issued above current price. There is no longer a Stop order in positive area to prevent the price from falling back to the original StopLoss (the biggest loss allowed per trade).
Sending a Limit order alone to the broker is not enough. There has to be a Stop order in positive area also. You could use the most recent Stop order. But in case the first Trailing stop is immediately a Limit order, you have to come up with another idea (half the limit value, half the close value???)
Have another look at my last screen capture, should clarify what I am trying to express here. Afraid I wasn’t clear the first time.
I used the file you attached to your post.
Anyway, I’ll check again tomorrow, but to make a thorough check, please attach again the sane ITF file you used and tell me the instrument, date and time of an incorrect trade.
As requested, itf and another screen capture of a losing trade after activation of trailing.
Date and time of trade: 2025-07-11 @ 17:39:00
Instrument: MicroGold 1025, future with IB.
The current code allows for this to happen. But I am pretty sure that this is not what you want to happen.
I don’t have IB, sorry. I can only test with IG and PRT.
In any case, I will do my utmost to find where your issue may come from.
I’ll be back to you next Monday.
I slightly modified the code, try this one (I am also attaching the ITF file):
SL = 30
TP = SL * 10
Sma = average[50,0](close)
IF close CROSSES OVER Sma and Not OnMarket THEN
BUY at Market
ELSIF close CROSSES UNDER Sma and Not OnMarket THEN
SELLSHORT at Market
ENDIF
SET STOP pLOSS SL
SET TARGET pPROFIT TP
//
//------------------------------------------------------------------------------------------------------------------------------------------------
// Trailing Start
//------------------------------------------------------------------------------------------------------------------------------------------------
If 1 = 1 then
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.25 //0.25% to start triggering Trailing Stop
StartPerCentShort = 0.20
StepPerCent = 0.15 //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 = 0.03 //0.1-1 Profit percentage to keep when setting BreakEven
PerCentInc = 0.1 // 0.1-1 PerCent increment after each StepSize chunk
//
TrailStartLong = (close / PipSize) * StartPerCentLong / 100 //use current price (CLOSE) for calculations
TrailStartShort = (close / PipSize) * StartPerCentShort / 100 //use current price (CLOSE) for calculations
StepSizeLong = TrailStartLong * StepPerCent / 100
StepSizeShort = TrailStartShort * StepPerCent / 100
//
RoundTO = -0.5 //-0.5 rounds always to Lower integer, +0.4 rounds always to Higher integer, 0 defaults PRT behaviour
PriceDistance = 8 * pipsize //7 minimun distance from current price
y1 = 0 //reset to 0
y2 = 0 //reset to 0
ProfitPerCent = BasePerCent //reset to desired default value
//PositionCount = 0
SellPrice = 0
SellPriceX = 0
ExitPrice = 9999999
ExitPriceX = 9999999
ELSE
//------------------------------------------------------
// --- 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 trailing
IF PositionPrice <> PositionPrice[1] AND (ExitPrice + SellPrice) <> 9999999 then//9999999 THEN //go on only if Trailing Stop had already started trailing
IF LongOnMarket THEN
q1 = PositionPrice + ((Close - PositionPrice) * ProfitPerCent) //calculate new SL
SellPriceX = 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 one
ELSIF ShortOnMarket THEN
r1 = PositionPrice - ((PositionPrice - Close) * ProfitPerCent) //calculate new SL
ExitPriceX = 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 one
ENDIF
ENDIF
// --- Update END
ENDIF
//
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 pips
IF x1 >= TrailStartLong THEN // go ahead only if N+ pips
Diff1 = abs(TrailStartLong - x1) //difference from current profit and TrailStart
Chunks1 = max(0,round((Diff1 / StepSizeLong) + RoundTO)) //number of STEPSIZE chunks
ProfitPerCent = BasePerCent + (BasePerCent * (Chunks1 * PerCentInc)) //compute new size of ProfitPerCent
ProfitPerCent = max(ProfitPerCent[1],min(100,ProfitPerCent)) //make sure ProfitPerCent doess not exceed 100%
y1 = max(x1 * ProfitPerCent, y1) //y1 = % of max profit)
ENDIF
ELSIF 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 pips
IF x2 >= TrailStartShort THEN // go ahead only if N+ pips
Diff2 = abs(TrailStartShort - x2) //difference from current profit and TrailStart
Chunks2 = max(0,round((Diff2 / StepSizeShort) + RoundTO)) //number of STEPSIZE chunks
ProfitPerCent = BasePerCent + (BasePerCent * (Chunks2 * PerCentInc)) //compute new size of ProfitPerCent
ProfitPerCent = max(ProfitPerCent[1],min(100,ProfitPerCent)) //make sure ProfitPerCent doess not exceed 100%
y2 = max(x2 * ProfitPerCent, y2) //y2 = % of max profit
ENDIF
ENDIF
//------------------------------------------------------------------------------
// 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 THEN
SELL AT SellPrice STOP
ELSE
SELL AT SellPrice LIMIT
ENDIF
ELSE
//
//sell AT MARKET when EXITPRICE does not meet the broker's minimun distance from current price
//
SELL AT Market
ENDIF
ENDIF
IF 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 THEN
EXITSHORT AT ExitPrice STOP
ELSE
EXITSHORT AT ExitPrice LIMIT
ENDIF
ELSE
//
//ExitShort AT MARKET when EXITPRICE does not meet the broker's minimun distance from current price
//
EXITSHORT AT Market
ENDIF
ENDIF
Endif
//
//EntryPrice = TradePrice
//IF Not OnMarket THEN
//EntryPrice = 0
//StopPrice = 0
//TargetPrice = 0
//TrailPrice = 0
//ENDIF
//IF LongOnMarket THEN
//StopPrice = EntryPrice - (SL * PipSize)
//TargetPrice = EntryPrice + (TP * PipSize)
//TrailPrice = SellPrice
//ELSIF ShortOnMarket THEN
//StopPrice = EntryPrice + (SL * PipSize)
//TargetPrice = EntryPrice - (TP * PipSize)
//TrailPrice = ExitPrice
//ENDIF
//IF OnMarket THEN
//graphonprice TradePrice coloured("white")
//graphonprice StopPrice coloured("red")
//graphonprice TargetPrice coloured("green")
//graphonprice TrailPrice coloured("cyan")
//ENDIF
//graph TrailStartLong
//graph x1
//graph y1
//graph ((PositionPerf * PositionPrice) / PipSize) AS "tempGAIN"
Thanks for the effort @Roberto. But I am not sure you sent the right version. This ….WW.itf is slightly different from the ….W.itf I sent you. Only some comments are modified (lines 55 and 79) and some blanks have been added in formulas to align “=”s and “*”s on consecutive lines (lines 29 and 32). And at the end all is commented out that only served for displaying levels with graphonprice commands, not affecting calculations at all. So, the results of …WW and …W are identical, problem still there.
The problem will be there as long as the following part of the code stays the same, because when switching to Limit orders, there currently is no remaining Stop order to protect against return to negative areas.
IF close >= SellPrice THEN
SELL AT SellPrice STOP
ELSE
SELL AT SellPrice LIMIT
MAINTAIN SAFETYNET // <--- HAS TO BE ADDED
ENDIF
I fixed the problem @Roberto! The solution requires a variable StopIssued that has to be reset at every new position (like your Y1, y2 etc.). And next to that some code to detect whether the Limit order has been preceded by Trailing Stop Order(s) or not. If preceded by at least 1 Stop order, we retain the last Stop level as a SafetyNet. If not preceded by a Stop order, we have to invent our own SafetNet level. I have chosen to pick the level halfway tradeprice and the Limit order. The variable safetyMult (from Multiplier) allows to optimise this value if you wish. I just set it at 0.5, meaning halfway.
For Longs the code is:
IF close >= SellPrice THEN
SELL AT SellPrice STOP
StopIssued = StopIssued + 1 // WM: Count number of Stop levels issued
SafetyNet = SellPrice // WM: Retain most recent Stop level
ELSE
SELL AT SellPrice LIMIT
if StopIssued = 0 then // WM: No previous Trailing STOP orders
SafetyNet = PositionPrice + safetyMult * (SellPrice - PositionPrice) // WM: Halfway entry and limit level
endif
sell at SafetyNet stop
ENDIF
See the 2 screen captures for both situations, Limit order preceded by Stop and immediate Limit order. The example with the preceding Stop order would have reached the original StopLoss without the SafetyNet adaptation! The .ITF is attached also.
Hi @Roberto, did you have a chance to verify my solution?
For me it works, no more negative results after Trailing has been triggered.
I found the issue (see Robertos-Trailing-PercentageWW).
It’s in these two lines:
SellPrice = max(SellPrice,PositionPrice + (y1 * pipsize))
ExitPrice = min(ExitPrice,PositionPrice - (y2 * pipsize))
because, sometimes the trailing stop EXCEEDED the current price, which should never be, as it might turn out that it’s never triggered and a loss is incurred in case the price retraces!
So just modify those two lines as follows, to make sure the current price (CLOSE) is never, ever, exceeded:
SellPrice = min(close,max(SellPrice,PositionPrice + (y1 * pipsize)))
ExitPrice = max(close,min(ExitPrice,PositionPrice - (y2 * pipsize)))
BreakEven & Trailing Profit: complete function
This topic contains 137 replies,
has 23 voices, and was last updated by Wim
5 months, 1 week ago.
| Forum: | ProOrder support |
| Language: | English |
| Started: | 03/18/2019 |
| Status: | Active |
| Attachments: | 25 files |
The information collected on this form is stored in a computer file by ProRealCode to create and access your ProRealCode profile. This data is kept in a secure database for the duration of the member's membership. They will be kept as long as you use our services and will be automatically deleted after 3 years of inactivity. Your personal data is used to create your private profile on ProRealCode. This data is maintained by SAS ProRealCode, 407 rue Freycinet, 59151 Arleux, France. If you subscribe to our newsletters, your email address is provided to our service provider "MailChimp" located in the United States, with whom we have signed a confidentiality agreement. This company is also compliant with the EU/Swiss Privacy Shield, and the GDPR. For any request for correction or deletion concerning your data, you can directly contact the ProRealCode team by email at privacy@prorealcode.com If you would like to lodge a complaint regarding the use of your personal data, you can contact your data protection supervisory authority.