ProRealCode - Trading & Coding with ProRealTime™
It’s lines 45 and 50.
There’s no MyEquity.
Thank 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.
// 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 TP
PerCentStart = 0.2 //0.2% is the Trailing Stop trigger level
PerCentStep = 0.2 //0.2% is each subsequent step
PerCentSaved = 0.1 //0.1% is how much profit has to be saved when trailing starts and every step
Multiplier = 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 TP
PerCentStart1 = PerCentStart //0.2 //0.2% is the Trailing Stop trigger level
PerCentStep1 = 0.2 //0.2% is each subsequent step
PerCentSaved1 = 0.1 //0.1% is how much profit has to be saved when trailing starts and every step
Multiplier1 = 1.5 //1.5 is how much PerCentSaved is incremented each trailing step
Distance = 4//6 //6 pip distance from current price (if required by the broker)
MySL = 0
MySL1 = 0
ProfitPerCent = 0
ENDIF
//
// 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 THEN
PCent = PositionPrice * PerCentTP / 100
PStart = PositionPrice * PerCentStart / 100
PStep = PositionPrice * PerCentStep / 100
PSaved = PositionPrice * PerCentSaved / 100
ENDIF
//
// check if Trailing Stop has to be triggered
//
IF MySL = 0 THEN
IF LongOnMarket THEN
IF (close - PositionPrice) >= PStart THEN
MySL = min(close,PositionPrice + PSaved)
PSaved = PSaved * Multiplier
ENDIF
ELSIF ShortOnMarket THEN
IF (PositionPrice - close) >= PStart THEN
MySL = max(close,PositionPrice - PSaved)
PSaved = PSaved * Multiplier
ENDIF
ENDIF
ELSE
//
// check if another Step has been triggered
//
IF LongOnMarket THEN
IF (close - MySL) >= PStep THEN
MySL = min(close,MySL + PSaved)
PSaved = PSaved * Multiplier
ENDIF
ELSIF ShortOnMarket THEN
IF (MySL - close) >= PStep THEN
MySL = max(close,MySL - PSaved)
PSaved = PSaved * Multiplier
ENDIF
ENDIF
ENDIF
//
// place Pending STOP orders
//
IF MySL > 0 THEN
IF (MySL = close) OR (abs(MySL - close) < Distance) THEN //exit immediately in case MySL has reached
// the current price or there's not enough DISTANCE
SELL AT MARKET
EXITSHORT AT MARKET
ELSE
SELL AT MySL STOP
EXITSHORT AT MySL STOP
ENDIF
ENDIF
/////////
IF (longonmarket and (close-tradeprice)>=limit1) or (shortonmarket and (tradeprice-close)>=limit1) then
IF MySL1 = 0 THEN
PCent1 = PositionPrice * PerCentTP1 / 100
PStart1 = PositionPrice * PerCentStart1 / 100
PStep1 = PositionPrice * PerCentStep1 / 100
PSaved1 = PositionPrice * PerCentSaved1 / 100
ENDIF
//
// check if Trailing Stop has to be triggered
//
IF MySL1 = 0 THEN
IF LongOnMarket THEN
IF (close - PositionPrice) >= PStart1 THEN
MySL1 = min(close,PositionPrice + PSaved1)
PSaved1 = PSaved1 * Multiplier1
ENDIF
ELSIF ShortOnMarket THEN
IF (PositionPrice - close) >= PStart1 THEN
MySL1 = max(close,PositionPrice - PSaved1)
PSaved1 = PSaved1 * Multiplier1
ENDIF
ENDIF
ELSE
//
// check if another Step has been triggered
//
IF LongOnMarket THEN
IF (close - MySL1) >= PStep1 THEN
MySL1 = min(close,MySL1 + PSaved1)
PSaved1 = PSaved1 * Multiplier1
ENDIF
ELSIF ShortOnMarket THEN
IF (MySL1 - close) >= PStep1 THEN
MySL1 = max(close,MySL1 - PSaved1)
PSaved1 = PSaved1 * Multiplier1
ENDIF
ENDIF
ENDIF
//
// place Pending STOP orders
//
IF MySL1 > 0 THEN
IF (MySL1 = close) OR (abs(MySL1 - close) < Distance) THEN //exit immediately in case MySL has reached
// the current price or there's not enough DISTANCE
SELL AT MARKET
EXITSHORT AT MARKET
ELSE
SELL AT MySL1 STOP
EXITSHORT AT MySL1 STOP
ENDIF
ENDIF
ENDIF
////////
ENDIF
Good job Khaled, it actually can be improved like any other code.
I improved mine this way:
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.
I 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.5
It should have kicked in ~30p before the lowest close. What am I missing here?
//------------------------------------------------------------------------------------------------------------------------------------------------
// 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 Stop
StartPerCentShort = 0.4
StepPerCent = 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 BreakEven
PerCentInc = 0.8 // 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 = 7 * 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 //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
Please post the code, otherwise it’s impossible to tell.
What istrument and TF were you trading?
Instrument: Nasdaq
TF: 3min
TZ: UTC-5
The 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.
defparam cumulateorders = false
defparam preloadbars = 50000
// Should be january 20, be if I put 20220120 it opens on 19th instead
if date = 20220121 and time = 205400 then
sellshort 1 contract at market
set stop %loss 1.3
endif
//------------------------------------------------------------------------------------------------------------------------------------------------
// 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 Stop
StartPerCentShort = 0.4
StepPerCent = 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 BreakEven
PerCentInc = 0.8 // 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 = 7 * 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 //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
Isn’t it line 87 above that is the culprit?
The + should be a – ?
With original +, it sets ExitPrice way past the current price.
Change line 23 as:
BasePerCent = 0.1 //10% (1=100%)
You can also append these lines:
graphonprice ExitPrice coloured(255,0,0,255)
graphonprice SellPrice coloured(0,128,0,155)
to plot the trailing stop on your chart while backtesting.
Alright, 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.
StartPerCent = 0.4 //0.4% to start triggering Trailing Stop
BasePerCent = 0.5 //50.0% Profit percentage to keep when setting BerakEven
PerCentInc = 0.5 //50.0% PerCent increment after each StepSize chunk
TrailStartShort: 14712.8*0.4/100 = 58.9
14711.4-58.9 = 14652.5
I 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 😉
Thanks alot robertogozzi for ur great code.
Would it be posssible to make a version of it without trailing stoploss
Only use the Limit-line (takeprofit) I like how its dynamic .
Modify ur code to only get the line dynamic
It’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)?
The line I marked in post #188110 is takeorofit-line and dynamic?
Would it possible to make thos snippet without The stoploss-line?
The 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.
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.