Threading

Every strategy runs in its own thread. Method IContext.executeTask allows to execute critical operations (e.g., order submission) from a different thread.

Examples

Consider a task which submits an order with a stop loss price:

private class BuyTask implements Callable<IOrder> {
    private final Instrument instrument;
    private final double stopLossPips;

    public BuyTask(Instrument instrument, double stopLossPips) {
        this.instrument = instrument;
        this.stopLossPips = stopLossPips;
    }

    public IOrder call() throws Exception {
        double stopLossPrice = history.getLastTick(instrument).getBid() - stopLossPips * instrument.getPipValue();
        IOrder order = engine.submitOrder("Buy_order1"+System.nanoTime(), instrument, IEngine.OrderCommand.BUY, 0.001, 0, 20, stopLossPrice, 0);
        print("Created order: " + order.getLabel());
        return order;
    }
}

Synchronous execution

Consider executing the task synchronously, i.e. from the strategy thread:

BuyTask task = new BuyTask(Instrument.EURUSD, 40);
context.executeTask(task);  

Asynchronous execution

Consider executing the task asynchronously, i.e. from a different thread:

final IContext finalContext = context;
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            finalContext.executeTask(task);
        } catch (Exception e) {
            console.getErr().println(Thread.currentThread().getName() + " " + e);
        }
    }
    });
thread.start();

ThreadTest3.java

Scheduled asynchronous execution

Consider scheduling a task to execute at a fixed rate. Consider an example strategy which on its start creates an order and a horizontal line. Then it schedules a task which moves the horizontal line's price 5 pips above the order's open price whenever the order price changes.

package jforex.charts;

import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.dukascopy.api.*;
import com.dukascopy.api.IEngine.OrderCommand;

import com.dukascopy.api.drawings.IHorizontalLineChartObject;

/**
 * The strategy on its start creates an order and a horizontal line.
 * Then it schedules a task which moves the horizontal line's price
 * 5 pips above the order's open price whenever the order price changes.
 * 
 * On strategy stop the order gets closed and the line removed from the chart.
 * Also the executor service gets stopped, otherwise it would continue the task
 * execution as scheduled
 *
 */
@RequiresFullAccess
public class HLineScheduledExecutor implements IStrategy {

    private IChart chart;
    private IHistory history;
    private IConsole console;
    private IEngine engine;

    private Instrument instrument = Instrument.EURUSD;
    private double pip = Instrument.EURUSD.getPipValue();

    @Configurable("Execution interval in milliseconds")
    public long execIntervalMillis = 1000;

    private ScheduledExecutorService executor;
    private IOrder order;
    private IHorizontalLineChartObject hLine;

    @Override
    public void onStart(final IContext context) throws JFException {
        this.chart = context.getChart(instrument);
        this.history = context.getHistory();
        this.console = context.getConsole();
        this.engine = context.getEngine();
        ITick tick = history.getLastTick(instrument);  

        //create hline at price 0 and a conditional order 
        hLine = chart.getChartObjectFactory().createHorizontalLine("hLineKey", 0);
        chart.addToMainChart(hLine);        
        order = engine.submitOrder("orderWithHLine", instrument, OrderCommand.BUYSTOP, 0.001, tick.getAsk() + pip * 10);

        //create and schedule the task to run in a separate thread
        final HLineTask hlineTask = new HLineTask(order, hLine);        
        executor = Executors.newSingleThreadScheduledExecutor();

        Runnable periodicTask = new Runnable() {
            public void run() {
                context.executeTask(hlineTask);
            }
        };

        executor.scheduleAtFixedRate(periodicTask, 0, execIntervalMillis, TimeUnit.MILLISECONDS);
    }

    private class HLineTask implements Callable<Object>{
        private IOrder order;
        private IHorizontalLineChartObject hLine;      
        private double lastOpenPrice = 0;

        public HLineTask(IOrder order, IHorizontalLineChartObject hLine) {
            this.hLine = hLine;
            this.order = order;
        }

        public Object call() throws Exception {
            //on open price change move hline 5 pips above the open price
            if(Double.compare(lastOpenPrice, order.getOpenPrice()) != 0){
                hLine.setPrice(0, order.getOpenPrice() + pip * 5);
                console.getOut().println(String.format("Adjust hline price from %.5f to %.5f", lastOpenPrice, order.getOpenPrice()));
                lastOpenPrice = order.getOpenPrice();
            }
            return null;
        }
    }

    @Override
    public void onStop() throws JFException {
        executor.shutdown();
        if(order.getState() == IOrder.State.FILLED || order.getState() == IOrder.State.OPENED){
            order.close();
        }
        chart.remove(hLine);

    }

    @Override
    public void onMessage(IMessage message) throws JFException {}

    @Override
    public void onTick(Instrument instrument, ITick tick) throws JFException {    }

    @Override
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {}

    @Override
    public void onAccount(IAccount account) throws JFException {}

}

HLineScheduledExecutor.java

Schedule at concrete time

Consider scheduling a daily order creation at a concrete time:

@Override
public void onStart(final IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();

    Date dateOff = new Date(timeInMillis + TimeZone.getDefault().getRawOffset());

    if(dateOff.getTime() < System.currentTimeMillis()){
        console.getWarn().format("The scheduled time %s has passed - now it is %s. Will reschedule for the same time tomorrow", 
                DateUtils.format(dateOff.getTime()), DateUtils.format(System.currentTimeMillis())).println();
        dateOff = new Date(dateOff.getTime() + TimeUnit.DAYS.toMillis(1));
    }

    console.getOut().println("Time left till the order creation start: " + formatInterval(dateOff.getTime() - System.currentTimeMillis()));

    timer.scheduleAtFixedRate(new TimerTask(){
      @Override
      public void run() {
          context.executeTask(new Callable<IOrder>(){ 

              @Override
              public IOrder call() throws Exception {
                  if(orderCounter >= orderCount){
                      console.getOut().println("All orders created");
                      timer.cancel();
                      timer.purge();
                      context.stop();
                      return null;
                  }
                  String label = String.format("%s_%s_%s", orderPrefix, orderCounter++, TIME_FORMAT.format(System.currentTimeMillis()));
                  return engine.submitOrder(label, instrument, IEngine.OrderCommand.BUY, orderAmount);
              }});
      }
        }
    ,dateOff, timeUnit.toMillis(interval));
}

ScheduledTimeBuy.java

The information on this web site is provided only as general information, which may be incomplete or outdated. Click here for full disclaimer.