Standalone API client on LINUX running Oracle/Sun Java Server VM JDK 7 update 45
on an Amazon Linux EC2 AMI . JForex API 2.8.0
One client already running 8 strategies.
During startup of second client process, same Live account login, different process,
I see this exception while the second client is attempting to start
its strategies, which is an identical set of strategies as the first
client process is already running.
May be simply a synchronization issue of delivering Ticks to a strategy simultaneous with an internal
Strategy list being modified, since it is intermittent?? So the additional process stuff may be a
"red herring"........
Is there some synchronization issue you can recognize, since I don't think it's a problem
on my end... ? Since these are separate processes, I don't think there is
anything I can do in my code, so could be an issue in Dukascopy API and/or
server side coding. Would appreciate if you could look into it.
HyperScalper
after call startStrategy HyperBOT_EURJPY
Waiting for Strategy HyperBOT_EURJPY
2013-11-28 16:59:25.959 ERROR LiveCurrencyMarketProcessingThread - java.util.ConcurrentModificationException
java.util.concurrent.ExecutionException: java.util.ConcurrentModificationException
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at com.dukascopy.dds2.greed.market.LiveCurrencyMarketProcessingThread.run(LiveCurrencyMarketProcessingThread.java:84)
Caused by: java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:926)
at java.util.HashMap$ValueIterator.next(HashMap.java:954)
at com.dukascopy.api.impl.connect.DCClientImpl$7.tickReceived(DCClientImpl.java:821)
at com.dukascopy.dds2.greed.market.LiveCurrencyMarketProcessingThread$1.run(LiveCurrencyMarketProcessingThread.java:138)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Here is the code section where the error occurs, as a list
of Strategy instances is started. Very reliable with a single
process but, as I say, when a second process instance is started
this code throws the ConcurrentModificationException.
final void startStrategies() {
int numStrategies = instrumentNamesList.size();
log("StartStrategies running "+instrumentNamesList.size()+" instances.");
IHyperBotStrategy strategy = null;
String instrumentName = null;
String currency1 = null;
String currency2 = null;
String slashName = null;
long id = 0;
try {
log("Run RemoteServerTickTimestamps");
RemoteServerTickTimestamps remoteServerTickTimestamps = new RemoteServerTickTimestamps(); // use defaults
id = getIClient().startStrategy(remoteServerTickTimestamps, myStrategyExceptionHandler);
synchronized(strategiesMapMutex) {
strategiesMap.put(new Long(id), remoteServerTickTimestamps);
}
log("after RemoteServerTickTimestamps");
}
catch(Exception e) {
e.printStackTrace();
}
pause(10000);
for (int i=0; i<numStrategies; i++) {
Instrument instrument = null;
instrumentName = instrumentNamesList.get(i);
if (instrumentName.length()!=6) continue;
boolean error = false;
try {
// create an Instrument
currency1 = instrumentName.substring(0,3);
currency2 = instrumentName.substring(3,6);
slashName = currency1+"/"+currency2;
log("Slashed name: "+slashName);
instrument = Instrument.fromString(slashName);
}
catch(Exception e) {
log("Error creating instrument "+instrumentName);
error=true;
}
if (instrument==null || error) {
log("ERROR INSTRUMENT "+instrumentName+" does not exist.");
continue; // skip it
}
if ( !availableInstruments.contains(instrument)) {
log("ERROR INSTRUMENT "+instrumentName+" is NOT AVAILABLE to your account.");
continue; // skip it
}
masterStrategy = new HyperBot(); //RemoteServerTickTimestamps();
masterStrategy.selectedInstrument = instrument;
boolean validStrategy = validStrategy(masterStrategy);
if ( !validStrategy) {
log("Invalid HyperBot strategy failed.");
systemExit(1);
}
// cast is guaranteed by validStrategy check
strategy = (IHyperBotStrategy)masterStrategy;
strategy.setHyperBotHost(this); // this is the host
String strategyName = "HyperBOT"+"_"+instrumentName;
strategy.setName(strategyName);
try {
log("call startStrategy "+strategyName);
id = getIClient().startStrategy(masterStrategy, myStrategyExceptionHandler);
synchronized(strategiesMapMutex) {
strategiesMap.put(new Long(id), masterStrategy);
}
log("after call startStrategy "+strategyName);
}
catch(Exception e) {
e.printStackTrace();
}
if (id==0) {
log("Start strategy failed.");
systemExit(1);
}
log("Waiting for Strategy "+strategyName);
if (i<numStrategies) {
pause(5000);
}
}
}