package jforex.account;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.dukascopy.api.*;
import static com.dukascopy.api.Instrument.*;

/**
 * The strategy demonstrates how to maintain multiple sub-accounts
 * and calculate their equities.
 * 
 * In order to test the strategy, launch it with live-data and do
 * manual trading with the instruments that have been defined for the mini accounts
 *
 */
public class MutliEquities implements IStrategy {

    private IConsole console;    
    private List<MiniAccount> miniAccounts = new ArrayList<MiniAccount>();    
    MiniAccount eurAccount, usdAccount;
    
    @Override
    public void onStart(IContext context) throws JFException {
        console = context.getConsole();

        //define two mini accounts with base equity of 10K USD and designated set of instruments
        miniAccounts.add(new MiniAccount(10000, EURUSD, EURCHF));
        miniAccounts.add(new MiniAccount(10000, USDCAD, USDJPY, USDCHF));
        
    }

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

    @Override
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
        if(instrument != Instrument.EURUSD || period != Period.TEN_SECS){
            return;
        }
        //print data of all sub-accounts
        for (MiniAccount miniAccount : miniAccounts){
            console.getOut().println(miniAccount);
            
        }
    }

    @Override
    public void onMessage(IMessage message) throws JFException {
        //on any order fill add it to MiniAccount which has the particular instrument
        if(message.getType() == IMessage.Type.ORDER_FILL_OK){
            IOrder order =message.getOrder();
            //add order to particular mini account if the mini account has the order's instrument
            for (MiniAccount miniAccount : miniAccounts){
                if(miniAccount.hasInstrument(order.getInstrument())){
                    miniAccount.addOrder(order);
                }
            }
        }
    }

    @Override
    public void onAccount(IAccount account) throws JFException {
        // TODO Auto-generated method stub

    }

    @Override
    public void onStop() throws JFException {
        // TODO Auto-generated method stub

    }

}

/**
 * The class represents a sub-account which has a designated base equity
 * and contains its own set of orders
 */
class MiniAccount {
    
    private final List<IOrder> orders = new ArrayList<IOrder>();
    private final Set<Instrument> instruments;
    private final double baseEquity;
    
    public MiniAccount (double baseEquity, Instrument...instruments){
        this.instruments = new HashSet<Instrument> (Arrays.asList(instruments));
        this.baseEquity = baseEquity;
    }
    
    public void addOrder (IOrder order){
        orders.add(order);
    }
    
    public boolean hasInstrument(Instrument instrument){
        return instruments.contains(instrument);
    }
    
    public double getEquity(){        
        double profitLoss = 0d;        
        for (IOrder o : orders){
            profitLoss += o.getProfitLossInUSD();
        }
        double equity = baseEquity + profitLoss;
        return equity;
    }
    
    @Override
    public String toString(){
        return String.format("%s account of base equity %.5f has %s orders and current equity: %.5f", 
                instruments.toString(), baseEquity, orders.size(), getEquity());
    }
    
}
