I think it's a bug that the IEngine.broadcast pacing does
not appear to be on a per-Strategy basis.
Each strategy instance should be able to pace itself with the
mandatory delay of 1000+ msecs since the last broadcast
and function correctly, avoiding the pacing exception.
But, correct me if I'm wrong, it appears this isn't true;
if you run the attached strategy it's just fine. But if you
concurrently run another instance of that strategy
(just copy and rename the .jfx) then we get the
exception constantly.
You'll need the Java Console running to see the exceptions.
com.dukascopy.api.JFException: Broadcast min period exceeded : 365 / 1000
at com.dukascopy.api.impl.connect.bh.broadcast(Unknown Source)
at com.fs.strategy.IEngineBroadcastBug$BroadcastExecutableTask.call(IEngineBroadcastBug.java:59)
at com.fs.strategy.IEngineBroadcastBug$BroadcastExecutableTask.call(IEngineBroadcastBug.java:1)
at com.dukascopy.api.impl.execution.k.call(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at com.dukascopy.api.impl.execution.g$a.f(Unknown Source)
at com.dukascopy.api.impl.execution.g$a.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: com.dukascopy.jss.JssException: Broadcast min period exceeded : 365 / 1000
at com.dukascopy.jss.b.j(Unknown Source)
... 9 more
com.dukascopy.api.JFException: Broadcast min period exceeded : 365 / 1000
at com.dukascopy.api.impl.connect.bh.broadcast(Unknown Source)
at com.fs.strategy.IEngineBroadcastBug$BroadcastExecutableTask.call(IEngineBroadcastBug.java:59)
at com.fs.strategy.IEngineBroadcastBug$BroadcastExecutableTask.call(IEngineBroadcastBug.java:1)
at com.dukascopy.api.impl.execution.k.call(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at com.dukascopy.api.impl.execution.g$a.f(Unknown Source)
at com.dukascopy.api.impl.execution.g$a.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: com.dukascopy.jss.JssException: Broadcast min period exceeded : 365 / 1000
at com.dukascopy.jss.b.j(Unknown Source)
... 9 more
...............forever
Feel free to hack it any way you want, but I think that
the IEngine.broadcast Mandatory delay should be per-Strategy. Otherwise,
with multiple Strategies using broadcast, there is almost
no way for them to avoid the minimum delay violation
as they are running concurrently.
In my case, I implemented a standalone client Global
pacing solution, but that's just not practical for ordinary
Strategy modules.
Apologies if I'm completely wrong here.....
Thanks for looking into this !!
HyperScalper
//package com.fs.strategy;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
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.IMessage;
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 IEngineBroadcastBug implements IStrategy {
IContext context = null;
IEngine engine = null;
IConsole console = null;
volatile private boolean isRunning = true;
volatile long lastBroadcastTimestamp = 0;
final private long now() {
return System.currentTimeMillis();
}
// waits until 1100 msecs has elapsed since
// the lastBroadcastTimestamp
final private void mandatoryDelay() {
long now = now();
if (lastBroadcastTimestamp==0) { // first time
lastBroadcastTimestamp = now;
return; // no delay
}
int elapsed = (int)(now - lastBroadcastTimestamp);
if (elapsed<1100) { // add an extra 100 msecs
int msecsWait = (1100-elapsed); // remainder to wait
if (msecsWait<10) msecsWait=10;
try {
Thread.sleep(msecsWait);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
// queued using IContext.executeTask(Callable)
class BroadcastExecutableTask implements Callable<Void> {
public Void call() {
try {
mandatoryDelay();
lastBroadcastTimestamp = now();
try {
console.getOut().println("broadcast...");
engine.broadcast("test","test");
}
catch(Exception e) {
e.printStackTrace();
}
}
catch(Exception e) {
e.printStackTrace();
}
return null;
}
}
public class BroadcastLoop implements Runnable {
public void run() {
while (isRunning) {
try {
Thread.sleep(1000);
}
catch(Exception e) {
e.printStackTrace();
}
if ( !isRunning) continue; // quit
BroadcastExecutableTask task = new BroadcastExecutableTask();
Future<Void> future = null;
try {
future = context.executeTask(task);
future.get(); // wait synchronous
}
catch(Exception e) {
e.printStackTrace();
}
} // end while
}
}
@Override
public void onStart(IContext context) throws JFException {
this.context = context;
this.console = context.getConsole();
this.engine = context.getEngine();
Thread runner = new Thread(new BroadcastLoop());
runner.start();
}
@Override
public void onTick(Instrument instrument, ITick tick) throws JFException {
// TODO Auto-generated method stub
}
@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 {
// TODO Auto-generated method stub
}
@Override
public void onAccount(IAccount account) throws JFException {
// TODO Auto-generated method stub
}
@Override
public void onStop() throws JFException {
isRunning=false; // allow for thread loop to exit
}
}