package jforex;

import java.util.*;

import com.dukascopy.api.*;
import com.dukascopy.api.Configurable;
import com.dukascopy.api.IEngine;
import com.dukascopy.api.IAccount;
import com.dukascopy.api.IBar;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.IContext;
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.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.OfferSide;
import com.dukascopy.api.Period;
import com.dukascopy.api.IEngine.OrderCommand;
import com.dukascopy.api.IIndicators.MaType;

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


public class swapper implements IStrategy{
    //+--------------------------------------------------------+
    //|
    //| Инициализация либ
    //|
    //+--------------------------------------------------------+
    private IEngine engine;
    private IIndicators indicators;
    private IConsole console;
    private IContext context;
    private IAccount account;
    private SimpleDateFormat sdf;
    private IHistory history;
    private IOrder order;
    
    //+--------------------------------------------------------+
    //|
    //| Определение глобальных переменных 
    //| для последующего использования всей программой
    //|
    //+--------------------------------------------------------+
    public Period fixedPeriod = Period.TICK;               // Период
    public static String magic = "SWAPPER";                // Магич. индендификатор сделок
    
    public static OrderCommand BUY = OrderCommand.BUY;     // BUY Сигнал на покупку
    public static OrderCommand SELL = OrderCommand.SELL;   // SELL Сигнал на продажу
    
    
    @Configurable("Начальный лот")
    public double lot = 0.001;
    
    @Configurable("Инструмент")
    public Instrument inst = Instrument.AUDJPY;
    
    @Configurable("Take Profit")
    public double tp = 10;
    
    @Configurable("Stop (New Order after)")
    public double so = 8;
    
    //+--------------------------------------------------------+
    //|
    //| Закрытые(внутренние) переменные программы
    //|
    //+--------------------------------------------------------+
    public OfferSide side = OfferSide.BID;
    private int fastKPeriod = 5;
    private MaType slowDMaType =  MaType.SMA;
    private int slowKPeriod = 3;
    private MaType slowKMaType =  MaType.SMA;
    private int slowDPeriod = 3;
    private int shift = 0;
    private int counter = 0;
    
    private String parsedStartTime;
    private String parsedEndTime;
    
    
    
    
    
    
    //| Далее главные и основные функции (фундамент)
    
    //+--------------------------------------------------------+
    //|
    //| Функция вызывается при старте советника (не изменять)
    //|
    //+--------------------------------------------------------+
    public void onStart(IContext context) throws JFException {
        engine = context.getEngine();
        indicators = context.getIndicators();
        console = context.getConsole();
        
        print("Запуск / Start");
    }
    
    //+--------------------------------------------------------+
    //|
    //| Функция вызывается при каждом изменением бара
    //|
    //+--------------------------------------------------------+
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException 
    {/*
                // Если ордеров нет, открываем первый
        if(getorders_count(magic)==0)
        {
            createOrder(inst, bidBar, BUY, 0, 5, tp, so*1000);
            print("1 is open");
        }
        // Если есть ордера - начинаем танцы с бубном
        else
        {
            IOrder order = engine.getOrder(getlastorder());                // Получаем последний ордер
            /*if(order.getTakeProfitPrice()==0)                              // Если нет Profita выставляем
            {
                order.setTakeProfitPrice(order.getOpenPrice()+(tp*inst.getPipValue()));
                print("TP set");
            }*/
            
            // Если цена дошла до Stop - New Order, открывай новую позицию
          /*  if(order.getProfitLossInPips()<(so*(-1)))
            {
                createOrder(inst, bidBar, BUY, 0, 5, tp, so*1000);
                print("Stop :: New order");
            }
            //order.getOpenPrice()+(10*inst.getPipValue());
            //print(Double.toString(order.getOpenPrice()+(10*inst.getPipValue())));
            
            print(Double.toString(order.getProfitLossInPips()) );
        }
       // OrderCommand orderCommand = OrderCommand.BUY;
        //createOrder(instrument, bidBar, orderCommand);   
        */
    }
    
    //+--------------------------------------------------------+
    //|
    //| Функция вызывается каждый тик. 
    //| 1. Чаще чем onBar в 30-40 раз
    //| 2. примерно 10-20 раз в секунду
    //|
    //+--------------------------------------------------------+
    public void onTick(Instrument instrument, ITick tick) throws JFException
    {
        
        // Если ордеров нет, открываем первый
        if(getorders_count(magic)==0)
        {
            createOrder(inst, tick, BUY, 5);
            print("First is open");
        }
        // Если есть ордера - начинаем танцы с бубном
        else
        {
            order = engine.getOrder(getlastorder());                // Получаем последний ордер
            print(getlastorder()+ "::" +Double.toString(counter));
            
            if (order.getState() == IOrder.State.FILLED)
            {
	            /*if(order.getTakeProfitPrice()==0)                       // Если нет Profita выставляем
	            {
	                order.setTakeProfitPrice(order.getOpenPrice()+(tp*instrument.getPipValue()));
	                print("Order :: new take profit");
	            }*/
	            
	            // Если цена дошла до Stop - New Order, открывай новую позицию
	            if(order.getProfitLossInPips()<(so*(-1)))
	            {
	                createOrder(inst, tick, BUY, 5);
	                print("Stop :: New order");
	            }
                else if(order.getProfitLossInPips()>=tp)
                {
                    order.close();
                    print("Profit :: Close order");
                    counter--;
                }
            }
            //order.getOpenPrice()+(10*inst.getPipValue());
            //print(Double.toString(order.getOpenPrice()+(10*inst.getPipValue())));
            
            //print(Double.toString(order.getProfitLossInPips()) );
        }
       // OrderCommand orderCommand = OrderCommand.BUY;
        //createOrder(instrument, bidBar, orderCommand);
    }
    
