ProRealCode - Trading & Coding with ProRealTime™
I’ve been working on a strategy template and thought I’d post it here in case anyone finds it useful. The idea is to include as many common features as possible, most of them being switchable so you can easily opt out of the bits you don’t want. It also includes typical optimization parameters so they don’t have to be entered again and again – just build or insert a strategy and most of the other stuff will already be there with provisional values.
Most of what’s here are snippets created by various people – namely Nicolas, Vonasi, Roberto and Paul among others – that i’ve picked up along the way and found useful. I’m hoping the overall package can be improved and it would be great to hear suggestions for anything else you feel should be included (as well as checking for errors that may have crept into the coding).
There’s a choice of 3 different trailing stops, and I thought of doing the same for MoneyManagement options but, as this seems to be quite a personal choice, I only included the one that I normally use. You can swap it out for whichever you prefer, as long as it produces a value for ‘positionsize’.
This version has some aspects specific to the DAX: spread, minimum positionsize, minimum stop distance (for ATR TS), and certain MoneyManagement details. These have to be altered if you want to use it with other instruments.
DEFPARAM CumulateOrders = false // Cumulating positions deactivated
DEFPARAM preloadbars = 10000
//Money Management DAX
MM = 0 // 0 = level stakes for optimization
if MM = 0 then
positionsize= 1
ELSIF MM then
ONCE startpositionsize = 0.5
ONCE factor = f // adjust for speed of change, higher = slower. factor of 10 means margin will increase/decrease by 10% of strategy profit; factor 20 = 5% etc
ONCE margin = (close*.05) //IG tier 1 margin value of 1 contract in instrument currency; change decimal according to available leverage
ONCE margin2 = (close*.05)//IG tier 2 margin value of 1 contract in instrument currency; change decimal according to available leverage
ONCE tier1 = 105 // IG first tier margin limit
ONCE maxpositionsize = 1050 // IG tier 2 margin limit
ONCE minpositionsize = 0.5 // IG minimum position allowed
IF StrategyProfit <> StrategyProfit[1] THEN
positionsize = startpositionsize + Strategyprofit/(factor*margin)
ENDIF
IF StrategyProfit <> StrategyProfit[1] THEN
IF startpositionsize + Strategyprofit/(factor*margin) > tier1 then
positionsize = (((startpositionsize + (Strategyprofit/(factor*margin))-tier1)*(factor*margin))/(factor*margin2)) + tier1 //incorporating tier 2 margin
ENDIF
IF StrategyProfit <> StrategyProfit[1] THEN
if startpositionsize + Strategyprofit/(factor*margin) < minpositionsize THEN
positionsize = minpositionsize //keeps positionsize from going below allowed minimum
ENDIF
IF (((startpositionsize + (Strategyprofit/(factor*margin))-tier1)*(factor*margin))/(factor*margin2)) + tier1 > maxpositionsize then
positionsize = maxpositionsize// keeps positionsize from going above IG tier 2 margin limit
ENDIF
ENDIF
ENDIF
ENDIF
once tradetype = 1 // [1] long/short [2]long [3]short
once closeonreversal = 0 // if tradetype=2 or tradetype=3, close position when opposite conditions obtain
Tradetime = time >=h1 and time <h2 //active hours for entering trades
//Tradetime = 1 // 24 hour trading
//Strategy*************************************************************************
***Insert all the funky stuff***
CBUY = Tradetime and (tradetype=1 or tradetype=2) and (CONDITIONS)
CSELL = Tradetime and (tradetype=1 or tradetype=3) and (CONDITIONS)
// Conditions to enter long positions
IF NOT LongOnMarket AND CBUY THEN
BUY positionsize CONTRACTS AT MARKET
ENDIF
// Conditions to exit long positions
If LongOnMarket AND (CONDITIONS) THEN
SELL AT MARKET
ENDIF
if closeonreversal and tradetype=2 and CSELL then
sell at market
endif
// Conditions to enter short positions
IF NOT ShortOnMarket AND CSELL THEN
SELLSHORT positionsize CONTRACTS AT MARKET
ENDIF
// Conditions to exit short positions
IF ShortOnMarket AND (CONDITIONS) THEN
EXITSHORT AT MARKET
ENDIF
if closeonreversal and tradetype=3 and CBUY then
EXITSHORT at market
endif
// partial close
once partialclose = 0
If partialclose then
ONCE PerCent = pcc //0.1 = 10% positions to close
ONCE PerCentGain = pcg //0.005 = 0.5% gain
ONCE MinLotSize = 0.5 //IG minimum
ExitQuantity = abs(CountOfPosition) * PerCent
LeftQty = max(MinLotSize,abs(CountOfPosition) - ExitQuantity)
CloseQuantity = abs(CountOfPosition) - LeftQty
IF Not OnMarket THEN
Flag = 1
ENDIF
IF partialclose AND LongOnMarket and close >= (PositionPrice * (1 + PerCentGain)) AND Flag THEN
SELL CloseQuantity Contracts AT Market
Flag = 0
endif
IF partialclose AND ShortOnMarket and close <= (PositionPrice * (1 - PerCentGain)) AND Flag THEN
exitshort CloseQuantity Contracts AT Market
Flag = 0
endif
endif
// Stops and targets
DONCHIANSTOP = 0
if DONCHIANSTOP then
Upper = Highest[DC](high)
Lower = Lowest[DC](low)
if longonmarket then
laststop = Lower[1]
endif
if shortonmarket then
laststop = Upper[1]
endif
if onmarket then
sell at laststop stop
exitshort at laststop stop
endif
endif
if LongOnMarket and not DONCHIANSTOP then
SET STOP %LOSS sl
ENDIF
if ShortOnMarket and not DONCHIANSTOP then
SET STOP %LOSS sls
ENDIF
If LongOnMarket THEN
SET TARGET %PROFIT tp
ENDIF
If ShortOnMarket THEN
SET TARGET %PROFIT tps
ENDIF
//EXIT ZOMBIE TRADE, closes long-running unprofitable trades after specified number of bars
EZT = 0
if EZT then
IF longonmarket and barindex-tradeindex(1)<= z1 and close<positionprice then
sell at market
endif
IF shortonmarket and barindex-tradeindex(1)>= z2 and close>positionprice then
exitshort at market
endif
endif
//trailing stop
once trailingstopPC = 1 // Percentage TS, includes break even function
once enableBreakEven = 0 //Break even, can be used in conjunction with ATR TS
once trailingstopATR = 0 //ATR TS
once trailingstopRTS = 0 //RobertoGozzi trailing stop
// Percentage trailing stop function incl. cumulative positions
if trailingstopPC then
trailingpercentlong = tsl // %
trailingpercentshort = tss // %
once acceleratorlong = a1 // always > 0 (typically TSL/10)
once acceleratorshort= a2 // always > 0 (typically TSS/10)
ts2sensitivity = 2 // 1 = close 2 = High/Low 3 = Low/High 4 = typicalprice (do not use once)
//====================
once steppercentlong = (trailingpercentlong/10)*acceleratorlong
once steppercentshort = (trailingpercentshort/10)*acceleratorshort
if onmarket then
trailingstartlong = positionprice*(trailingpercentlong/100)
trailingstartshort = positionprice*(trailingpercentshort/100)
trailingsteplong = positionprice*(steppercentlong/100)
trailingstepshort = positionprice*(steppercentshort/100)
endif
if not onmarket or ((longonmarket and shortonmarket[1]) or (longonmarket[1] and shortonmarket)) then
newsl = 0
mypositionprice = 0
endif
positioncount = abs(countofposition)
if newsl > 0 then
if positioncount > positioncount[1] then
if longonmarket then
newsl = max(newsl,positionprice * newsl / mypositionprice)
else
newsl = min(newsl,positionprice * newsl / mypositionprice)
endif
endif
endif
if ts2sensitivity=1 then
ts2sensitivitylong=close
ts2sensitivityshort=close
elsif ts2sensitivity=2 then
ts2sensitivitylong=high
ts2sensitivityshort=low
elsif ts2sensitivity=3 then
ts2sensitivitylong=low
ts2sensitivityshort=high
elsif ts2sensitivity=4 then
ts2sensitivitylong=typicalprice
ts2sensitivityshort=typicalprice
endif
if longonmarket then
if newsl=0 and ts2sensitivitylong-positionprice>=trailingstartlong*pipsize then
newsl = positionprice+trailingsteplong*pipsize
endif
if newsl>0 and ts2sensitivitylong-newsl>=trailingsteplong*pipsize then
newsl = newsl+trailingsteplong*pipsize
endif
endif
if shortonmarket then
if newsl=0 and positionprice-ts2sensitivityshort>=trailingstartshort*pipsize then
newsl = positionprice-trailingstepshort*pipsize
endif
if newsl>0 and newsl-ts2sensitivityshort>=trailingstepshort*pipsize then
newsl = newsl-trailingstepshort*pipsize
endif
endif
if barindex-tradeindex>1 then
if longonmarket then
if newsl>0 then
sell at newsl stop
endif
if newsl>0 then
if low crosses under newsl then
sell at market
endif
endif
endif
if shortonmarket then
if newsl>0 then
exitshort at newsl stop
endif
if newsl>0 then
if high crosses over newsl then
exitshort at market
endif
endif
endif
endif
mypositionprice = positionprice
endif
// break even stop incl. cumulative positions
if enableBreakEven then
//====================
once besg = be //% break even stop gain
once besl = bes //% break even stop level (+ or -)
besensitivity = 2 // 1 = close 2 = High/Low 3 = Low/High 4 = typicalprice (do not use once)
//====================
if not onmarket or ((longonmarket and shortonmarket[1]) or (longonmarket[1] and shortonmarket)) then
benewsl=0
mypositionpricebe = 0
endif
positioncountbe = abs(countofposition)
if benewsl > 0 then
if positioncountbe > positioncountbe[1] then
if longonmarket then
benewsl = max(benewsl,positionprice * benewsl / mypositionpricebe)
else
benewsl = min(benewsl,positionprice * benewsl / mypositionpricebe)
endif
endif
endif
if besensitivity=1 then
besensitivitylong=close
besensitivityshort=close
elsif besensitivity=2 then
besensitivitylong=high
besensitivityshort=low
elsif besensitivity=3 then
besensitivitylong=low
besensitivityshort=high
endif
if longonmarket then
if besensitivitylong-positionprice>=((positionprice/100)*besg)*pointsize then
benewsl=positionprice+((positionprice/100)*besl)*pointsize
endif
endif
if shortonmarket then
if positionprice-besensitivityshort>=((positionprice/100)*besg)*pointsize then
benewsl=positionprice-((positionprice/100)*besl)*pointsize
endif
endif
if barindex-tradeindex>1 then
if longonmarket then
if benewsl>0 then
sell at benewsl stop
endif
if benewsl>0 then
if low crosses under benewsl then
sell at market
endif
endif
endif
if shortonmarket then
if benewsl>0 then
exitshort at benewsl stop
endif
if benewsl>0 then
if high crosses over benewsl then
exitshort at market
endif
endif
endif
endif
mypositionpricebe = positionprice
endif
// trailing atr stop incl. cumulative positions
if trailingstopATR = 1 then
//====================
once tsincrements = tsi // set to 0 to ignore tsincrements
once tsminatrdist = tsm
once tsatrperiod = 14 // atr parameter
once tsminstop = 5 // IG minimum stop distance: DAX = 5, DJ = 12, NAS = 4, SP500 = 1
tssensitivity = 2 // 1 = close 2 = High/Low 3 = Low/High 4 = typicalprice (do not use once)
//====================
if barindex=tradeindex then
trailingstoplong = ATRL // ts atr distance
trailingstopshort = ATRS // ts atr distance
else
if longonmarket then
if tsnewsl>0 then
if trailingstoplong>tsminatrdist then
if tsnewsl>tsnewsl[1] then
trailingstoplong=trailingstoplong
else
trailingstoplong=trailingstoplong-tsincrements
endif
else
trailingstoplong=tsminatrdist
endif
endif
endif
if shortonmarket then
if tsnewsl>0 then
if trailingstopshort>tsminatrdist then
if tsnewsl<tsnewsl[1] then
trailingstopshort=trailingstopshort
else
trailingstopshort=trailingstopshort-tsincrements
endif
else
trailingstopshort=tsminatrdist
endif
endif
endif
endif
tsatr=averagetruerange[tsatrperiod]((close/10))/1000
//tsatr=averagetruerange[tsatrperiod]((close/1)) // (forex)
tgl=round(tsatr*trailingstoplong)
tgs=round(tsatr*trailingstopshort)
if not onmarket or ((longonmarket and shortonmarket[1]) or (longonmarket[1] and shortonmarket)) then
tsmaxprice=0
tsminprice=close
tsnewsl=0
mypositionpriceatr = 0
endif
positioncountatr = abs(countofposition)
if tsnewsl > 0 then
if positioncountatr > positioncountatr[1] then
if longonmarket then
tsnewsl = max(tsnewsl,positionprice * tsnewsl / mypositionpriceatr)
else
tsnewsl = min(tsnewsl,positionprice * tsnewsl / mypositionpriceatr)
endif
endif
endif
if tssensitivity=1 then
tssensitivitylong=close
tssensitivityshort=close
elsif tssensitivity=2 then
tssensitivitylong=high
tssensitivityshort=low
elsif tssensitivity=3 then
tssensitivitylong=low
tssensitivityshort=high
elsif tssensitivity=4 then
tssensitivitylong=typicalprice
tssensitivityshort=typicalprice
endif
if longonmarket then
tsmaxprice=max(tsmaxprice,tssensitivitylong)
if tsmaxprice-positionprice>=tgl*pointsize then
if tsmaxprice-positionprice>=tsminstop then
tsnewsl=tsmaxprice-tgl*pointsize
else
tsnewsl=tsmaxprice-tsminstop*pointsize
endif
endif
endif
if shortonmarket then
tsminprice=min(tsminprice,tssensitivityshort)
if positionprice-tsminprice>=tgs*pointsize then
if positionprice-tsminprice>=tsminstop then
tsnewsl=tsminprice+tgs*pointsize
else
tsnewsl=tsminprice+tsminstop*pointsize
endif
endif
endif
if longonmarket then
if tsnewsl>0 then
sell at tsnewsl stop
endif
if tsnewsl>0 then
if low crosses under tsnewsl then
sell at market // when stop is rejected
endif
endif
endif
if shortonmarket then
if tsnewsl>0 then
exitshort at tsnewsl stop
endif
if tsnewsl>0 then
if high crosses over tsnewsl then
exitshort at market // when stop is rejected
endif
endif
endif
mypositionpriceatr = positionprice
endif
//RobertoGozzi TS with cumulative orders
IF trailingstopRTS then
ONCE UseCLOSE = 0 //1=use CLOSE, 0=use High/Low
srcH = close //defaults to CLOSE
srcL = close //defaults to CLOSE
IF UseCLOSE = 0 THEN
srcH = high
srcL = low
ENDIF
ONCE UsePerCentage = 1 //0=use Pips (default), 1=use Percentages
ONCE UseEquity = 0 //0=use price (default), 1=use current Equity (initial Capital + StrategyProfit, as defined by variable MyEquity)
MyEquity = 1000
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
StartPerCent = pc //0.25 = 0.25% movement to trigger Trailing Stop (when UsePerCentage=1)
StepPerCent = spc //50 = 50% (of the 0.25% above) as a Trailing Step (when UsePerCentage=1) (set to 100 to make StepSize=TrailStart, set to 200 to make it twice TrailStart)
TrailStart = 30 //30 Start trailing profits from this point (when UsePerCentage=0)
MinStart = 10 //10 Minimum value for TrailStart (when UseEquity=1, to prevent TrailStart from dropping below ZERO when Equity turns negative)
IF UsePerCentage THEN
TrailStart = (close / PipSize) * StartPerCent / 100 //use current price (CLOSE) for calculations
IF UseEquity THEN //alternative calculations using EQUITY
TrailStart = Max(MinStart,(MyEquity / PipValue) * StartPerCent / 100) //MyEquity is the variable (feel free to use a different name) retaining your current equity
ENDIF
ENDIF
//
BasePerCent = bpc //0.08 - 0.2 Profit percentage to keep when setting BerakEven
StepSize = ss //5 - 15 Pip chunks to increase Percentage
IF UsePerCentage THEN
StepSize = TrailStart * StepPerCent / 100
ENDIF
PerCentInc = pci //0.06 - 0.14 PerCent increment after each StepSize chunk
RoundTO = -0.5 //-0.5 rounds always to Lower integer, +0.4 rounds always to Higher integer, 0 defaults PRT behaviour
PriceDistance = 5 * pipsize //broker's minimum 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 + ((srcH - 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 - srcL) * 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 srcH > (PositionPrice + (y1 * pipsize)) THEN //LONG positions
//
// compute the value of the Percentage of profits, if any, to lock in for LONG trades
//
x1 = (srcH - PositionPrice) / pipsize //convert price to pips
IF x1 >= TrailStart THEN // go ahead only if N+ pips
Diff1 = abs(TrailStart - x1) //difference from current profit and TrailStart
Chunks1 = max(0,round((Diff1 / StepSize) + 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 srcL < (PositionPrice - (y2 * pipsize)) THEN //SHORT positions
//
// compute the value of the Percentage of profits, if any, to lock in for SHORT trades
//
x2 = (PositionPrice - srcL) / pipsize //convert price to pips
IF x2 >= TrailStart THEN // go ahead only if N+ pips
Diff2 = abs(TrailStart - x2) //difference from current profit and TrailStart
Chunks2 = max(0,round((Diff2 / StepSize) + 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
Nice job nonetheless, this will spare many of us hours of searching and coding.
Thank you 🙂
Hey Roberto, glad you like it. A lot of the code is yours so grazie a te!
I wanted to check, in your TS, at line 456 above, there’s a value for PriceDistance. Is this a variable, or the IG minimum stop distance?
(I assumed the latter)
What a great idea Nonetheless … you are a Star!!
Thank You so much for sharing your work pulling all the snippets together!
your assumption is right, it’s the broker’s minimum distance required for pending orders.
Link to above Combo Snippet Template added as Log 286 here …
pulling all the snippets together!
Well, not ALL the snippets, but hopefully some of the more useful ones. Let’s see if any changes/improvements come to light over the next few days and I’ll knock up separate versions for the main indices to lodge in the Snippet Library for posterity…
Actually I spotted a mistake already, line 139 should be >=
IF longonmarket and barindex-tradeindex(1)>= z1 and close<positionprice then
Don’t know how that happened ???
v2 with minor changes and corrections…
let’s try that again, I think I exported without saving and somehow the correction didn’t register ???
Excellent idea. This would make it very streamlined to optimise and may lead to interesting results.
We could add candlestick patterns or generic filters into the template. Ofcourse Grahals snippets.
Ill try to contribute as well when i can.
some minor changes, plus versions specific to DJ, NAS, SP500
Thank you very much for this initiative! I was just thinking of creating a few specific topics to bring together the snippets by theme: trailing stop, money management, etc. Bravo!
a few more changes, corrections…
On small simplification suggestion:
Line 23 and 26 of the original code
23: if positionsize < minpositionsize then
26: if positionsize > maxpositionsize then
Thanks for sharing your template
New strategy template
This topic contains 35 replies,
has 10 voices, and was last updated by Chrisinobi
3 years, 12 months ago.
| Forum: | ProOrder: Automated Strategies & Backtesting |
| Language: | English |
| Started: | 05/15/2021 |
| Status: | Active |
| Attachments: | 13 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.