AlgoTraderAlgoTrader Documentation

Chapter 5. Strategy Backtesting

5.1. Exchange Simulator
5.2. Simulation Process
5.3. Single Run Simulation
5.4. Automated Parameter Optimization
5.5. Performance Statistics
5.6. In-Process Exchange Simulator (deprecated)
5.7. Multi Security Simulations

Historical data for back testing can be provided to strategies either via .csv files or via Section 18.1, “InfluxDB”.

Securities specified within the table subscription or securities subscribed to via the SubscriptionService are fed to the Strategy.

To feed data from CSV files during a back test the following property needs to be set inside Alternatively the properties can be changed via Section 2.3, “VM Arguments”:

# should market data events be feed from CSV files

For further details on file format and storage location of CSV files please see Section 18.9, “Market Data File Format”.


When feeding historical data with CSV files it is not possible to set a particular time range for the simulation. If this is a requirement please feed data through InfluxDB

To feed data from InfluxDB during a back test the following properties need to be set inside Alternatively the properties can be changed via Section 2.3, “VM Arguments”:

# should market data events be feed from the database
dataSource.0.dataSourceType = DB

# the back test start date when feeding from InfluxDB
dataSource.0.minDate = 2016-01-01

# the back test end date when feeding from InfluxDB
dataSource.0.maxDate = 2016-12-31

The tables Subscription, Position, Combination & Component have a field persistent which has the following meaning:

Backtesting strategies written in Python uses the same procedures as backtesting strategies written in Java, for details see Section 4.5, “Strategy Development in Python”

The system provides an Exchange Simulator that is mainly used in back testing mode, but can also be used in live trading. The Exchange Simulator executes Orders by using an ExecutionModel. An Execution Model contains the logic which decides whether an order gets executed under the current market situation and what portion of the order gets executed. In addition the ExecutionModel also contains the logic to calculate commissions and fees that should be added to an order.

AlgoTrader contains a DefaultExecutionModel which provides a reasonable default logic for executing orders. The DefaultExecutionModel provides the following properties inside the file where they can be changed. Alternatively the properties can be changed via Section 2.3, “VM Arguments”:

# percent slippage that will be added to an order
#{"type":"Double","label":"Percent Slippage"}
execution.slippagePct = 0.0

# execution commission per order
#{"type":"Double","label":"Commission Per Order"}
execution.commissionPerOrder = 0.0

# execution commission per contract
#{"type":"Double","label":"Commission Per Contract"}
execution.commissionPerContract = 0.0

# execution commission in percent of the order amount (i.e. quantity x price)
#{"type":"Double","label":"Commission In Percent"}
execution.commissionInPercent = 0.0

The DefaultExecutionModel always charges commissions in the quote currency of the order. E.g. when buying BTC/USD the fees will be charged in USD.

For further details on the DefaultExecutionModel please consult the JavaDoc.

It is possible to replace the DefaultExecutionModel with a custom implementation that implements the interface ExecutionModel. The custom Execution Model needs to be registered as a Spring Bean in the following locations:

  • For simulation: /META-INF/applicationContext-client-xxx.xml in the strategy project under src/main/resources.

  • For live trading (to be used globally): /META-INF/applicationContext-env.xml. This file needs to be in the class path, e.g. in the conf project under src/main/resources.

During the simulation process transaction as well as position and cash_balance updates are executed in the database. It is therefore possible to use a standard database reporting tool to perform additional analysis on it, provided you are not running vs. the H2 in-memory database (Spring profile embeddedDataSource).

To use the Exchange Simulator the Spring profile simulation has to be used, e.g.


Note than when using the Exchange Simulator in live trading, orders will be executed against live data internally and will not get sent to the external Broker or Exchange. If the Spring Profile simulation is enabled all other external Order Services will be disabled.

-Dsimulation=true denotes a back test and will effectively disable external Market Data services, so if the intention is to run exchange simulator against live market data, make sure that this parameter is set to false

All external order services must be disabled, e.g. Spring profiles like bFX, bFL etc must be inactive

