Several optimization methods (Ascent, Genetic, Brute Force) are available through
TrainMode. The optimization target can be individually defined
with a user-supplied **objective** function. The optimization process
consists of many cycles. For every cycle the **optimize** function
generates a different value between **min** and **max**
and tests its effect on the strategy. At the end of the optimization, a parameter
chart is plotted that reveals the effect of a certain parameter on the strategy
(see below). The chart displays the number of winning trades (bright blue bars),
losing trades (dark blue) and overall performance (red) of the parameter. The best
or most robust parameter values are then selected and stored in a **.par**
file.

The chart above is a typical result of an **optimize** call in [Train]
mode with the Ascent algorithm. The strategy parameter to be optimized here is used
for a buy/sell threshold. It varies from **0.200** to **3.00**
in constant steps of **0.1**. We have a small performance peak around
**0.90** and the highest peak at **1.60**. The best parameter
value however is **1.70**, with a performance of **2.7**
and **125** winning trades. Although its adjacent bars are higher,
the optimizer normally selects the center of the broad peak that represents not
the most profitable, but the most robust parameter value (this behavior can be changed
with TrainMode). Using the value of a very narrow peak or
of a single line bears the danger of overfitting the strategy.

By using several **optimize** calls in the code, any number of parameters
can be optimized at the same time. The more parameters are optimized, the more cycles
are needed and the longer will it take. Dependent on the method, the best value
of a parameter can affect the optimization of the next parameters. If the script
trades multiple assets or algorithms and contains loop calls,
a separate parameter set for each loop is optimized.

default |
Default value of the parameter, returned when the
PARAMETERS flag is not set in [Test] or [Trade]
mode. This should be the estimated best value of the parameter, normally
in the middle of its range. Must be >= 0. |

min, max |
Parameter range, given by its minimum and maximum values (>=
0). |

step |
Optional step width. When 0 or omitted, 10%
is added to the parameter for every optimization step (Ascent
optimization only; in Brute Force or Genetic optimization the range is divided
in 10 equal steps). When a positive step value is given,
add this constant value every step; when a negative step
value is given, add its magnitude as a percentage every step (f.i.
-20 adds 20% per step). Adding a percentage
instead of a constant value gives a better step resolution at the begin
of the range. For best results, select the step value so
that every parameter has about 10..15 optimization steps. The recommended
minimum number of steps is 5, the maximum number of steps
(MAX_STEPS) can be found in trading.h. |

bias |
Optional preference of low or high parameter values (Ascent
optimization only). When 0 or omitted, select the optimal
parameter. When > 0, prefer higher parameter values
even when their rank is lower by the given bias in percent.
When < 0, prefer lower parmeter values even when their
rank is lower by abs(bias) in percent. Preferring values
from the low or high range can make sense f.i. for setting a Stop
as tight as possible even when its value is not optimal. |

- Optimization theory is described under Training; an example can be found under Workshop 5.
- All
**optimize**calls must be placed either in the run function or in functions that are called from the**run**function. Since parameters are enumerated by the order of their**optimize**calls, the order or number of**optimize**calls must not change between test and training or from one run to the next. - In portfolio strategies, parameters must be normally optimized individually
for any component. For this use one or two loop calls
to cycle through assets and algos. All
**optimize**calls must be inside the inner loop. The asset and algo must be selected before calling**optimize**. For optimizing asset- or algo-independent parameters in a portfolio system, call**optimize**outside the loop, but select an asset before calling**optimize**. If individual optimization is not desired, don't use loop, but enumerate the assets in a simple for loop, f.i.**for(used_assets) ...**, and optimize the parameters outside the for loop. Make sure in that case to select all assets before the first**optimize**call; otherwise the optimizier will assume a single-asset strategy. - The strategy performance is calculated in the
**objective**function in**include\default.c**. This function can be replaced by any user provided function named**objective**in the script. This way, other performance values can be used for optimizing parameters, for instance the profit/drawdown ratio, or the gross profit, or the Sharpe ratio (examples below). The**objective**function can access all trade statistics for determining the performance value. By default, the function calculates the pessimistic return ratio (**PRR**) with reduced influence of the biggest win and the biggest loss, a penalty for fewer trades, and a 5 trades minimum. - Optimized parameters are stored in
**.par**files in the**Data**folder. They are plain text files that contain the parameter values in the order of their**optimize**calls. If WFO was used, the file names contain the number of the WFO cycle. If**optimize**was called without calling asset before, the file names contain the asset name from the scrollbox; this way different sets of**.par**files can be generated by selecting different assets. In multi-asset or multi-algo strategies the**.par**files contain the parameters for all asset/algo combinations.

