If a trader opens identical orders simultaneously in JForex DEMO version and in JForex LIVE version, he receives different prices, even if both have the same attributes and are sent at the same time.
We tested LIVE and DEMO account trading with a very simple program, find the source code below and the same compiled version attached. Be aware: It does open trades!
We attached a screenshot after 5 Trades which shows the positions tab from a DEMO and from a LIVE version. The Ext. IDs show the simultaneous entries.
As you can see
* the open price is different
* the current tick differs
* P/L is different
That means if a trader tests a strategy with the same conditions on a DEMO and on a LIVE version, independently of manual or automatic trading, he gets different results and P/L!
Why are DEMO and LIVE so different in trading behavior?
How can a trader get the same entries and exits in DEMO and LIVE?
![Image](https://www.dukascopy.com/swiss/english/forex/jforex/forum/download/file.php?id=941)
/*
* This is a test programm only, do not use for trading!
* It measures latency time for an instrument.
* The entry is based on the client's system time
* It buys every full amount of system ms, e.g 30000 ms
* It does not close bars, but a stoploss is used
* The label contains the current System time in ms when the order is opened
*
* The following times are measured
* Strategy Delta: this is the time between the strategy sends a submit order and order is filled
* JForex Delta: this is the time between an order is created and filled. Therefore it is
* partial of Strategy Delta
*
* (c) Stash GmbH München
* Author: Bernhard Schicht
* [email protected]
* www.stash.de
*/
package jforex;
import java.util.*;
import com.dukascopy.api.*;
import com.dukascopy.api.IEngine.OrderCommand;
import java.util.Collections;
import java.util.HashMap;
import java.util.concurrent.Callable;
public class LatencyTest6 implements IStrategy {
private IEngine engine;
private IConsole console;
private IHistory history;
private IContext context;
private IIndicators indicators;
private IUserInterface userInterface;
// test on ten seconds bars
private Period theperiod = Period.TEN_SECS;
// stores the time open
public Map<IOrder,Long> timeOpen;
// count new bars
private int newBars = 0;
// contains later random number of bars
private int rndBars = 0;
// accumulate strategy delta latency times
private long accStratDelta = 0;
// accumulate JForex delta latency times
private long accJForexDelta = 0;
// count elements for average calculation
private int deltaCount;
// determines if last trade was long. It is uses for alternation
private boolean lastwaslong = false;
@Configurable("Instrument") public Instrument theinstrument = Instrument.EURUSD;
@Configurable("Trade Volume") public double tradeVolume = 1000D;
@Configurable("trade on full system ms") public int msTrader = 10000;
@Configurable("max. trades ") public int maxTradesPerInstrument = 5;
@Configurable("Stoploss in Pips") public int stopLossPips = 20;
@Configurable("Slippage in Pips") public int slippage = 5;
public void onStart(final IContext context) throws JFException {
this.engine = context.getEngine();
this.console = context.getConsole();
this.history = context.getHistory();
this.context = context;
this.indicators = context.getIndicators();
this.userInterface = context.getUserInterface();
// init
timeOpen = Collections.synchronizedMap(new HashMap<IOrder,Long>());
Thread execute = new Thread(new Runnable(){
public void run() {
while(!context.isStopped() && timeOpen.size() < maxTradesPerInstrument){
if ( System.currentTimeMillis()%msTrader == 0){
// open demo order
context.executeTask(new Callable<Boolean>() {
public Boolean call() {
OrderCommand oc = null;
double price = 0D;
ITick lastTick = null;
try{
lastTick = history.getLastTick(theinstrument);
}
catch(Exception e) {
e.printStackTrace(console.getErr());
}
if (lastTick == null) return new Boolean(false);
double currentInstrumentSL = 0D;
double currentPipValue = theinstrument.getPipValue();
if (!lastwaslong) {
oc = OrderCommand.BUY;
lastwaslong = true;
price = lastTick.getAsk();
currentInstrumentSL = price - stopLossPips*currentPipValue;
}
else{
oc = OrderCommand.SELL;
lastwaslong = false;
price = lastTick.getBid();
currentInstrumentSL = price + stopLossPips*currentPipValue;
}
// save time just before opened
long tempTime = System.currentTimeMillis();
String label = "Test"+tempTime;
IOrder currentOrder = null;
try{
currentOrder = engine.submitOrder(
label,theinstrument,
oc, tradeVolume/1000000D, price,
slippage, currentInstrumentSL,
0D
);
}
catch(Exception e) {
e.printStackTrace(console.getErr());
}
if (currentOrder != null) timeOpen.put(currentOrder, tempTime);
return new Boolean(true);
}
});
}
sleep(1);
}
context.stop();
}
});
execute.start();
}
public void onAccount(IAccount account) throws JFException {
}
// print time after order is filled
public void onMessage(IMessage message) throws JFException {
// if order is not filled return
if (message.getType() != IMessage.Type.ORDER_FILL_OK) return;
// search for the right order
for (IOrder order : timeOpen.keySet()){
if (message.getOrder() != order) continue;
// creation time of DC order
long timeOpenCreation = order.getCreationTime();
// get filltime of DC order
long timeOpenFillTime = order.getFillTime();
long jForexDelta = timeOpenFillTime-timeOpenCreation;
accJForexDelta += jForexDelta;
// get time order send was initially started by strategy
long timeOpenSend = timeOpen.get(order).longValue();
// get system time now
long systemTime = System.currentTimeMillis();
long strategyDelta = systemTime - timeOpenSend;
accStratDelta += strategyDelta;
deltaCount++;
double stratDeltaAverage = Math.round(accStratDelta/deltaCount);
double stratJForexAverage = Math.round(accJForexDelta/deltaCount);
p(order.getInstrument().toString()+" order ID = "+order.getId()+": openPrice ="+order.getOpenPrice()+", Strategy Delta = "+strategyDelta+" ms"+", in average["+deltaCount+"] = "+stratDeltaAverage+" ms");
p(order.getInstrument().toString()+" order ID = "+order.getId()+": openPrice ="+order.getOpenPrice()+", JForex Delta = "+jForexDelta+" ms"+", in average["+deltaCount+"] = "+stratJForexAverage+" ms");
break;
}
}
public void onStop() throws JFException {
}
public void onTick(Instrument instrument, ITick tick) throws JFException {
}
public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
}
public static void sleep(long millis) {
try { Thread.sleep(millis);
}
catch (final InterruptedException e) {
// Ignore; we did our best. - } }
}
}
public void p(String text){
console.getOut().println(text);
}
}