Add the following program to you JForex-SDK project:
package jforex.sdk;
import com.dukascopy.api.*;
import com.dukascopy.api.system.ISystemListener;
import com.dukascopy.api.system.ITesterClient;
import com.dukascopy.api.system.ITesterClient.DataLoadingMethod;
import com.dukascopy.api.system.TesterFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
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;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
/**
* This example program demonstrates how to compile and run a strategy from a java file
*/
@RequiresFullAccess
public class StrategyRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(StrategyRunner.class);
private static String jnlpUrl = "https://www.dukascopy.com/client/demo/jclient/jforex.jnlp";
private static String userName;
private static String password;
public static void main(String[] args) throws Exception {
if(args.length < 5){
LOGGER.error("Insufficient parameter count " + args.length + ". Expected 5 arguments." );
return;
}
userName = args[0];
password = args[1];
String strategyPath = args[2];
String fromStr = args[3];
String toStr = args[4];
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager sjfm = jc.getStandardFileManager(null, null, null);
File javaFile = new File(strategyPath);
String qualifiedClassName = getQualifiedName(javaFile.getAbsolutePath());
jc.getTask(null, null, null, null, null, sjfm.getJavaFileObjects(javaFile)).call();
sjfm.close();
LOGGER.info("Class has been successfully compiled");
URL[] urls = new URL[] { new URL("file://.") };
URLClassLoader ucl = new URLClassLoader(urls);
Class targetClass = ucl.loadClass(qualifiedClassName);
IStrategy strategy = (IStrategy) targetClass.newInstance();
// 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:\\temp\\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
}
});
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);
}
final SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
Date dateFrom = dateFormat.parse(fromStr);
Date dateTo = dateFormat.parse(toStr);
client.setDataInterval(DataLoadingMethod.ALL_TICKS, dateFrom.getTime(), dateTo.getTime());
// 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(), 50000);
//client.setCacheDirectory(new File("C:/temp/cacheTemp"));
// load data
LOGGER.info("Downloading data");
Future<?> future = client.downloadData(null);
// wait for downloading to complete
future.get();
// start the strategy
LOGGER.info("Starting strategy");
client.startStrategy(strategy);
// now it's running
}
private static String getQualifiedName(String path) throws Exception{
String fileContents = readFileContents(path);
String className = findRegex(fileContents, "class ([\\p{Alnum}.]+) ");
String packageName = findRegex(fileContents, "package ([\\p{Alnum}.]+);");
if(packageName.isEmpty()){
throw new RuntimeException("Please define the package of your strategy");
}
return packageName + "." + className;
}
private static String readFileContents(String path) throws IOException {
FileInputStream stream = new FileInputStream(new File(path));
try {
FileChannel fc = stream.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
return Charset.defaultCharset().decode(bb).toString();
} finally {
stream.close();
}
}
private static String findRegex(String src, String regexpString) {
Pattern pattern = Pattern.compile(regexpString, Pattern.DOTALL);
Matcher matcher = pattern.matcher(src);
return matcher.find() ? matcher.group(1) : "";
}
}
Then export the program to a runnable jar file and run it in the following manner:
java -jar JarFileName.jar username password ./YourStrategy.java "05/01/2012 00:00:00" "05/01/2012 00:10:00"
If you don't want the strategy to get recompiled every time you run the program, consider passing the strategy's .class file to the program and remove the compilation logic.
Isak wrote:
What I was trying to suggest in my original post is that such a sample application should be included in the wiki, as part of documentation on ITesterClient.
We don't plan to post this example in our wiki, since this is a Java SE problem, not a JForex-API problem. In general wiki's purpose is to show users how to use the JForex-API functionality, not Java SE in whole (which itself has countless online tutorials and forums).