Consider the example which shows that the functionality in question works as expected (see as well the provided full list of current filled orders).
package jforex.strategies.test;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.TimeZone;
import com.dukascopy.api.*;
import com.dukascopy.api.IEngine.OrderCommand;
/**
* The strategy maintains a list of 4 orders and on any change in the order list,
* prints out the information about the last buy order, the last sell order
* and the current list of orders
*/
public class OnTickBug3010Refute implements IStrategy {
private IEngine engine;
private IHistory history;
private IConsole console;
private int stopLossPips = 60;
private int takeProfitPips = 40;
private double amount = 0.001;
private Instrument instrument = Instrument.EURUSD;
private int counter;
private List<IOrder> orders;
private int minOrderCount = 4;
//user's magic constant
private String magic = "O";
private String lastOnTickInfo;
private SimpleDateFormat sdf;
@Override
public void onStart(IContext context) throws JFException {
this.engine = context.getEngine();
this.history = context.getHistory();
this.console = context.getConsole();
String DATE_FORMAT_NOW = "HH:mm:ss"; //yyyy-MM-dd
sdf = new SimpleDateFormat(DATE_FORMAT_NOW);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
//create 4 orders
orders = new ArrayList<IOrder>();
orders.add(submitOrder(OrderCommand.BUY, magic));
orders.add(submitOrder(OrderCommand.BUY, magic));
orders.add(submitOrder(OrderCommand.SELL, magic));
orders.add(submitOrder(OrderCommand.SELL, magic));
}
@Override
public void onTick(Instrument instrument, ITick tick) throws JFException {
long lastBuyTime = 0, lastSellTime = 0;
double lastBuyPrice = 0, lastSellPrice = 0;
String label = "";
//concat. all active order info
String orderInfo = "ORDERS: ";
for (IOrder order : engine.getOrders(instrument)) {
label = order.getLabel();
if (!label.startsWith(magic))
continue;
if (order.getState() != IOrder.State.FILLED)
continue;
orderInfo+= order.getLabel() + ", " + sdf.format(order.getFillTime()) + "; ";
if (order.getOrderCommand().equals(IEngine.OrderCommand.BUY)) {
if (order.getFillTime() > lastBuyTime) {
lastBuyTime = order.getFillTime();
lastBuyPrice = order.getOpenPrice();
}
}
if (order.getOrderCommand().equals(IEngine.OrderCommand.SELL)) {
if (order.getFillTime() > lastSellTime) {
lastSellTime = order.getFillTime();
lastSellPrice = order.getOpenPrice();
}
}
}
String onTickInfo = "__label: " + label +
" lastBuyTime: " + sdf.format(lastBuyTime) + " lastBuyPrice: " + (new DecimalFormat("#.0000")).format(lastBuyPrice)
+ " lastSellTime: " + sdf.format(lastSellTime) + " lastSellPrice: " + (new DecimalFormat("#.0000")).format(lastSellPrice);
//print only if the string had changed
if(lastBuyTime + lastSellTime > 0 && !onTickInfo.equals(lastOnTickInfo)){
print(onTickInfo + " " + orderInfo);
lastOnTickInfo = onTickInfo;
}
//retain only active orders
orders.retainAll(engine.getOrders(instrument));
//if some order (or orders) has been closed/cancelled we create a new one
while(orders.size() < minOrderCount){
orders.add(submitOrder(getRandomOrderCommand(), magic));
}
}
@Override
public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
// TODO Auto-generated method stub
}
@Override
public void onMessage(IMessage message) throws JFException {
print(sdf.format(message.getCreationTime()) + " - " + message.getOrder().getLabel() + ": " + message.getContent());
}
@Override
public void onAccount(IAccount account) throws JFException {
// TODO Auto-generated method stub
}
@Override
public void onStop() throws JFException {
// TODO Auto-generated method stub
}
private IOrder submitOrder(OrderCommand orderCmd, String prefix) throws JFException {
double stopLossPrice, takeProfitPrice;
// Calculating stop loss and take profit prices
if (orderCmd == OrderCommand.BUY) {
stopLossPrice = history.getLastTick(this.instrument).getBid() - getPipPrice(this.stopLossPips);
takeProfitPrice = history.getLastTick(this.instrument).getBid() + getPipPrice(this.takeProfitPips);
} else {
stopLossPrice = history.getLastTick(this.instrument).getAsk() + getPipPrice(this.stopLossPips);
takeProfitPrice = history.getLastTick(this.instrument).getAsk() - getPipPrice(this.takeProfitPips);
}
// Submitting an order for the specified instrument at the current market price
return engine.submitOrder(getLabel(instrument, prefix, orderCmd), this.instrument, orderCmd, this.amount, 0, 20, stopLossPrice, takeProfitPrice);
}
protected String getLabel(Instrument instrument, String prefix, OrderCommand orderCmd) {
return (prefix + "_" + orderCmd.toString() + "_"+ instrument.name() + "_" + (new DecimalFormat("00.#")).format((counter++))).toUpperCase();
}
private void print(String message) {
console.getOut().println(message);
}
private OrderCommand getRandomOrderCommand(){
return ( new Random()).nextInt(2) == 0 ? OrderCommand.BUY : OrderCommand.SELL ;
}
private double getPipPrice(int pips) {
return pips * this.instrument.getPipValue();
}
}
Nevertheless, if this example doesn't correspond to your problem, please provide a more precise algorithm which would expose the bug.