With the following sample:
package de.invesdwin.forextrading.sample.orders;
import java.util.HashSet;
import java.util.Set;
import com.dukascopy.api.IAccount;
import com.dukascopy.api.IBar;
import com.dukascopy.api.IContext;
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;
import com.dukascopy.api.system.ISystemListener;
import com.dukascopy.api.system.ITesterClient;
import com.dukascopy.api.system.TesterFactory;
/**
* This small program demonstrates how to initialize Dukascopy client and start a strategy
*/
//CHECKSTYLE:OFF
//@NotThreadSafe
public final class OrderCloseAmount0Sample {
//CHANGE THIS IN THE SAMPLE BEFORE RUNNING
private static final String JNLP_URL = de.invesdwin.forextrading.ForexProperties.JFOREX_JNLP_URL.toString();
private static final String JNLP_USERNAME = de.invesdwin.forextrading.ForexProperties.JFOREX_JNLP_USERNAME;
private static final String JNLP_PASSWORD = de.invesdwin.forextrading.ForexProperties.JFOREX_JNLP_PASSWORD;
private OrderCloseAmount0Sample() {}
public static void main(final String[] args) throws Exception {
//get the instance of the IClient interface
final ITesterClient client = TesterFactory.getDefaultInstance();
//set the listener that will receive system events
client.setSystemListener(new ISystemListener() {
private int lightReconnects = 3;
@Override
public void onStart(final long processId) {
System.out.println("Strategy started: " + processId);
}
@Override
public void onStop(final long processId) {
System.out.println("Strategy stopped: " + processId);
if (client.getStartedStrategies().size() == 0) {
System.exit(0);
}
}
@Override
public void onConnect() {
System.out.println("Connected");
lightReconnects = 3;
}
@Override
public void onDisconnect() {
System.err.println("Disconnected");
if (lightReconnects > 0) {
client.reconnect();
--lightReconnects;
} else {
try {
//sleep for 10 seconds before attempting to reconnect
Thread.sleep(10000);
} catch (final InterruptedException e) {
e.printStackTrace();
}
try {
client.connect(JNLP_URL, JNLP_USERNAME, JNLP_PASSWORD);
} catch (final Exception e) {
e.printStackTrace();
}
}
}
});
System.out.println("Connecting...");
//connect to the server using jnlp, user name and password
client.connect(JNLP_URL, JNLP_USERNAME, JNLP_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()) {
System.err.println("Failed to connect Dukascopy servers");
System.exit(1);
}
//subscribe to the instruments
final Set<Instrument> instruments = new HashSet<Instrument>();
instruments.add(Instrument.EURUSD);
System.out.println("Subscribing instruments...");
client.setSubscribedInstruments(instruments);
//start the strategy
Thread.sleep(1000);
System.out.println("Starting strategy");
client.startStrategy(new IStrategy() {
private IContext context;
boolean orderCreated;
int label;
@Override
public void onTick(final Instrument instrument, final ITick tick) throws JFException {
if (orderCreated) {
if (context.getEngine().getOrders().size() == 0) {
throw new IllegalStateException("Order instantly closed automatically?!?");
}
if (context.getEngine().getOrders().size() > 1) {
throw new IllegalStateException("I did not create more than 1 order!");
}
for (final IOrder order : context.getEngine().getOrders()) {
order.close(0, 0, 0);
}
orderCreated = false;
} else {
context.getEngine().submitOrder("label_" + String.valueOf(label++), Instrument.EURUSD,
OrderCommand.BUY, 0.001, 0, 0, 0, 0, 0, null);
orderCreated = true;
}
}
@Override
public void onStop() throws JFException {}
@Override
public void onStart(final IContext context) throws JFException {
this.context = context;
}
@Override
public void onMessage(final IMessage message) throws JFException {
System.out.println(message);
}
@Override
public void onBar(final Instrument instrument, final Period period, final IBar askBar, final IBar bidBar)
throws JFException {}
@Override
public void onAccount(final IAccount account) throws JFException {}
});
//now it's running
}
}
You can reproduce the following exception:
2012-06-26 17:52:18,441 [ |StrategyRunner Thre] ERROR c.d.d.g.agent.strategy.tester.StrategyRunner.handleException - userType=Other Amount cannot be less than 1000
com.dukascopy.api.JFException: userType=Other Amount cannot be less than 1000
at com.dukascopy.dds2.greed.agent.strategy.tester.TesterCustodian.closeOrder(TesterCustodian.java:892) ~[greed-common-194.jar:194]
at com.dukascopy.dds2.greed.agent.strategy.tester.TesterOrder.close(TesterOrder.java:119) ~[greed-common-194.jar:194]
at de.invesdwin.forextrading.sample.orders.OrderCloseAmount0Sample$2.onTick(OrderCloseAmount0Sample.java:123) ~[bin/:na]
at com.dukascopy.dds2.greed.agent.strategy.tester.AbstractStrategyRunner.historicalTickReceived(AbstractStrategyRunner.java:609) ~[greed-common-194.jar:194]
at com.dukascopy.dds2.greed.agent.strategy.tester.StrategyRunner.run(StrategyRunner.java:469) ~[greed-common-194.jar:194]
at java.lang.Thread.run(Thread.java:679) [na:1.6.0_24]
This is caused by invoking the order close method with an amount of 0 to close all amount. The javadoc says the following:
/**
* Sends a request to close the position with specified amount, price and slippage.
* Position can not be closed in {@link State#CREATED}.
*
* @param amount closing amount. Can be less than opened amount, in this case partial close will take place. If 0 is provided then all
* amount will be closed
* @param price required close price. Close will be rejected if no liquidity at this price. This parameter doesn't affect
* entry (conditional) orders.
* @param slippage required price slippage.
* @throws JFException when called for order not in {@link State#FILLED} state
*/
public void close(double amount, double price, double slippage) throws JFException;
Though it seems the implementation throws an exception instead of closing all amount. It would be nice to have this feature behave as documented and close all amount if the parameter is 0.