We created a strategy that explicitly shows that what you claim is false. Launch the following strategy and see its messages:
package jforex.messages;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.dukascopy.api.IAccount;
import com.dukascopy.api.IBar;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.IContext;
import com.dukascopy.api.IEngine;
import com.dukascopy.api.IEngine.OrderCommand;
import com.dukascopy.api.IMessage;
import com.dukascopy.api.IOrder;
import com.dukascopy.api.IStrategy;
import com.dukascopy.api.ITick;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.Period;
public class MessageTest implements IStrategy {
private IEngine engine;
private IConsole console;
private final Map<IOrder, List<IMessage.Type>> messages = new HashMap<IOrder, List<IMessage.Type>>();
private Instrument instrument = Instrument.EURUSD;
private int counter;
private final Set<IOrder> tpSetInProgress = new HashSet<IOrder>();
private final Set<IOrder> closeInProgress = new HashSet<IOrder>();
@Override
public void onStart(IContext context) throws JFException {
engine = context.getEngine();
console = context.getConsole();
context.setSubscribedInstruments(EnumSet.of(Instrument.EURUSD));
}
@Override
public void onTick(Instrument instrument, ITick tick) throws JFException {
if(instrument != this.instrument){
return;
}
// console.getOut().println(tick);
if(engine.getOrders().size() > 50){
for(IOrder o : engine.getOrders()){
if(o.getState() == IOrder.State.FILLED
&& o.getTakeProfitPrice() > 0
&& !closeInProgress.contains(o)){
o.close();
closeInProgress.add(o);
}
}
return;
}
for(IOrder o : engine.getOrders()){
if(o.getState() == IOrder.State.FILLED && o.getTakeProfitPrice() == 0 && !tpSetInProgress.contains(o)){
double tpPrice = o.isLong()
? tick.getBid() + instrument.getPipValue() * 10
: tick.getAsk() - instrument.getPipValue() * 10;
o.setTakeProfitPrice(tpPrice);
tpSetInProgress.add(o);
}
}
for(int i = 0; i<10; i++){
engine.submitOrder(String.format("o_%s_%s", counter++, System.currentTimeMillis()), instrument, OrderCommand.BUY, 0.001);
}
}
@Override
public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
}
@Override
public void onMessage(IMessage message) throws JFException {
IOrder order = message.getOrder();
if(order == null || message.getType() == IMessage.Type.NOTIFICATION){
return;
}
List<IMessage.Type> messageTypes = messages.get(order);
if(messageTypes == null){
messageTypes = new ArrayList<IMessage.Type>();
messages.put(order, messageTypes);
}
messageTypes.add(message.getType());
if(message.getType() == IMessage.Type.ORDER_CLOSE_OK){
closeInProgress.remove(order);
if(messageTypes.containsAll(Arrays.asList(IMessage.Type.ORDER_SUBMIT_OK, IMessage.Type.ORDER_FILL_OK))){
console.getInfo().format("closed order %s has received all necessary messages: %s", order.getLabel(), messageTypes).println();
} else {
console.getErr().format("closed order %s has NOT received all necessary messages: %s", order.getLabel(), messageTypes).println();
}
messages.remove(order);
}
if(message.getReasons().contains(IMessage.Reason.ORDER_CHANGED_TP)){
tpSetInProgress.remove(order);
}
}
@Override
public void onAccount(IAccount account) throws JFException {
}
@Override
public void onStop() throws JFException {
}
}
The strategy sends a lot of requests at the same time to the server and as you see all necessary order change messages have been received by the
onMessage. You can use the same strategy to make sure that also manual-trading orders' messages get received - simply remove the parts of the strategy that generate the orders and modifies them.