
 
import java.util.*;
import java.text.*;
 
import com.dukascopy.api.*;
 
public class BollingerBandExample implements IStrategy {
    private IEngine engine;
    private IConsole console;
    private IHistory history;
    private IContext context;
    private IIndicators indicators;
    private IUserInterface userInterface;
 
    @Configurable("selectedInstrument:")
    public Instrument selectedInstrument = Instrument.EURUSD;
    @Configurable("selectedPeriod:")
    public Period selectedPeriod = Period.TEN_MINS;
    @Configurable("stopLossPips:")
    public int stopLossPips = 25;
    @Configurable("takeProfitPips:")
    public int takeProfitPips = 50;
 
    private boolean lowCross = false;
    private boolean upperCross = false;
 
    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd_HHmmss");
 
    public void onStart(IContext context) throws JFException {
        this.engine = context.getEngine();
        this.console = context.getConsole();
        this.setHistory(context.getHistory());
        this.setContext(context);
        this.indicators = context.getIndicators();
        this.setUserInterface(context.getUserInterface());
 
        context.setSubscribedInstruments(Collections.singleton(selectedInstrument), true);
    }
 
    public void onAccount(IAccount account) throws JFException {
    }
 
    public void onMessage(IMessage message) throws JFException {
    }
 
    public void onStop() throws JFException {
    }
 
    public void onTick(Instrument instrument, ITick tick) throws JFException {
       console.getOut().println("Instrument:" + instrument + " ask price:" + tick.getAsk());
    }
 
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
        if (!instrument.equals(selectedInstrument) || !period.equals(selectedPeriod)) {
            return;
        }


        long time = bidBar.getTime();
        Object[] indicatorResult = indicators.calculateIndicator(selectedInstrument, selectedPeriod, new OfferSide[] {OfferSide.BID},
                "BBANDS", new IIndicators.AppliedPrice[] {IIndicators.AppliedPrice.CLOSE}, new Object[] {20, 2.0, 2.0, 0}, Filter.WEEKENDS, 1, time, 0);
        double bollingerUpperValue = ((double[]) indicatorResult[0])[0];
        @SuppressWarnings("unused")
        double bollingerMiddleValue = ((double[]) indicatorResult[1])[0];
        double bollingerLowerValue = ((double[]) indicatorResult[2])[0];
 
        if (askBar.getClose() < bollingerLowerValue) {
            lowCross = true;
        }
        if (bidBar.getClose() > bollingerUpperValue) {
            upperCross = true;
        }
 
        if (lowCross && askBar.getClose() >= bollingerLowerValue) {
            boolean existLong = false;
            for (IOrder order : engine.getOrders(selectedInstrument)) {
                if (order.getState() == IOrder.State.OPENED || order.getState() == IOrder.State.FILLED) {
                    existLong = order.isLong();
                    if (existLong) {
                        break;
                    }
                }
            }
 
            if (!existLong) {
                double stopLoss = bidBar.getClose() - selectedInstrument.getPipValue() * stopLossPips;
                double takeProfit = bidBar.getClose() + selectedInstrument.getPipValue() * takeProfitPips;
 
                engine.submitOrder(getLabel(time), selectedInstrument, IEngine.OrderCommand.BUY, 0.1, 0, 5, stopLoss, takeProfit, 0, "");
            }
 
            upperCross = false;
            lowCross = false;
 
        } else if (upperCross && bidBar.getClose() <= bollingerUpperValue) {
            boolean existShort = false;
            for (IOrder order : engine.getOrders(selectedInstrument)) {
                if (order.getState() == IOrder.State.OPENED || order.getState() == IOrder.State.FILLED) {
                    existShort = !order.isLong();
                    if (existShort) {
                        break;
                    }
                }
            }
 
            if (!existShort) {
                double stopLoss = askBar.getClose() + selectedInstrument.getPipValue() * stopLossPips;
                double takeProfit = askBar.getClose() - selectedInstrument.getPipValue() * takeProfitPips;
 
                engine.submitOrder(getLabel(time), selectedInstrument, IEngine.OrderCommand.SELL, 0.1, 0, 5, stopLoss, takeProfit, 0, "");
            }
 
            upperCross = false;
            lowCross = false;
        }
    }
 
    private String getLabel(long time) {
        return "IVF" + DATE_FORMAT.format(time) + generateRandom(10000) + generateRandom(10000);
    }
 
    private String generateRandom(int n) {
        int randomNumber = (int) (Math.random() * n);
        String answer = "" + randomNumber;
        if (answer.length() > 3) {
            answer = answer.substring(0, 4);
        }
        return answer;
    }

    public IHistory getHistory() {
        return history;
    }

    public void setHistory(IHistory history) {
        this.history = history;
    }

    public IContext getContext() {
        return context;
    }

    public void setContext(IContext context) {
        this.context = context;
    }

    public IUserInterface getUserInterface() {
        return userInterface;
    }

    public void setUserInterface(IUserInterface userInterface) {
        this.userInterface = userInterface;
    }
}