    //+--------------------------------------------------------+
    //|
    //| Функция вызывается при завершении работы советника
    //|
    //+--------------------------------------------------------+
    public void onStop() throws JFException {
        print("Остановка / Stopping");
        
        // закрытие всех позиций
        //for (IOrder order : engine.getOrders()) {
        //    order.close();
        //}
    }
    
    // ???
    public void onAccount(IAccount account) throws JFException {
    }
    
    // ???
    public void onMessage(IMessage message) throws JFException {
    }
    
    
    
    
    
    // Далее идут технические посредственные функции
    
    //+--------------------------------------------------------+
    //|
    //| Выводит сообщение в терминал
    //|
    //+--------------------------------------------------------+
    public void print(String string) {
        console.getOut().println(string);
    }
    
    //+--------------------------------------------------------+
    //|
    //| Остановка робота + комментарий.
    //|
    //+--------------------------------------------------------+
    public void stop(String comment)
    {
        print(comment);
        context.stop();
    }
    
    //+--------------------------------------------------------+
    //|
    //| Считает уникальный ID поз. (уникальный номер/фраза/код)
    //|
    //+--------------------------------------------------------+
    public String getLabel(Instrument instrument) {
        String label = magic+"_"+instrument.name();
        label = label + (counter++);
        label = label.toUpperCase();
        return label;
    }
    
    //+--------------------------------------------------------+
    //|
    //| Ограничение торговли временем (если используется)
    //|
    //+--------------------------------------------------------+
    public boolean isTime(long tickTime) {
 
        String formattedTickTime = sdf.format(tickTime); 
        formattedTickTime = formattedTickTime.replace(":", "");
 
        int tickTimeValue = Integer.parseInt(formattedTickTime);
        int startTimeValue = Integer.parseInt(parsedStartTime);
        int endTimeValue = Integer.parseInt(parsedEndTime);
 
        if (startTimeValue < endTimeValue){
            if ((tickTimeValue > startTimeValue) && (tickTimeValue < endTimeValue)){
                return true;
            }
        // Else swap time range and calculate valid time 
        } else {
            int tmpTimeValue = startTimeValue;
            startTimeValue = endTimeValue;
            endTimeValue = tmpTimeValue;
            if ((tickTimeValue < startTimeValue) || (tickTimeValue >= endTimeValue)){
                return true;
            }
        }
        return false;
    }
    
    
    
    
    // Далее идут торговые функции, открытие, закрытие, изменение позиций
 
    //+--------------------------------------------------------+
    //|
    //| Закрытие ВСЕХ позициий
    //|
    //+--------------------------------------------------------+
    private void closeOppositeIfExist(OrderCommand command) throws JFException
    {
        if (engine.getOrders().size() == 0) { return; }            // Если ордеров нет, то выходим
        
        /*for (IOrder order: engine.getOrders())                     // Закрытие ордеров по очереди
        {
            if (!order.getOrderCommand().equals(command))
            {
                order.close();
            }
        }*/
    }
    
    //+--------------------------------------------------------+
    //|
    //| Создание новой позициии/ордера
    //|
    //+--------------------------------------------------------+
    public void createOrder(Instrument instrument, ITick tick, OrderCommand orderCommand,double slippage) throws JFException
    {
        // Отправляем ордер
        engine.submitOrder(getLabel(instrument), instrument, orderCommand, lot, 0, slippage);
    }
    
    /*public void modifyOrder()
    {
        // Подсчет ТП и СЛ
        if (orderCommand == BUY) {
            sl = tick.getBid() - (sl*instrument.getPipValue());
            tp = tick.getBid() + (tp*instrument.getPipValue());
           // price = tick.getBid();
        } else {
            sl = tick.getAsk() + (sl*instrument.getPipValue());
            tp = tick.getAsk() - (tp*instrument.getPipValue());
           // price = tick.getAsk();
        }
    }*/
    
    //+--------------------------------------------------------+
    //|
    //| Возвращает строку с Label последнего ордера
    //|
    //+--------------------------------------------------------+
    public String getlastorder()
    {
        String ret = magic + "_" + inst.name();
        
        if(counter<=0)
        {
            ret = ret + (counter);
        }
        else
        {
            ret = ret + (counter-1);
        }
        
        ret.toUpperCase();
        return(ret);
    }

    //+--------------------------------------------------------+
    //|
    //| Получаем все ордера + фильтр по label-у
    //|
    //+--------------------------------------------------------+
    public int getorders_count(String filter) throws JFException
    {
        int i=0;
        
        // Если фильтра нет
        for (IOrder order: engine.getOrders())                     // Закрытие ордеров по очереди
        {
            if(filter=="-" || filter=="")
            {
                i++;
            }
            else
            {
                if(substr_count(filter,order.getLabel())>=1)
                {
                    i++;
                }
            }
        }

        return(i);
    }
    
    //+--------------------------------------------------------+
    //|
    //| Проверяет есть ли в тексте string строка subString
    //|
    //+--------------------------------------------------------+
    public int substr_count(String subString,String string) {
        if (string.length() < subString.length())
            return(-1);

        int patternHash = 0;
        int currentHash = 0;

        for (int i = 0; i < subString.length(); i++) {
            patternHash += subString.charAt(i);
            currentHash += string.charAt(i);
        }

        int end = string.length() - subString.length() + 1;
        for (int i = 0; i < end; i++) {
            if (patternHash == currentHash)
                if (string.regionMatches(i, subString, 0, subString.length()))
                    return(1);

            currentHash -= string.charAt(i);
            if (i != end - 1)
                currentHash += string.charAt(i + subString.length());
        }

        return(0);
    }
}
