package jforex;

import com.dukascopy.api.IBar;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.OfferSide;
import com.dukascopy.api.indicators.*;

public class DXYIndicator implements IIndicator {
    
    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;
    private IBar[][] inputs = new IBar[7][];
    private int timePeriod = 0;
    private double[][] outputs = new double[1][];
    private double dxyconst = 50.14348112;

    
    public void onStart(IIndicatorContext context) {

        indicatorInfo = new IndicatorInfo("DXY", "Shows US Dollar index", "My indicators",
                false, false, false, false, 7, 0, 1);
                
        InputParameterInfo   main = new InputParameterInfo("Main", InputParameterInfo.Type.BAR);      
                       
        InputParameterInfo eurusd = new InputParameterInfo("EURUSD", InputParameterInfo.Type.BAR);
        eurusd.setInstrument(Instrument.EURUSD);
        eurusd.setOfferSide(OfferSide.BID);
        
        InputParameterInfo gbpusd = new InputParameterInfo("GBPUSD", InputParameterInfo.Type.BAR);
        gbpusd.setInstrument(Instrument.GBPUSD);
        gbpusd.setOfferSide(OfferSide.BID);
        
        InputParameterInfo usdjpy = new InputParameterInfo("USDJPY", InputParameterInfo.Type.BAR);
        usdjpy.setInstrument(Instrument.USDJPY);
        usdjpy.setOfferSide(OfferSide.BID);
        
        InputParameterInfo usdcad = new InputParameterInfo("USDCAD", InputParameterInfo.Type.BAR);
        usdcad.setInstrument(Instrument.USDCAD);
        usdcad.setOfferSide(OfferSide.BID);
        
        InputParameterInfo usdchf = new InputParameterInfo("USDCHF", InputParameterInfo.Type.BAR);
        usdchf.setInstrument(Instrument.USDCHF);
        usdchf.setOfferSide(OfferSide.BID);
        
        InputParameterInfo usdsek = new InputParameterInfo("USDSEK", InputParameterInfo.Type.BAR);
        usdsek.setInstrument(Instrument.USDSEK);
        usdsek.setOfferSide(OfferSide.BID);
        
        
        inputParameterInfos = new InputParameterInfo[] {main, eurusd, gbpusd, usdjpy, usdcad, usdchf, usdsek};         
        
        
        outputParameterInfos = new OutputParameterInfo[] {new OutputParameterInfo("DXY", OutputParameterInfo.Type.DOUBLE,
                OutputParameterInfo.DrawingStyle.LINE)};

    }


        public IndicatorResult calculate(int startIndex, int endIndex) {
        //calculating startIndex taking into account lookback value
        if (startIndex - getLookback() < 0) {
            startIndex -= startIndex - getLookback();
        }
        
        if (startIndex > endIndex) {
            return new IndicatorResult(0, 0);
        }

        int i, j;
            for (i = startIndex, j = 0; i <= endIndex; i++, j++) {
            int timeIndex1 = getTimeIndex(inputs[0][i].getTime(), inputs[1]);            
            int timeIndex2 = getTimeIndex(inputs[0][i].getTime(), inputs[2]);
            int timeIndex3 = getTimeIndex(inputs[0][i].getTime(), inputs[3]);
            int timeIndex4 = getTimeIndex(inputs[0][i].getTime(), inputs[4]);
            int timeIndex5 = getTimeIndex(inputs[0][i].getTime(), inputs[5]);
            int timeIndex6 = getTimeIndex(inputs[0][i].getTime(), inputs[6]);
            
            outputs[0][j] = (timeIndex1 == -1 || timeIndex2 == -1 || timeIndex3 == -1 || timeIndex4 == -1 || timeIndex5 == -1 || timeIndex6 == -1)? 
                    Double.NaN : Math.pow((((IBar)inputs[1][timeIndex1]).getClose()), -0.576)* //EUR
                                 Math.pow((((IBar)inputs[2][timeIndex2]).getClose()), -0.119)* //GBP
                                 Math.pow((((IBar)inputs[3][timeIndex3]).getClose()),  0.136)* //JPY
                                 Math.pow((((IBar)inputs[4][timeIndex4]).getClose()),  0.091)* //CAD
                                 Math.pow((((IBar)inputs[5][timeIndex5]).getClose()),  0.036)* //CHF
                                 Math.pow((((IBar)inputs[6][timeIndex6]).getClose()),  0.042)* //SEK
                                 dxyconst;
                }

                // US Dollar Index = 50.14348112 × EUROUS Dollar^(-0.576) × US Dollar JP Yen^(0.136) × 
                // GBPUS Dollar^(-0.119) × US Dollar CAD^(0.091) × US Dollar SEK^(0.042) × US Dollar CHF^(0.036)
                //result = dxyconst * Math.pow(eurusd, -0.576) * Math.pow(gbpusd, -0.119) * Math.pow(usdjpy, 0.136) * Math.pow(usdcad, 0.091)  * Math.pow(usdchf, 0.036)* Math.pow(usdsek, 0.042);
            //outputs[0][j] = result;
        
        return new IndicatorResult(startIndex, j);
    }
 public IndicatorInfo getIndicatorInfo() {
        return indicatorInfo;
    }

    public InputParameterInfo getInputParameterInfo(int index) {
        if (index <= inputParameterInfos.length) {
            return inputParameterInfos[index];
        }
        return null;
    }

    public int getLookback() {
        //timePeriod is 0 etc.
        return timePeriod;
    }

    public int getLookforward() {
        return 0;
    }

    public OptInputParameterInfo getOptInputParameterInfo(int index) {
        //if (index <= optInputParameterInfos.length) {
        //    return optInputParameterInfos[index];
        //}
        return null;
    }

    public OutputParameterInfo getOutputParameterInfo(int index) {
        if (index <= outputParameterInfos.length) {
            return outputParameterInfos[index];
        }
        return null;
    }

    public void setInputParameter(int index, Object array) {
        inputs[index] = (IBar[]) array;
    }

    public void setOptInputParameter(int index, Object value) {        
    }

    public void setOutputParameter(int index, Object array) {
        outputs[index] = (double[]) array;
    }
       
    private int getTimeIndex(long time, IBar[] target) {
        if (target == null) {
            return -1;
        }

        int first = 0;
        int upto = target.length;
        
        while (first < upto) {
            int mid = (first + upto) / 2;
            
            IBar data = target[mid];
            
            if (data.getTime() == time) {
                return mid;
            }
            else if (time < data.getTime()) {
                upto = mid;
            } 
            else if (time > data.getTime()) {
                first = mid + 1;
            } 
        }                               
        return -1;
    }
}



