Dukascopy
 
 
Wiki JStore Search Login

Attention! Read the forum rules carefully before posting a topic.

    Submit JForex API function requests in this forum only.
    Off topics are strictly forbidden.

Any topics which do not satisfy these rules will be deleted.

ITesterClient, optimize the code for parallel strategy backtesting
 Post subject: ITesterClient, optimize the code for parallel strategy backtesting Post rating: 0   New post Posted: Wed 12 Feb, 2014, 17:55 
User avatar

User rating: 5
Joined: Fri 02 Sep, 2011, 10:08
Posts: 157
Location: FranceFrance
Hi,

I just figured out how to backtest strategies in parallel with ITesterClient and the MA_Play.java
example provided with the JFOREX SDK.

How would you optimize things in order to use close to 100% of the CPU ?
I never managed to stay above 50-60% (I7 4770k 4 cores / 4 threads).

Please see the following code, I'm starting the same strategy with a different
parameter through a loop.

The higher the number of strategies loaded, the higher the number of threads is in
the Windows task manager (+6000 threads for 200 strategies) and the higher is the Ram usage.
But CPU load still remains at 50-60%

Why ?
Thanks for your help and knowledge.

/*
 * Copyright (c) 2009 Dukascopy (Suisse) SA. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Dukascopy (Suisse) SA or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. DUKASCOPY (SUISSE) SA ("DUKASCOPY")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL DUKASCOPY OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF DUKASCOPY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 */
package singlejartest;

import com.dukascopy.api.Instrument;
import com.dukascopy.api.LoadingProgressListener;
import com.dukascopy.api.OfferSide;
import com.dukascopy.api.Period;
import com.dukascopy.api.system.ISystemListener;
import com.dukascopy.api.system.ITesterClient;
import com.dukascopy.api.system.TesterFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.Future;

/**
 * This small program demonstrates how to initialize Dukascopy tester and start
 * a strategy
 */
public class TesterMain {

    private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);

    //url of the DEMO jnlp
    private static String jnlpUrl = "https://www.dukascopy.com/client/demo/jclient/jforex.jnlp";
    //user name
    private static String userName = "****";
    //password
    private static String password = "****";

    public static void main(String[] args) throws Exception {
        //get the instance of the IClient interface
        final ITesterClient client = TesterFactory.getDefaultInstance();
        //set the listener that will receive system events
        client.setSystemListener(new ISystemListener() {
            @Override
            public void onStart(long processId) {
                LOGGER.info("Strategy started: " + processId);
            }

            @Override
            public void onStop(long processId) {
                LOGGER.info("Strategy stopped: " + processId);
                File reportFile = new File("C:\\report.html");
                try {
                    client.createReport(processId, reportFile);
                } catch (Exception e) {
                    LOGGER.error(e.getMessage(), e);
                }
                if (client.getStartedStrategies().size() == 0) {
                    System.exit(0);
                }
            }

            @Override
            public void onConnect() {
                LOGGER.info("Connected");
            }

            @Override
            public void onDisconnect() {
                //tester doesn't disconnect
            }
        });
       
        // setting the cacheFolder
        File CacheFolder = new File("C:/JforexSDKCache/.cache");
        client.setCacheDirectory(CacheFolder);

        LOGGER.info("Connecting...");
        //connect to the server using jnlp, user name and password
        //connection is needed for data downloading
        client.connect(jnlpUrl, userName, password);

        //wait for it to connect
        int i = 10; //wait max ten seconds
        while (i > 0 && !client.isConnected()) {
            Thread.sleep(1000);
            i--;
        }
        if (!client.isConnected()) {
            LOGGER.error("Failed to connect Dukascopy servers");
            System.exit(1);
        }

        //set instruments that will be used in testing
        Set<Instrument> instruments = new HashSet<Instrument>();
        instruments.add(Instrument.EURUSD);
        LOGGER.info("Subscribing instruments...");
        client.setSubscribedInstruments(instruments);
        //setting initial deposit
        client.setInitialDeposit(Instrument.EURUSD.getSecondaryCurrency(), 100000);

        //
        final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

        Date dateFrom = dateFormat.parse("2013/01/01 00:00:00");
        Date dateTo = dateFormat.parse("2014/01/01 00:00:00");

        //client.setDataInterval(ITesterClient.DataLoadingMethod.ALL_TICKS, dateFrom.getTime(), dateTo.getTime());
        client.setDataInterval(Period.ONE_MIN, OfferSide.BID, ITesterClient.InterpolationMethod.FOUR_TICKS ,dateFrom.getTime(), dateTo.getTime());
        //load data
        LOGGER.info("Downloading data");
        Future<?> future = client.downloadData(null);
        //wait for downloading to complete
        future.get();

        //workaround for LoadNumberOfCandlesAction for JForex-API versions > 2.6.64
        Thread.sleep(5000);


        for (int j = 0; j < 80; j++) {

            MA_Play strategy1 = new MA_Play();
            strategy1.testParam01 = j;

            //start the strategy
            LOGGER.info("Starting strategy");
            client.startStrategy(strategy1, new LoadingProgressListener() {
                @Override
                public void dataLoaded(long startTime, long endTime, long currentTime, String information) {
                    //LOGGER.info(information);
                }

                @Override
                public void loadingFinished(boolean allDataLoaded, long startTime, long endTime, long currentTime) {
                }

                @Override
                public boolean stopJob() {
                    return false;
                }
            });
            //now it's running
        }
    }
}


 
 Post subject: Re: ITesterClient, optimize the code for parallel strategy backtesting Post rating: 0   New post Posted: Fri 14 Feb, 2014, 09:51 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
