Unfortunately I can't fully disclose the code.
A very simplified version looks like this (the original is over 1000 lines).
I deleted all irrelevant lines and kept the maintaining code untouched as much as possible. I's important to note however that the original code can have 3 OrderProcess threads running concurrently. I log all output (including error output) to a logfile in which I didn't find any exceptions or errors.
Regarding submitorder()/trading:
In the original version the instrument and orderCommand can change. The slippage and amount(defaultAmount) are 'static' once the strategy starts as in this version (exact same variables).
package com.forex.strategies;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.SimpleTimeZone;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.dukascopy.api.*;
import com.dukascopy.api.IEngine.OrderCommand;
public class StrategyBughunter implements IStrategy{
private double defaultAmount = 0.001;
private double defaultSlippage = 0;
private IContext context;
private IEngine engine;
private IConsole console;
private Instrument mainInstrument = Instrument.GBPCHF;
private OrderProcess orderProcess = new OrderProcess();
{
orderProcess.start();
}
@Override
public void onStart(IContext context) throws JFException {
this.context = context;
engine = context.getEngine();
this.console = context.getConsole();
}
@Override
public void onStop() throws JFException {
for (IOrder order : engine.getOrders()) {
order.close();
}
}
@Override
public void onTick(Instrument instrument, ITick tick) throws JFException {
/*
* Do some smart thing and start trading once you think you can
*/
if(Math.random() > 0.99){
orderProcess.sendEntrySignal(OrderCommand.BUY, tick);
}
}
public class OrderProcess extends Thread{
private Object entryWaitObject = new Object();
private ITick entrySignal;
private OrderCommand orderCommand;
private volatile IOrder order;
private double price;
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
public OrderProcess(){
dateFormat.setCalendar(Calendar.getInstance(new SimpleTimeZone(0, "GMT")));
}
public void sendEntrySignal(OrderCommand orderCommand, ITick tick){
synchronized(entryWaitObject){
if(entrySignal == null){
this.orderCommand = orderCommand;
entrySignal = tick;
entryWaitObject.notify();
}
}
}
public void run(){
while (true) {
entrySignal = null;
order = null;
/* --------------------------------
* Wait for Entry Signal
-------------------------------- */
synchronized(entryWaitObject) {
do{
try{
entryWaitObject.wait();
}catch(InterruptedException ignored){}
}while(entrySignal == null);
}
/* --------------------------------
* About to Submit Order
-------------------------------- */
ITick mainTick = entrySignal;
price = (orderCommand == OrderCommand.BUY || orderCommand == OrderCommand.PLACE_BID ? mainTick.getAsk() : mainTick.getBid());
/* --------------------------------
* Submit Order
-------------------------------- */
Future<IOrder> future = context.executeTask(
new Callable<IOrder>() {
public IOrder call() {
try {
Instrument mainCP = mainInstrument;
int num = engine.getOrders(mainCP).size() + 1;
return engine.submitOrder("Order_" + mainCP.getPrimaryCurrency() + mainCP.getSecondaryCurrency() + num, mainCP, orderCommand, defaultAmount, price, defaultSlippage);
} catch (JFException e) {
e.printStackTrace(console.getOut());
return null;
}
}
});
try {
order = future.get();
/*
* do some other smart things, close position and take profit
*/
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) {
}
@Override
public void onAccount(IAccount account) throws JFException {
}
@Override
public void onMessage(IMessage message) throws JFException {
}
}