import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Stack;
import java.util.TimeZone;

import com.dukascopy.api.Configurable;
import com.dukascopy.api.Filter;
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.OfferSide;
import com.dukascopy.api.Period;


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.IHistory;
import com.dukascopy.api.IIndicators;
import com.dukascopy.api.IMessage;
import com.dukascopy.api.IOrder;
import com.dukascopy.api.IStrategy;
import com.dukascopy.api.ITick;
import com.dukascopy.api.IUserInterface;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.OfferSide;
import com.dukascopy.api.Period;
import com.dukascopy.api.IEngine.OrderCommand;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

import com.dukascopy.api.Configurable;

public class MFI_Indicator_SELL20_BUY80 implements IStrategy {
  private IIndicators indicators;

    private IEngine engine;
    private IConsole console;
    private IHistory history;
    private int counter = 0;

    private Stack<IOrder> buyOrdrs = new Stack<IOrder>();
    private Stack<IOrder> sellOrdrs = new Stack<IOrder>();

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

    @Configurable("Period")
      public Period period = Period.ONE_MIN;
    
    @Configurable("Time period")
      public int timePeriod = 5;
    
    @Configurable("Offer side")
    public OfferSide offerSide = OfferSide.BID;

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

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

    @Configurable("Filter")
    public Filter filter = Filter.ALL_FLATS;

    @Configurable("Take profit pips")
    public int takeProfitPips = 100;

    @Configurable("Stop loss in pips")
    public int stopLossPips = 100;


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

    @Configurable("Total take loss Money")
    public double ngProfit = 0;
    private double balance;

  public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    this.history = context.getHistory();
    this.indicators = context.getIndicators();
  }


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

  public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
    if (period != this.period || instrument != this.instrument) {
      return;
    }
    int shift = 1;
    double mfi = indicators.mfi(instrument, period, OfferSide.BID, timePeriod, shift);
    console.getOut().println(mfi);
    
    if (mfi>=80){sellOrdrs.push(submitOrder(OrderCommand.BUY, instrument));}
    else if (mfi<=20){buyOrdrs.push(submitOrder(OrderCommand.SELL, instrument));}
  }

    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 {
        print(message);
    }

    public void onStop() throws JFException {
    }

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

    public static String toStr(double[] arr) {
        String str = "";
        for (int r = 0; r < arr.length; r++) {
            str += "[" + r + "] " + (new DecimalFormat("#.#######")).format(arr[r]) + "; ";
        }
        return str;
    }

    public static String toStr(double[][] arr) {
        String str = "";
        if (arr == null) {
            return "null";
        }
        for (int r = 0; r < arr.length; r++) {
            for (int c = 0; c < arr[r].length; c++) {
                str += "[" + r + "][" + c + "] " + (new DecimalFormat("#.#######")).format(arr[r][c]);
            }
            str += "; ";
        }
        return str;
    }

    public String toStr(double d) {
        return (new DecimalFormat("#.#######")).format(d);
    }

    public String toStr(Long time) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") {

            private static final long serialVersionUID = 1L;

            {
                setTimeZone(TimeZone.getTimeZone("GMT"));
            }
        };
        return sdf.format(time);
    }

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

        double stopLossPrice = 0.0, takeProfitPrice = 0.0;
        if (orderCmd == OrderCommand.BUY) {
            if (stopLossPips > 0) {
                stopLossPrice = history.getLastTick(instrument).getBid() - getPipPrice(stopLossPips);
            }
            if (takeProfitPips > 0) {
                takeProfitPrice = history.getLastTick(instrument).getBid() + getPipPrice(takeProfitPips);
            }
        } else {
            if (stopLossPips > 0) {
                stopLossPrice = history.getLastTick(instrument).getBid() + getPipPrice(stopLossPips);
            }
            if (takeProfitPips > 0) {
                takeProfitPrice = history.getLastTick(instrument).getBid() - getPipPrice(takeProfitPips);
            }
        }

        return engine.submitOrder(getLabel(instrument), instrument, orderCmd, amount, 0, slippage, stopLossPrice,
                takeProfitPrice);
    }

    public void onAccount(IAccount account) throws JFException {
        ITick lastTick = history.getLastTick(instrument);

        double pozitivebalance = balance + tpProfit;
        double negativebalance = balance - ngProfit;

        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) + " Date  "
                        + getCurrentTime(lastTick.getTime()));
            }
        }
        if (ngProfit > 0) {
            if (negativebalance > history.getEquity()) {
                for (IOrder order : engine.getOrders()) {
                    if (order.getState() != IOrder.State.CLOSED && order.getState() != IOrder.State.CANCELED
                    // && order.getProfitLossInAccountCurrency()<0
                    ) {
                        order.close();
                    }
                }

                balance = account.getEquity();
                console.getOut().println("DOWN balance " + (new DecimalFormat("#.#######")).format(balance) + " Date  "
                        + getCurrentTime(lastTick.getTime()));
            }
        }
    }

    private String getCurrentTime(long time) {
        SimpleDateFormat sdf = new SimpleDateFormat();
        return sdf.format(time);
    }


}