// Merge special Buy with Buys, Sells with Sells for every open instrument
// Strategy does not change report of trade and exposure but only cleans multiple 
// open trades in one buy and one sell for a specific instrument 
// lots amount differ as how many trades joined together


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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.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.IUserInterface;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.Period;

public class Merge_Special_BUYwithBUY_SELLwithSELL implements IStrategy {


    private boolean mergeInProgress = false;
    private int counter = 0;
    private IEngine engine;
    private IContext context;
    private IConsole console;
    private IHistory history;
    private IUserInterface userInterface;
    
    
    @Configurable("Merge Buys with Buys")
    public boolean mergeBB= true;
    
    @Configurable("Merge Sells with Sell")
    public boolean mergeSS= true;
    
    
    @Override
    public void onStart(IContext context) throws JFException {
   
        context.getConsole();
        engine = context.getEngine();    
        
//remove after testing VVVVV
        engine.submitOrder("Buy_EURCHF1", Instrument.EURCHF, IEngine.OrderCommand.BUY, 0.001, 0, 2, 0, 0, 0, "B");
        engine.submitOrder("Buy_EURCHF2", Instrument.EURCHF, IEngine.OrderCommand.BUY, 0.01, 0, 2, 0, 0, 0, "B");
        engine.submitOrder("Buy_EURCHF3", Instrument.EURCHF, IEngine.OrderCommand.SELL, 0.1, 0, 2, 0, 0, 0, "B");
        engine.submitOrder("Buy_EURCHF4", Instrument.EURCHF, IEngine.OrderCommand.SELL, 0.01, 0, 2, 0, 0, 0, "B");
        engine.submitOrder("Buy_EURCHF5", Instrument.EURCHF, IEngine.OrderCommand.BUY, 0.01, 0, 2, 0, 0, 0, "B");
        engine.submitOrder("Sell_EURUSD6", Instrument.EURUSD, IEngine.OrderCommand.BUY, 0.1, 0, 2, 0, 0, 0, "S");
        engine.submitOrder("Sell_EURUSD7", Instrument.EURUSD, IEngine.OrderCommand.SELL, 0.01, 0, 2, 0, 0, 0, "S");
        engine.submitOrder("Sell_EURUSD8", Instrument.EURUSD, IEngine.OrderCommand.SELL, 0.01, 0, 2, 0, 0, 0, "S");
        engine.submitOrder("Sell_EURUSD9", Instrument.EURUSD, IEngine.OrderCommand.BUY, 0.1, 0, 2, 0, 0, 0, "S");
        engine.submitOrder("SellUSDCHF10", Instrument.USDCHF, IEngine.OrderCommand.BUY, 0.01, 0, 2, 0, 0, 0, "S");
        engine.submitOrder("SellUSDCHF11", Instrument.USDCHF, IEngine.OrderCommand.SELL, 0.1, 0, 2, 0, 0, 0, "S");
        engine.submitOrder("SellUSDCHF12", Instrument.USDCHF, IEngine.OrderCommand.BUY, 0.01, 0, 2, 0, 0, 0, "S");
        engine.submitOrder("SellUSDCHF13", Instrument.USDCHF, IEngine.OrderCommand.SELL, 0.1, 0, 2, 0, 0, 0, "S");
//remove after testing *******

    
    }
    
    public void onTick(Instrument instr, ITick tick) throws JFException {
        if(mergeBB) {megaMergeBUYS();}
        if(mergeSS) {megaMergeSELLS();}
            
    }
      
     
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {}
    public void onStop() throws JFException {
    }

    public IContext getContext() {
        return context;
    }

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

    public IConsole getConsole() {
        return console;
    }

    public void setConsole(IConsole console) {
        this.console = console;
    }

    public IHistory getHistory() {
        return history;
    }

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

    public IUserInterface getUserInterface() {
        return userInterface;
    }

    public void setUserInterface(IUserInterface userInterface) {
        this.userInterface = userInterface;
    }
    
    @Override
    public void onAccount(IAccount account) throws JFException {
    }
////merge////
    private void megaMergeBUYS() throws JFException {
        if (!mergeInProgress) {
            List<IOrder> allPositions = engine.getOrders();
            Map<Instrument, List<IOrder>> allByInstruments = new HashMap<Instrument, List<IOrder>>();
            for (IOrder order : allPositions) {
                if (order.isLong()) {////////
                    Instrument instr = order.getInstrument();
                    List<IOrder> orders = allByInstruments.get(instr);
                    if (orders == null) {
                        orders = new ArrayList<IOrder>();
                        allByInstruments.put(instr, orders);
                    }
                    orders.add(order);
                }
            } ///
            for (Instrument instr : allByInstruments.keySet()) {
                List<IOrder> list = allByInstruments.get(instr);
                if (list.size() > 1) {
                    mergeOrders(list);
                    mergeInProgress = true;
                }
            }
        }
    }

    private void megaMergeSELLS() throws JFException {
        if (!mergeInProgress) {
            List<IOrder> allPositions = engine.getOrders();
            Map<Instrument, List<IOrder>> allByInstruments = new HashMap<Instrument, List<IOrder>>();
            for (IOrder order : allPositions) {
                if (!order.isLong()) {////////
                    Instrument instr = order.getInstrument();
                    List<IOrder> orders = allByInstruments.get(instr);
                    if (orders == null) {
                        orders = new ArrayList<IOrder>();
                        allByInstruments.put(instr, orders);
                    }
                    orders.add(order);
                }
            } ///
            for (Instrument instr : allByInstruments.keySet()) {
                List<IOrder> list = allByInstruments.get(instr);
                if (list.size() > 1) {
                    mergeOrders(list);
                    mergeInProgress = true;
                }
            }
        }
    }

    public void mergeOrders(List<IOrder> positions) throws JFException {

        if (positions == null || positions.size() == 0) {
            return;
        }
        engine.mergeOrders("Merged" + counter + System.currentTimeMillis(), positions.toArray(new IOrder[0]));
        counter++;
    }

    public void onMessage(IMessage message) throws JFException {
    }///end////merge////
}
