Simple Strategy

Follow the instructions described in Create a strategy section in order to create an empty strategy class before you begin.

Summary

The following strategy fetches a previous daily bar for the specified instrument in order to define the side of the initial order. If the close price of the bar is greater than the open price, long order is created. Otherwise, short order is created. For every winning trade the same side order is opened at the current market price with 5 pips Take Profit. For every losing trade the opposite side order is opened with the initial Take Profit.

Defining configurable parameters

In order to define configurable parameters for our strategy we'll use the @Configurable annotation. The following code fragment defines 4 configurable parameters: Instrument, Amount, Take profit, Stop loss and sets their default values.

Fields engine and history are used to submit orders and fetch bars from history respectively.

public class SimpleTpSlStrategy implements IStrategy {
    // Configurable parameters
    @Configurable("Instrument")
    public Instrument instrument = Instrument.EURUSD;
    @Configurable("Amount")
    public double amount = 0.001;
    @Configurable("Stop loss")
    public int slPips = 10;
    @Configurable("Take profit on loss")
    public int tpPipsOnLoss = 10;
    @Configurable("Take profit on profit")
    public int tpPipsOnProfit = 5;

Adding strategy services

Appropriate strategy services will be injected into strategy fields that have @JFXInject annotation. Supported types include IEngine, IContext, IConsole, IAccount, IDataService, IHistory, IIndicators, IUserInterface, JFUtils.

    @JFXInject public IEngine engine;
    @JFXInject public IHistory history;
    @JFXInject public IConsole console;
    @JFXInject public IContext context;
    @JFXInject public IOrder order;

The onStart method

The onStart method is called at the start of the strategy. We'll use it to create our initial order. The following code fragment fetches a previous daily bar from history, identifies the side of the initial order and submits the initial order.

Method submitOrder(double amount, OrderCommand orderCmd, double takeProfitPips) calculates the appropriate stop loss and take profit prices and creates a new order:

public void onStart(IContext context) throws JFException {
    // subscribe the instrument that we are going to work with
    context.setSubscribedInstruments(java.util.Collections.singleton(instrument));
    // Fetching previous daily bar from history
    IBar prevDailyBar = history.getBar(instrument, Period.DAILY, OfferSide.ASK, 1);
    // Identifying the side of the initial order
    OrderCommand orderCmd = prevDailyBar.getClose() > prevDailyBar.getOpen() 
            ? OrderCommand.BUY 
            : OrderCommand.SELL;
    // submitting the order with the specified amount, command and take profit
    submitOrder(amount, orderCmd, tpPipsOnLoss);
}

private void submitOrder(double amount, OrderCommand orderCmd, double tpPips) throws JFException {
    double slPrice, tpPrice;
        ITick lastTick = history.getLastTick(instrument);
        // Calculating stop loss and take profit prices
        if (orderCmd == OrderCommand.BUY) {
            slPrice = lastTick.getAsk() - slPips * instrument.getPipValue();
            tpPrice = lastTick.getAsk() + tpPips * instrument.getPipValue();
        } else {
            slPrice = lastTick.getBid() + slPips * instrument.getPipValue();
            tpPrice = lastTick.getBid() - tpPips * instrument.getPipValue();
        }
        // Submitting the order for the specified instrument at the current market price
        order = engine.submitOrder("ord"+ strategyID + System.currentTimeMillis(), instrument, orderCmd, amount, 0, 20, slPrice, tpPrice);
}

The onMessage method

The onMessage method is called whenever a new message is received in our case - everytime the order is closed. We will use it to create new orders whenever an order gets closed.

public void onMessage(IMessage message) throws JFException {
    if (message.getType() != Type.ORDER_CLOSE_OK
            || !message.getOrder().equals(order) //only respond to our own order close
        ) {
        return;
    }
    console.getInfo().format("%s closed with P/L %.1f pips", order.getLabel(), order.getProfitLossInPips()).println();
    if (message.getReasons().contains(IMessage.Reason.ORDER_CLOSED_BY_TP)) {
        // on close by TP we keep the order direction
        submitOrder(amount, order.getOrderCommand(), tpPipsOnProfit);
    } else if (message.getReasons().contains(IMessage.Reason.ORDER_CLOSED_BY_SL)) {
        //  on close by SL we change the order direction and use other TP distance
        OrderCommand orderCmd = order.isLong() ? OrderCommand.SELL : OrderCommand.BUY;
        submitOrder(amount, orderCmd, tpPipsOnLoss);
    } else {
        //on manual close or close by another strategy we stop our strategy
        console.getOut().println("Order closed either from outside the strategy. Stopping the strategy.");
        context.stop();
    }
}

public void onStop() throws JFException {
    if(order.getState() == IOrder.State.FILLED || order.getState() == IOrder.State.OPENED){
        order.close();
    }
}

Download

SimpleTpSlStrategy.java

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