package jforex.strategies;

import com.dukascopy.api.*;

import com.dukascopy.api.bar.IPointAndFigure;
import com.dukascopy.api.listener.IPointAndFigureFeedListener;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class LIVE12_point_and_figure_x3remote_EURUSD implements IStrategy {
    private IEngine engine = null;
    private IIndicators indicators = null;
    private int tagCounter = 0;
    private IConsole console;
    private IHistory history;
    private IAccount account;
    private int side_up = 0, trend_up = 0;
    private int side_dn = 0, trend_dn = 0;    
    private int situatie_initiala = 1;
    private int mark1 = 0;
    private String order_side="";
    private IOrder curent_order = null;
    private java.util.Set<IChart> charts;
///////////////////////////////////////////////////////////////////////////////////////////
    private double amount = 0.006;
    private int slippage = 10;    
    private double reff_up = 1.4290;
    private double max_risk=20;    
    private double mm1=3;            
    private double mm=3;        
    private double acc_vall_reff=0;   
///////////////////////////////////////////////////////////////////////////////////////////
    private Instrument selectedInstrument = Instrument.EURUSD;
    private double account_val, account_val_ini, account_val_ini_trade;
    private double risk;
    private double reff_up_stop;
    private double reff_dn_stop;
    private double stopLossPrice=0;
    private double reff_dn;
    IPointAndFigure prevBar1, prevBar2;
                                                                                                                                                                                                                                
    public void onStart(IContext context) throws JFException {
        engine = context.getEngine();
        indicators = context.getIndicators();
        console = context.getConsole();
        history = context.getHistory();
        account = context.getAccount();

        account_val=account.getEquity();
        if(acc_vall_reff>0) {
            account_val_ini=acc_vall_reff;
        }
        else {
            account_val_ini=account.getEquity();
        }
        
        reff_dn=reff_up;        
        risk = getPipPrice(max_risk);
        reff_up_stop=reff_up - risk;
        reff_dn_stop=reff_dn + risk;

        context.subscribeToPointAndFigureFeed(selectedInstrument, OfferSide.BID, PriceRange.valueOf(1), ReversalAmount.valueOf(3),
           new IPointAndFigureFeedListener() {
               public void onBar(Instrument instrument, OfferSide offerSide, PriceRange priceRange, ReversalAmount reversalAmount,IPointAndFigure bar) {
                    prevBar2=prevBar1;
                    prevBar1=bar;
              }
           }
       );

    }

    public void onStop() throws JFException {
    }

    public void onTick(Instrument instrument, ITick tick) throws JFException {
        
        reff_dn=reff_up;        
        risk = getPipPrice(max_risk);
        reff_up_stop=reff_up - risk;
        reff_dn_stop=reff_dn + risk;
        
        if (!instrument.equals(selectedInstrument))
            return;
        if (prevBar1==null || prevBar2==null)
            return;

        double max_up=Math.max(prevBar1.getHigh(), Math.max(prevBar2.getHigh(),reff_up));
        double min_up=Math.min(prevBar1.getLow(), Math.min(prevBar2.getLow(),reff_up));
        double max_dn=Math.max(prevBar1.getHigh(), Math.max(prevBar2.getHigh(),reff_dn));
        double min_dn=Math.min(prevBar1.getLow(), Math.min(prevBar2.getLow(),reff_dn));

//algos for the reff_up trigger
        if(tick.getBid()>max_up) side_up = 1;
           else if(tick.getBid()<min_up) side_up = -1;
        if(side_up==-1 && trend_up != -1) {
            if (engine.getOrders().size() > 0) {
                for (IOrder order : engine.getOrders()) {
                    if (order.isLong() && order.getInstrument().equals(selectedInstrument)) {
                        order.close();
                    } 
                }
            }
            trend_up=-1;
        }
        if(side_up==1) {
            if (trend_up == -1) {
                stopLossPrice = roundHalfDown(reff_up_stop, selectedInstrument.getPipScale() + 1);
                order_side="B";
                account_val=Math.max(account.getEquity(), account_val_ini);
                account_val_ini_trade=account.getEquity();
                curent_order = engine.submitOrder(getLabel(selectedInstrument), selectedInstrument, IEngine.OrderCommand.BUY, amount, 0, slippage, stopLossPrice, 0);
                reff_up=min_up; reff_dn=min_dn;
                mark1=0;
                trend_up=1;
            }
        }

//algos for the reff_dn trigger
        if(tick.getBid()>max_dn) side_dn = 1;
           else if(tick.getBid()<min_dn) side_dn = -1;
        if(side_dn==1 && trend_dn != 1) {
            if (engine.getOrders().size() > 0) {
                for (IOrder order : engine.getOrders()) {
                    if (!order.isLong() && order.getInstrument().equals(selectedInstrument)) {
                        order.close();
                    }  
                }
            }
            trend_dn=1;
        }
        if(side_dn==-1) {
            if (trend_dn == 1) {
                stopLossPrice = roundHalfDown(reff_dn_stop + getPipPrice(1.5), selectedInstrument.getPipScale() + 1);
                order_side="S";   
                account_val=Math.max(account.getEquity(), account_val_ini);
                account_val_ini_trade=account.getEquity();
                curent_order = engine.submitOrder(getLabel(selectedInstrument), selectedInstrument, IEngine.OrderCommand.SELL, amount, 0, slippage, stopLossPrice, 0);
                reff_up=max_up; reff_dn=max_dn;
                mark1=0;
                trend_dn=-1;
            }
        }        

        if(curent_order!=null && !curent_order.getState().equals(IOrder.State.CLOSED)) {
            double sum = curent_order.getAmount();
            double sum_close=0.001;
            if (sum>=0.003) {
                     sum_close = 0.001;
	                 if (account.getEquity()>account_val+sum*100*mm && mark1==11) {
	                    sum_close = sum-0.002;
	                    curent_order.close(sum_close);
	                    mark1=12;
                        account_val=Math.max(account.getEquity(), account_val_ini);
	                }
                     if (account.getEquity()>account_val+sum*100*mm && mark1==10) {
                        curent_order.close(sum_close);
                        mark1=11;
                        account_val=Math.max(account.getEquity(), account_val_ini);
                    }
                     if (account.getEquity()>account_val+sum*100*mm && mark1==9) {
                        curent_order.close(sum_close);
                        mark1=10;
                        account_val=Math.max(account.getEquity(), account_val_ini);
                    }
                     if (account.getEquity()>account_val+sum*100*mm && mark1==8) {
                        curent_order.close(sum_close);
                        mark1=9;
                        account_val=Math.max(account.getEquity(), account_val_ini);
                    }
                     if (account.getEquity()>account_val+sum*100*mm && mark1==7) {
                        curent_order.close(sum_close);
                        mark1=8;
                        account_val=Math.max(account.getEquity(), account_val_ini);
                    }
	                 if (account.getEquity()>account_val+sum*100*mm && mark1==6) {
	                    curent_order.close(sum_close);
	                    mark1=7;
                        account_val=Math.max(account.getEquity(), account_val_ini);
	                }                                
	                 if (account.getEquity()>account_val+sum*100*mm && mark1==5) {
	                    curent_order.close(sum_close);
	                    mark1=6;
                        account_val=Math.max(account.getEquity(), account_val_ini);
	                }
	                 if (account.getEquity()>account_val+sum*100*mm && mark1==4) {
	                    curent_order.close(sum_close);
	                    mark1=5;
                        account_val=Math.max(account.getEquity(), account_val_ini);
	                }
	                 if (account.getEquity()>account_val+sum*100*mm && mark1==3) {
	                    curent_order.close(sum_close);
	                    mark1=4;
                        account_val=Math.max(account.getEquity(), account_val_ini);
	                }
	                if (account.getEquity()>account_val+sum*100*mm && mark1==2) {
	                    curent_order.close(sum_close);
	                    mark1=3;
                        account_val=Math.max(account.getEquity(), account_val_ini);
	                }
	                if (account.getEquity()>account_val+sum*100*mm && mark1==1) {
	                    curent_order.close(sum_close);
	                    mark1=2;
                        account_val=Math.max(account.getEquity(), account_val_ini);
	                }                       
	                //if (curent_order.getProfitLossInPips()>(risk/2)/getPipPrice(1)+1.5+2.0 && mark1==0) {
                    if (account.getEquity()>account_val+sum*100*mm1 && (mark1==-1 || mark1==0)) {
	                    sum_close = roundHalfUp(Math.max(0.001, 1*sum/3), 3);
	                    curent_order.close(sum_close);
	                    mark1=1;
                        account_val=Math.max(account.getEquity(), account_val_ini);
	                }
                    if (account_val_ini_trade < account_val_ini && account.getEquity()>account_val_ini+sum*100*1.5 && (mark1==-1 || mark1==0)) {
                        sum_close = roundHalfUp(Math.max(0.001, 2*sum/3), 3);
                        curent_order.close(sum_close);
                        mark1=1;
                        account_val=Math.max(account.getEquity(), account_val_ini);
                    }
                    if (account.getEquity()<account_val && curent_order.getProfitLossInPips()>1.5+1.0+3.0 && mark1==0) {
                        sum_close = roundHalfUp(Math.max(0.001, 1*sum/3), 3);
                        curent_order.close(sum_close);
                        mark1=-1;
                        account_val=Math.max(account.getEquity(), account_val_ini);
                    }
            }
        }
    }

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

    protected String getLabel(Instrument instrument) {
        String label = instrument.name();
        label = label.substring(0, 2) + label.substring(3, 5);
        label = "BB0"+label + order_side + (tagCounter++);
        label = label.toLowerCase();
        return label;
    }

    public void onMessage(IMessage message) throws JFException {
    }

    public void onAccount(IAccount account) throws JFException {
    }

    private double getPipPrice(double pips) {
        return pips * selectedInstrument.getPipValue();
    }    
    
    private double roundHalfDown(double amount, int decimalPlaces) {
       return (new BigDecimal(amount)).setScale(decimalPlaces, BigDecimal.ROUND_DOWN).doubleValue();
    }
    
    private double roundHalfUp(double amount, int decimalPlaces) {
       return (new BigDecimal(amount)).setScale(decimalPlaces, BigDecimal.ROUND_UP).doubleValue();
    }

}