Each line in a .par file begins with the asset name and optional algorithm identifier of the parameter set. The values are listed in the order of the**optimize**calls in the script. A**'+'**before a parameter value indicates that the best value is at the end of its parameter range. In that case it could make sense to extend the range for better results. . - For determining the performance of a parameter combination, the system normally uses fixed trades sizes of 1 lot. Training with individual lot sizes can be set up with the TrainMode variable.
- The parameter range must be positive, i.e. both
**min**and**max**must not be less than**0**. If a strategy parameter has to be negative, multiply it with**-1**or subtract a constant to get a positive range for the**optimize**function. Parameters also should be in a decent number range from 0.1 to 1000, since they are stored in text files. 0.000000123 would be no good parameter value, nor would 1.23e45. Multiply them with a factor when needed. - Returned parameter values in Ascent mode are not necessarily a multiple of the step width. They can lie anywhere in the optimization range. Use the round or floor functions when optimizing an integer value.
- The
**bias**value can be used when a high or a low value of the parameter is preferred even though another value gives a slightly better**objective**result (Ascent mode only). For instance, you might prefer low stop distances to reduce the risk even when higher stop distances give slightly better results. - Parameters that affect the price data array, such as
**BarPeriod**, require special handling for optimization. They can not be changed during the simulation, so they can not be walk forward optimized; for a walk forward test they must be optimized in a separate training run before all other parameters. They can also not be read from the**.par**file, so their optimized value must be entered directly in the script as**default**parameter of the**optimize**call before further optimizing, testing, or trading the strategy. - When optimizing several parameters in Ascent mode,
put the most important parameters first. Parameters are optimized in the order
they appear in the code. For optimizing trade entry and exit parameters, optimize
entry parameters first and exit parameters afterwards. When your exit system
is complex, optimize entry parameters with a simplified exit such as a simple
stop. For using a simple exit while the entry parameters are optimized, evaluate
the current parameter number (
**ParCycle**), f.i.**if(Train && ParCycle <= NumParameters-3) setExitSimple();**. When parameters affect each other - for instance, two time periods for a crossover of two moving averages - optimize only one time period, and optimize a multiplication factor for the other (see the example below). This way the other time period also changes when the first one is optimized. - Special cases when RULES and PARAMETERS have to be optimized at the same time are described under Training. For optimizing parameters several times, use NumTrainCycles.
- The current optimization cycle can be evaluated with the
**ParCycle**and**StepCycle**variables. Optimization can be aborted by setting StepNext to**0**. This will end optimization after the current cycle. - When optimizing a time period of an indicator, make sure that
**LookBack**is set at least to the maximum period plus the**UnstablePeriod**(f.i.**LookBack = max(LookBack,300);**). Otherwise**LookBack**will automatically adapt to the period of the current parameter value. This can affect the result in an unexpected way because the back test period would then get shorter when the time period gets longer. - For avoiding randomness, slippage is not simulated
during optimization. Rollover is simulated; it can
have a large effect on the result and produce long/short asymmetry in parameters
and profit factors. For eliminating rollover asymmetry, set
RollLong/Short to
**0**after calling asset in training mode. For eliminating trend asymmetry, detrend the price curve in training mode. Even without rollover and trend, some commodities and stocks still require different parameter sets for long and short trades due to inherent asymmetries in their price curves (long trades are often dominant). - For optimizing in pre-defined individual steps, use an array and optimize
its index. Example:
**int Periods[5] = { 10, 20, 50, 100, 200 }; int Period = Periods[round(optimize(1,0,4,1),1)];** - For optimizing a global parameter without the
**optimize**function and outside of all WFO cycles, use NumTotalCycles for several training/test runs, use TotalCycle for setting the parameter value, and use the evaluate function to plot a histogram or select the best parameter. - When the strategy opens no trades at all in [Train]
mode - f.i. when no trade signal is generated or when Margin
or Lots is zero - the
**default**values are stored in the parameter file. - The profit/loss curves of every
**optimize**step can be exported in a file for further evaluation when a Curves file name is given. A curve is only exported when the**objective**function returns a nonzero value. - The height of the parameter charts can be controlled with PlotHeight2.

// trend trading with Moving Averages and optimized parametersfunction run() { set(PARAMETERS);// for optimizing time periods, set the LookBack variable to the // maximum possible value (here, TimeCycle 100 * TimeFactor 5)LookBack = 100*5;

var TimeCycle = optimize(30,10,100,5);var TimeFactor = optimize(3,1,5);// allow 3% tolerance for preferring low stop distancesStop = ATR(10) * optimize(3,1,10,0.5,-3); vars Price = series(price(0)); vars MA1 = series(SMA(Price,TimeCycle)); vars MA2 = series(SMA(Price,TimeCycle*TimeFactor)); plot("MA1",*MA1,0,BLUE); plot("MA2",*MA2,0,BLUE); if(crossOver(MA1,MA2)) enterLong(); else if(crossUnder(MA1,MA2)) enterShort(); }

// alternative objective function based on Calmar ratiovar objective() { return(WinTotal-LossTotal)/max(1,DrawDownMax); }// alternative objective function based on Sharpe ratiovar objective() { if(!NumWinTotal && !NumLossTotal) return 0.; return ReturnMean/ReturnStdDev; }// alternative objective function for binary optionsvar objective() { return ((var)(NumWinLong+NumWinShort))/max(1,NumLossLong+NumLossShort); }