To reach 100% the of the CPU usage the ITesterClient should keep all of your 4 processors busy at all times, which it is obviously not doing and it should not be doing this. You should be able reach 100% CPU if you ran 4 instances of the following program:
public class WhileTrue {
   public static void main(String[] args) {
      while(true){}
   }
}

Also mind that even though you are starting the strategies in a cycle, in ITesterClient only one strategy at a time is being back-tested (in IClient in comparison they run in parallel). If you wish to back-test multiple strategies in parallel, you need to run them from separate ITesterClient instances each of which get ran from a separate process.


 
 Post subject: Re: ITesterClient, optimize the code for parallel strategy backtesting Post rating: 0   New post Posted: Mon 17 Feb, 2014, 17:24 
User avatar

User rating: 5
Joined: Fri 02 Sep, 2011, 10:08
Posts: 157
Location: FranceFrance
Hi support,

I've figured out a lot of things.

One thing bothers me, backtesting in JForex is faster than in the standalone API with ITesterClient :

For my test I tried to backtest only one strategy.

- JForex with "Optimization" selected took about 20 minutes with a CPU load of 10-15%

- Standalone API with ITesterClient with no GUI (and no console print) took about 30 minutes with a CPU load of 15-30%

How is that possible ? It's a huge difference with even more CPU usage.

I tried both of these startStrategy calls, it doesn't make that much difference :
public long startStrategy(IStrategy strategy)

public long startStrategy(IStrategy strategy, LoadingProgressListener testerProgressListener, ITesterExecution testerExecution, ITesterUserInterface testerUserInterface)


Could you please give me some advice to solve this ?

Thanks


 
 Post subject: Re: ITesterClient, optimize the code for parallel strategy backtesting Post rating: 0   New post Posted: Thu 20 Feb, 2014, 15:13 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
Could you please provide an example ITesterClient program, an example strategy and Historical Tester setting and optimization setting printscreen?


 
 Post subject: Re: ITesterClient, optimize the code for parallel strategy backtesting Post rating: 0   New post Posted: Mon 24 Feb, 2014, 19:03 
User avatar

User rating: 5
Joined: Fri 02 Sep, 2011, 10:08
Posts: 157
Location: FranceFrance
Hello,

I did further testing and I may know why the JForex optimizer is faster than API ITesterClient's public long startStrategy(IStrategy strategy)

AND even faster than the JForex tester itself (without Visual mode nor Optimization checked).


Let's assume we test with 1 minute candles, BID and 4 ticks at OHLC.

The tester and ITesterClient are writing very large amounts of 1 minute intraperiod cache files. This is
causing the computer to slow down because of heavy disk utilization.
Moreover, this intraperiod cache has to be flushed after each restart, it's very painful after a multiyear, multicurrency backtest of 100GB !

In opposition,

JForex Tester with "Optimization" checked doesn't write any intraperiod 1 minute cache file.
This is for sure the reason why it is faster and does use less cpu than all other backtest method.


In the case exposed in the first post, starting multiple strategies with ITesterClient in a loop like the following
code, is creating as much duplicated intraperiod folders as they are strategies started.

for (int j = 0; j < 80; j++) {
 
            MA_Play strategy1 = new MA_Play();

            //start the strategy
            LOGGER.info("Starting strategy");
            client.startStrategy(strategy1)


This creates for each currency pair :
intraperiod
intraperiod1
intraperiod2
intraperiod3
...
...
intraperiod80

Each intraperiod is dupplicated and has the same data for hundred's of MB on the hard drive !
I don't see the need to duplicate all this data since ITesterClient has only one instance.

What can we do to have the same behavior than the tester with Optimization checked ?

Thanks for your support.
Nicolas


 
 Post subject: Re: ITesterClient, optimize the code for parallel strategy backtesting Post rating: 0   New post Posted: Tue 25 Feb, 2014, 08:59 
User avatar

User rating: 5
Joined: Fri 02 Sep, 2011, 10:08
Posts: 157
Location: FranceFrance
If I can't desactivate Intraperiod data to be written, is there a way to modify the API in order to
write Intraperiod data on an other disk than the cache data disk ?

The idea would be to use RAMDisk software to load Intraperiods in RAM with a program periodically
flushing the unused data.


 
 Post subject: Re: ITesterClient, optimize the code for parallel strategy backtesting Post rating: 0   New post Posted: Wed 26 Feb, 2014, 17:35 
User avatar

User rating: 5
Joined: Fri 02 Sep, 2011, 10:08
Posts: 157
Location: FranceFrance
Hi support,

I did start a new topic concerning intraperiod data issues and had a response from the platform support.
Since my last messages here are related to the same topic, please see the following link with tests and screenshots.

I am looking forward for some solution on this because right now it's impossible for me to go
further with my strategy because of this intraperiod issue.

Thanks

viewtopic.php?f=85&t=50828&p=78057#p78057


 

Jump to:  

cron
  © 1998-2024 Dukascopy® Bank SA
On-line Currency forex trading with Swiss Forex Broker - ECN Forex Brokerage,
Managed Forex Accounts, introducing forex brokers, Currency Forex Data Feed and News
Currency Forex Trading Platform provided on-line by Dukascopy.com