During a simulation process the following steps are executed sequentially by the SimulationExecutorImpl:

  1. Create strategy entries in the database

  2. The database is reset to its original state via the ResetService

  3. An initial amount (USD 1'000'000 per default) is allocated to each strategy (the initial amount can be changed through the simulation.initialBalance setting inside

  4. All server Esper modules are deployed

  5. The life cycle phase INIT is broadcasted to all strategies. During this phase potential initiation steps can be invoked.

  6. All strategy initModules Modules are deployed (if using Esper based strategies)

  7. The life cycle phase PREFEED is broadcasted to all strategies. During this phase technical indicators can be initialized using historical data

  8. All strategy runModules Modules are deployed (if using Esper based strategies)

  9. Market data subscriptions are initialized based on entries in the table subscription

  10. The life cycle phase START is broadcasted to all strategies. During this phase eventual actions like security subscriptions can be taken care of

  11. At that time the actual simulation starts and market data events are starting to be sent into the Esper Engines

  12. The life cycle phase EXIT is broadcasted to all strategies. During this phase eventual cleanup actions can be taken care of

  13. At the end of each simulation run, metrics are printed to the console (if enabled), see Chapter 28, Metrics

  14. All open orders are cancelled

  15. All open positions are closed

  16. An EndOfSimulationVO event is sent to all strategies

  17. SimulationResults are retrieved from the strategies

  18. Esper Engines are re-initialized

  19. The In-Process Exchange Simulator is reset

  20. The Market Data Cache is flushed

  21. The second-level cache is cleared

  22. All reports are closed

  23. The Excel based back test report is created and statistics are displayed to the console, see Section 5.5, “Performance Statistics”

To run a strategy in Simulation Mode with the currently defined parameters use the procedure defined in Section 3.1, “Simulation Mode”.

The system allows running multiple simulations in parallel. Using cloud based servers thousands of simulation runs can be carried out in a matter of a few hours. For additional information please visit the full blog post on cloud based trading strategy optimization using AlgoTrader and Amazon Elastic MapReduce.

Using Numerical Optimization functions (i.e. Brent & Newton) optimal parameter ranges can be determined in an automated fashion.

The following options exist (set in program arguments):


One Simulation run with a parameter set to the defined value. The example below will do one run with parameter a set to 0.8

simulateBySingleParam a:0.8


One Simulation run with multiple parameters set to defined values. The example below will do one run with parameter a set to 0.8 and b set to 12.0

simulateByMultiParam a:0.8,b:12.0


Multiple Simulation runs by incrementing the value of one parameter within a defined interval. The example below will increment the value of parameter a starting at 0.1 to 0.9, incrementing by 0.1 for each run

optimizeSingleParamLinear a:0.1:0.9:0.1


Multiple Simulation runs by iterating the value of one parameter according to defined list. The example below will iterate the value of parameter a through the following list: 0.2, 0.8, 0.9 and 1.2

optimizeSingleParamByValues a:0.2:0.8:0.9:1.2


Multiple Simulation runs by setting the value of one parameter within the defined range and trying to find the maximum Sharpe Ratio. The optimizer being used is UnivariateRealOptimizer. The example below will set the value of parameter a between 0.1 and 1.0 (accuracy 0.01).

optimizeSingleParam a:0.1:1.0:0.01


Multiple Simulation runs by doing a matrix Optimization of 2 or 3 parameters by incrementing their values within a defined interval. The example below will iterate through all possible combinations by incrementing the value of parameter a starting at 0.1 to 0.9 (increment: 0.1), and incrementing the value of parameter b starting at 10.0 to 100.0 (increment: 5.0)

optimizeMultiParamLinear a:0.1:0.9:0.1 b:10.0:100.0:5.0


Multiple Simulation runs by adjusting the value of multiple parameters around their start values and trying to find the maximum Sharpe Ratio. The example below will start the optimization by setting the value of parameter a to 85.0 and parameter b to 150.0

optimizeMultiParam a:85.0 b:150.0

In order to process parameters with the correct decimal scale the following property needs to be updated inside Alternatively the property can be changed via Section 2.3, “VM Arguments”:

# the number of digits all portfolio balances will be displayed with
misc.portfolioDigits = 2


In order for the parameter optimization to work the following properties need to be updated inside Alternatively the properties can be changed via Section 2.3, “VM Arguments”:

# if set to true, writing to CSV reports will be disabled
report.disabled = true

# if set to true, the Excel back test report will open at the end of a simulation
report.openBackTestReport = true


Before each back test run the Esper Engines will be reset. However Strategy services are not reset. Due to this any state that is maintained within the Strategy service needs to be reset within the onInit method.


The values of Esper variables as well as Java properties get initialized on startup using Spring. The actual optimization only happens once the Spring context is fully initialized. Due to this it is necessary to overwrite the default values in the onInit from system. properties. This can be done as follows for Esper variables:

getEngine().setVariableValue("propertyA", System.getProperty("propertyA"));

And like this for Java properties

this.propertyB = System.getProperty("propertyB");

At the end of each single simulation run, a CSV and Excel based back test report with performance statistics is created.

The following 4 files are created in the sub-folder /files/report :

  • BackTestReport.xlsm: the Excel based back test report (see image above)

  • MetricReport.csv: contains key performance metrics

  • PortfolioReport.csv: contains daily portfolio values (i.e. netLiqValue, marketValue, realizedPL, unrealizedPL, cashBalance, openPositons & leverage)

  • TradeReport.csv: contains all trades including their profit

The Excel based back test report can be modified in terms of formatting and layout if needed.

In addition when running a single simulation run, statistics will be displayed to the console in the following format:

execution time (min): 2.43
dataSet: eurusd-1min-20111218-20130121
month-year:          Dec-11  Jan-12  Feb-12  Mar-12  Apr-12  May-12  Jun-12  Jul-12  Aug-12  Sep-12  Oct-12  Nov-12  ...
monthlyPerformance:   0.58%   4.03%   2.66%  -0.19%   2.80%  -1.96%   2.44%   3.23%   0.66%  -0.58%   3.67%   2.31%  ...
year:                  2011    2012    2012
yearlyPerformance:    0.58%  22.33%  -0.06%
posMonths=10 negMonths=4 posYears=2 negYears=1
avgM=1.50% stdM=1.79% avgY=19.39% stdY=6.21%  sharpeRatio=3.12
maxMonthlyDrawDown=1.96% bestMonthlyPerformance=4.03% maxDrawDown=4.49% maxDrawDownPeriod=46.00days colmarRatio=4.32
WinningTrades: count=428(53.97%) totalProfit=1'277'201.37 avgProfit=2'984.12 avgProfitPct=0.23%
LoosingTrades: count=365(46.03%) totalProfit=-1'047'487.34 avgProfit=-2'869.83 avgProfitPct=-0.26%
AllTrades: count=793(100.00%) totalProfit=229'714.04 avgProfit=289.68 avgProfitPct=0.00% 

When running parameter optimizations, statistics will be displayed in the following summary format showing the current parameter values as well as corresponding performance statistics of one run on one single line:

a=90 avgY=39.86% stdY=20.16% sharpe=1.97 maxDDM=11.29% bestMP=8.35% ...
a=105 avgY=34.60% stdY=20.33% sharpe=1.69 maxDDM=11.56% bestMP=8.39% ... 

In addition to above General Performance statistics, strategy specific performance statistics are printed to the console. These are retrieved by calling the method StrategyService.getSimulationResults of the strategy.

The amount of output during the simulation can be adjusted by setting the Log Level according to Chapter 29, Logging.

Executing all transactions in the database during simulation is useful for reporting purposes but also incurs additional processing time. For trivial strategies that do not need to perform any sort of sophisticated querying based on transaction data, an additional in-process / in-memory exchange simulator is available that uses Hash Maps as the underlying storage mechanism. This will allow for significantly faster processing of orders during simulation. The in-process exchange simulator can be used as follows within strategies:

Order order = new MarketOrder.Factory.newInstance();

Position position = getSimulator().findPositionByStrategyAndSecurity(strategy, security);

By default, only those securities will be considered for simulations which have been subscribed to in the INIT or PREFEED phase.

Some strategies that are based on multiple securities need to subscribe and unsubscribe securities during the simulation. A typical example for this would be a Futures bases strategy that needs to unsubscribe an expiring Future and at the same time subscribe to the next Future in the chain.

To be able to subscribe and unsubscribe securities during a simulation change the following property inside the will cause all CSV files present in the dataset directory to be used for the simulation. Strategies still only receive market data for securities they have subscribed to. Alternatively the properties can be changed via Section 2.3, “VM Arguments”:

# should all files in the dataSetLocation be used or just the ones corresponding to defined subscriptions
dataSource.0.feedAllFiles = true