import java.text.DecimalFormat;
import com.dukascopy.api.Configurable;
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.IEngine.OrderCommand;
import com.dukascopy.api.IHistory;
import com.dukascopy.api.IMessage;
import com.dukascopy.api.IOrder;
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 Grids_ifSNBN_Buy_ifBNSN_Sell implements IStrategy {

    private IEngine engine;
    private IConsole console;
    private int counter = 0;
    private IHistory history;
    private ITick previousTick = null;
    private String string = "";

    @Configurable("Step pips")
    public double step = 20;

    @Configurable("Instrument")
    public Instrument instrument = Instrument.EURUSD;

    @Configurable("Slippage")
    public double slippage = 2;

    @Configurable("Amount")
    public double amount = 0.1;

    public double tpSELLS = 0;

    @Configurable("Stop Loss SELLS")
    public int slSELLS = 0;

    public double tpBUYS = 0;

    @Configurable("Stop Loss BUYS")
    public int slBUYS = 0;

    @Configurable("Total take profit Money")
    public double tpProfit = 0;

    private double balance;

    @Configurable("Print All Info")
    public boolean print = false;

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

        balance = context.getAccount().getEquity();
        console.getOut().println("initial balance " + (new DecimalFormat("#.#######")).format(balance));

    }

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

    public void onTick(Instrument instrument, ITick tick) throws JFException {
        if (instrument != this.instrument) {
            return;
        }
        if (previousTick == null) {
            previousTick = tick;
            return;
        }

        if (tick.getBid() >= previousTick.getBid() + getPipPrice(step) && tradesTotalBUY(instrument) == 0) {
            tpBUYS = step;
            string = "Buy_" + tpBUYS;
            submitOrderBUY(OrderCommand.BUY, instrument);
            previousTick = tick;

        }
        if (tick.getAsk() <= previousTick.getAsk() - getPipPrice(step) && tradesTotalSELL(instrument) == 0) {
            tpSELLS = step;
            string = "Sell_" + tpSELLS;
            submitOrderSELL(OrderCommand.SELL, instrument);
            previousTick = tick;

        }

        if (tick.getAsk() >= previousTick.getAsk() + getPipPrice(step)
                && tradesTotalSELLNegatives(instrument) > tradesTotalBUYNegatives(instrument)) {
            string = "SN>BN_" + tpBUYS;
            submitOrderBUY(OrderCommand.BUY, instrument);
            previousTick = tick;

        }
        if (tick.getAsk() <= previousTick.getAsk() - getPipPrice(step)
                && tradesTotalBUYNegatives(instrument) > tradesTotalSELLNegatives(instrument)) {
            string = "BN>SN_" + tpSELLS;
            submitOrderSELL(OrderCommand.SELL, instrument);
            previousTick = tick;
        }

    }

    private IOrder submitOrderBUY(OrderCommand orderCmd, Instrument instrument) throws JFException {

        double stopLossPrice = 0.0, takeProfitPrice = 0.0;
        if (slBUYS > 0) {
            stopLossPrice = history.getLastTick(instrument).getBid() - getPipPrice(slBUYS);
        }
        if (tpBUYS > 0) {
            takeProfitPrice = history.getLastTick(instrument).getBid() + getPipPrice(tpBUYS);
        }
        return engine.submitOrder(getLabel(instrument), instrument, orderCmd, amount, 0, slippage, stopLossPrice,
                takeProfitPrice, 0, string);
    }

    private IOrder submitOrderSELL(OrderCommand orderCmd, Instrument instrument) throws JFException {

        double stopLossPrice = 0.0, takeProfitPrice = 0.0;
        if (slSELLS > 0) {
            stopLossPrice = history.getLastTick(instrument).getBid() + getPipPrice(slSELLS);
        }
        if (tpSELLS > 0) {
            takeProfitPrice = history.getLastTick(instrument).getBid() - getPipPrice(tpSELLS);
        }
        return engine.submitOrder(getLabel(instrument), instrument, orderCmd, amount, 0, slippage, stopLossPrice,
                takeProfitPrice, 0, string);
    }

    private double getPipPrice(double pips) {
        return pips * this.instrument.getPipValue();
    }

    private String getLabel(Instrument instrument) {
        String label = instrument.name();
        label = label + (counter++);
        label = label.toUpperCase();
        return label;
    }

    public void onMessage(IMessage message) throws JFException {
        if (print) {
            print(message);
        }
    }

    public void onStop() throws JFException {
    }

    private void print(Object o) {
        console.getOut().println(o);
    }

    public IHistory getHistory() {
        return history;
    }

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

    public void onAccount(IAccount account) throws JFException {
        double pozitivebalance = balance + tpProfit;

        if (tpProfit > 0) {
            if (pozitivebalance < history.getEquity()) {
                for (IOrder order : engine.getOrders()) {
                    if (order.getState() != IOrder.State.CLOSED && order.getState() != IOrder.State.CANCELED) {
                        order.close();
                    }
                }
                balance = account.getEquity();
                console.getOut().println(
                        "UP balance " + (new DecimalFormat("#.#######")).format(balance) + "Trades=" + counter);
                counter = 1;
            }
        }
    }

    public int tradesTotalBUY(Instrument instrument) throws JFException {
        int counter1 = 0;
        for (IOrder ORD : engine.getOrders(instrument)) {
            if (ORD.getState() == IOrder.State.FILLED && ORD.isLong()) {
                counter1++;
            }
        }
        return counter1;
    }

    public int tradesTotalSELL(Instrument instrument) throws JFException {
        int counter2 = 0;
        for (IOrder ORD : engine.getOrders(instrument)) {
            if (ORD.getState() == IOrder.State.FILLED && !ORD.isLong()) {
                counter2++;
            }
        }
        return counter2;
    }

    public int tradesTotalBUYNegatives(Instrument instrument) throws JFException {
        int tradesTotalBUYNegatives = 0;
        for (IOrder ORD : engine.getOrders(instrument)) {
            if (ORD.getState() == IOrder.State.FILLED && ORD.isLong() && ORD.getProfitLossInPips() < 0) {
                tradesTotalBUYNegatives++;
            }
        }
        return tradesTotalBUYNegatives;
    }

    public int tradesTotalSELLNegatives(Instrument instrument) throws JFException {
        int tradesTotalSELLNegatives = 0;
        for (IOrder ORD : engine.getOrders(instrument)) {
            if (ORD.getState() == IOrder.State.FILLED && !ORD.isLong() && ORD.getProfitLossInPips() < 0) {
                tradesTotalSELLNegatives++;
            }
        }
        return tradesTotalSELLNegatives;
    }
}
