package com.desfate.chart.ui.old.OTC.controls;


import com.desfate.chart.data.BidChartTotalDatas;
import com.desfate.chart.data.ChartBIASDatas;
import com.desfate.chart.data.ChartDMADatas;
import com.desfate.chart.data.ChartData;
import com.desfate.chart.data.ChartDataContainer;
import com.desfate.chart.data.ChartKDJDatas;
import com.desfate.chart.data.ChartMADatas;
import com.desfate.chart.data.ChartPSYDatas;
import com.desfate.chart.data.ChartRSIDatas;
import com.desfate.chart.util.MathUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * @author
 */
public class TargetControl {

    private double calcAverage(ArrayList<Double> source, int end) {
        double sum = 0;
        for (int i = 0; i < end; i++) {
            sum += source.get(i);
        }

        return sum / (end + 1);
    }

    private double absCalcAverage(ArrayList<Double> source, int end) {
        double sum = 0;
        for (int i = 0; i < end; i++) {
            sum += Math.abs(source.get(i));
        }

        return sum / (end + 1);
    }

    public ChartRSIDatas getRSI(ChartDataContainer chartDatas) {
        ChartRSIDatas chartRSIDatas = new ChartRSIDatas();
        chartRSIDatas.setRsi6(getRSI(chartDatas, 6));
        chartRSIDatas.setRsi12(getRSI(chartDatas, 12));
        chartRSIDatas.setRsi24(getRSI(chartDatas, 24));
        return chartRSIDatas;
    }

    /**
     * 强弱指标的计算公式:
     * 可查看分析系统公式管理器
     *
     * @param chartDatas ChartDataContainer中的高开低收数据本身是倒序的，也就是说，0位就是最早的数据
     * @return RS
     */
    public List<Double> getRSI(ChartDataContainer chartDatas, int rate) {
        List<Double> doubles = new ArrayList<Double>();
        // 初始化5个0值
        int lastRate = rate - 1;
        for (int i = 0; i < lastRate; i++) {
            doubles.add(0.0);
        }

        ArrayList<Double> returns = new ArrayList<Double>();
        List<Double> smas = new ArrayList<Double>();
        List<Double> absSmas = new ArrayList<Double>();
        returns.add(0.0);
        for (int i = 0; i < chartDatas.mOHLCList.size(); i++) {
            if (i == 0) {
                continue;
            }
            returns.add(chartDatas.mOHLCList.get(i).getClose() - chartDatas.mOHLCList.get(i - 1).getClose());
        }

        for (int i = lastRate; i < returns.size(); i++) {
            if (i == lastRate) {
                smas.add(calcAverage(returns, i));
                absSmas.add(absCalcAverage(returns, i));
                doubles.add(smas.get(i - lastRate) / absSmas.get(i - lastRate));
                continue;
            }

            double sma = ((returns.get(i) > 0 ? returns.get(i) : 0) * 1 + (rate - 1) * smas.get(i - lastRate - 1)) / rate;
            smas.add(sma);

            double absSma = (Math.abs(returns.get(i)) * 1 + (rate - 1) * absSmas.get(i - lastRate - 1)) / rate;
            absSmas.add(absSma);
            doubles.add((smas.get(i - lastRate) / absSmas.get(i - lastRate)) * 100);
        }
        return doubles;
    }

    /**
     * 获取14个周期的rs值。
     *
     * @return
     */
    private double getRSs(double[] ds) {
        double rs1 = 0.0;// 负数 下降
        double rs2 = 0.0;// 正数 上升
        for (int i = 0; i < ds.length; i++) {
            if (ds[i] <= 0) {
                rs1 = rs1 + ds[i];
            } else if (ds[i] > 0) {
                rs2 = rs2 + ds[i];
            }
        }
        double rs = rs2 / Math.abs(rs1);
        return rs;
    }

    // ----------------- KDJ指标 ------------------------------------

    /**
     * 取前9个元素为一个周期。
     * <p>
     * <li>KDJ的计算比较复杂，首先要计算周期（n日、n周等）的RSV值，即未成熟随机指标值，然后再计算K值、D值、J值等。以日KDJ数值的计算为例
     * ，其计算公式为
     * <li>n日RSV=（Cn－Ln）÷（Hn－Ln）×100
     * <li>公式中，Cn为第n日收盘价；Ln为n日内的最低价；Hn为n日内的最高价。
     * <li>其次，计算K值与D值：
     * <li>当日K值=2/3×前一日K值+1/3×当日RSV
     * <li>当日D值=2/3×前一日D值+1/3×当日K值
     * <li>若无前一日K 值与D值，则可分别用50来代替。
     * <li>J值=3*当日K值-2*当日D值
     * <p>
     * eg:
     * </p>
     * <li>以9日为周期的KD线为例，即未成熟随机值，计算公式为
     * <li>9日RSV=（C－L9）÷（H9－L9）×100
     * <li>公式中，C为第9日的收盘价；L9为9日内的最低价；H9为9日内的最高价。
     * <li>K值=2/3×第8日K值+1/3×第9日RSV
     * <li>D值=2/3×第8日D值+1/3×第9日K值
     * <li>J值=3*第9日K值-2*第9日D值
     * <li>若无前一日K值与D值，则可以分别用50代替。
     *
     * @param chartDatas ChartDataContainer中的高开低收数据本身是倒序的，也就是说，0位就是最早的数据
     * @return
     */
    public ChartKDJDatas getKDJs(ChartDataContainer chartDatas) {
        ChartKDJDatas chartKDJDatas = new ChartKDJDatas();

        for (int i = 0; i < 8; i++) {
            chartKDJDatas.getRsv().add(0.0);

            chartKDJDatas.getK().add(0.0);
            chartKDJDatas.getD().add(0.0);
            chartKDJDatas.getJ().add(0.0);
        }

        double heightPrice = 0.0;
        double lowPrice = Double.MAX_VALUE;
        for (int i = 8; i < chartDatas.mOHLCList.size(); i++) {
            heightPrice = 0;
            lowPrice = Double.MAX_VALUE;
            for (int j = i - 8; j < i + 1; j++) {// 取前9个元素的索引，对比出最低和最高价

                if (heightPrice < chartDatas.mOHLCList.get(j).getHigh()) {
                    heightPrice = chartDatas.mOHLCList.get(j).getHigh();
                }
                if (lowPrice == 0 || lowPrice > chartDatas.mOHLCList.get(j).getLow()) {
                    lowPrice = chartDatas.mOHLCList.get(j).getLow();
                }
            }

            /**
             * 计算rsv
             */
            if (heightPrice == lowPrice) {// 如果前9日的元素的最高和最低价相等。
                chartKDJDatas.getRsv().add(50.0);
            } else {
                /**
                 * n日RSV=（Cn－Ln）÷（Hn－Ln）×100
                 * 公式中，Cn为第n日收盘价；Ln为n日内的最低价；Hn为n日内的最高价。
                 */
                double rsv = ((chartDatas.mOHLCList.get(i).getClose() - lowPrice) / (heightPrice - lowPrice)) * 100;
                chartKDJDatas.getRsv().add(Double.parseDouble(MathUtil.roundNum(rsv, 2)));
            }

            /**
             * 当日K值 = 2/3 * 前一日K值 + 1/3 * 当日RSV
             */
            double k = 0.0;
            double pK = 0.0;// 前一日K值
            pK = chartKDJDatas.getK().get(i - 1) == 0.0 ? 50 : chartKDJDatas.getK().get(i - 1);// 如果前一日的K值为0

            k = ((double) 2 / 3) * pK + ((double) 1 / 3) * chartKDJDatas.getRsv().get(i);
            chartKDJDatas.getK().add(Double.parseDouble(MathUtil.roundNum(k, 2)));

            /**
             * 当日D值=2/3×第8日D值+1/3×第9日K值
             */
            double d = 0.0;
            double pD = 0.0;// 前一日D值
            pD = chartKDJDatas.getD().get(i - 1) == 0.0 ? 50 : chartKDJDatas.getD().get(i - 1);

            d = ((double) 2 / 3) * pD + ((double) 1 / 3) * chartKDJDatas.getK().get(i);
            chartKDJDatas.getD().add(Double.parseDouble(MathUtil.roundNum(d, 2)));
            /**
             * 当日J值=3*第9日K值-2*第9日D值
             */
            double j = 0.0;
            j = 3 * chartKDJDatas.getK().get(i) - 2 * chartKDJDatas.getD().get(i);

            chartKDJDatas.getJ().add(Double.parseDouble(MathUtil.roundNum(j, 2)));
        }
        return chartKDJDatas;
    }

    /**
     * cci 周期13
     * 具体公式可查看分析系统公式管理器
     *
     * @param chartDatas ChartDataContainer中的高开低收数据本身是倒序的，也就是说，0位就是最早的数据
     */
    public List<Double> getCCIs(ChartDataContainer chartDatas) {
        List<Double> ccis = new ArrayList<Double>();
        List<Double> temMA = new ArrayList<Double>();
        List<Double> tps = new ArrayList<Double>();
        double cci = 0.0;
        int N = 13;
        for (int i = 0; i < N - 1; i++) {
            ccis.add(0.0);
            temMA.add(0.0);
            double tp = (chartDatas.mOHLCList.get(i).getHigh() + chartDatas.mOHLCList.get(i).getLow() + chartDatas.mOHLCList.get(i).getClose()) / 3;
            tps.add(tp);
        }


        for (int i = N - 1; i < chartDatas.mOHLCList.size(); i++) {
            double tpSum = 0;
            double tpMa = 0;
            double tpDevSum = 0;
            /**
             * TP = （最高价+最低价+收盘价） ÷ 3
             //			 */
            double tp = (chartDatas.mOHLCList.get(i).getHigh() + chartDatas.mOHLCList.get(i).getLow() + chartDatas.mOHLCList.get(i).getClose()) / 3;
            tps.add(tp);
            /**
             * MA = 最近N日收盘价的累计之和 ÷ N
             */
            for (int j = i - (N - 1); j < i + 1; j++) {
                tpSum += tps.get(j);
            }
            tpMa = tpSum / N;

            for (int j = i - (N - 1); j < i + 1; j++) {
                tpDevSum += Math.abs(tpMa - tps.get(j));
            }

            /**
             * CCI（N日）=（TP－MA） ÷ MD ÷ 0.015
             */
            cci = tpDevSum == 0 ? 0 : ((tps.get(i) - tpMa) / ((tpDevSum / N) * 0.015));
            cci = Double.parseDouble(MathUtil.roundNum(cci, 2));
            ccis.add(cci);
        }
        return ccis;
    }

    /**
     * DMA  10 50 6
     * <li>以求10日、50日为基准周期的DMA指标为例，其计算过程具体如下：
     * <li>DMA（10） = 10日平均值 — 50日平均值
     * <li>AMA（6） = dma的6日平均值
     *
     * @param chartDatas ChartDataContainer中的高开低收数据本身是倒序的，也就是说，0位就是最早的数据
     */
    public ChartDMADatas getDMAs(ChartDataContainer chartDatas) {
        ChartDMADatas chartDMADatas = new ChartDMADatas();
        if (chartDatas.mSize <= 0) {
            return chartDMADatas;
        }
        ChartMADatas chartMADatas = new ChartMADatas();
        /**
         * 先计算出MA10 和MA50的值
         */
        double ma10 = 0.0;
        double ma10Sum = 0.0;
        double ma50 = 0.0;
        double ma50Sum = 0.0;
        for (int i = 0; i < chartDatas.mOHLCList.size(); i++) {
            ma10Sum = 0.0;
            ma50Sum = 0.0;
            if (i >= 9) {
                for (int j = i - 9; j <= i; j++) {
                    ma10Sum += chartDatas.mOHLCList.get(j).getClose();
                }
                ma10 = ma10Sum / 10;
                chartMADatas.getMA10().add(ma10);
            } else {
                chartMADatas.getMA10().add(0.0);
            }

            if (i >= 49) {
                for (int j = i - 49; j <= i; j++) {
                    ma50Sum += chartDatas.mOHLCList.get(j).getClose();
                }
                ma50 = ma50Sum / 50;
                chartMADatas.getMA50().add(ma50);
            } else {
                chartMADatas.getMA50().add(0.0);
            }
        }
        chartMADatas.setSize(chartDatas.mOHLCList.size());

        /**
         * 计算出DMA 和 AMA值
         */
        for (int i = 0; i < 49; i++) {
            chartDMADatas.getAMA().add(0.0);
        }
        for (int i = 0; i < 49; i++) {
            chartDMADatas.getDMA().add(0.0);
        }
        double dma = 0.0;
        double amaSum = 0.0;
        double ama = 0.0;
        for (int i = 0; i < chartMADatas.getSize(); i++) {
            if (i >= 49) {
                dma = Double.parseDouble(
                        MathUtil.roundNum(chartMADatas.getMA10().get(i) - chartMADatas.getMA50().get(i), 2));
                chartDMADatas.getDMA().add(dma);
                amaSum = 0.0;
                for (int j = i - 5; j <= i; j++) {// 计算AMA
                    amaSum += chartDMADatas.getDMA().get(j);
                }
                ama = Double.parseDouble(MathUtil.roundNum(amaSum / 6, 2));
                chartDMADatas.getAMA().add(ama);
            }
        }
        return chartDMADatas;
    }

    /**
     * <li>BIAS 6日、12日、24日
     * <li>
     * <li>BIAS=(当日指数或收盘价-N日平均指数或收盘价)÷N日平均指数或收盘价×100％
     * <li>N的参数一般确定为6日、12日、24日，并且同时设置成三条线。
     *
     * @param chartDatas ChartDataContainer中的高开低收数据本身是倒序的，也就是说，0位就是最早的数据
     */
    public ChartBIASDatas getBIASs(ChartDataContainer chartDatas) {
        ChartBIASDatas chartBIASDatas = new ChartBIASDatas();
        double b6 = 0.0;
        double b12 = 0.0;
        double b24 = 0.0;

        double bn = 0.0;
        double bnSum = 0.0;
        for (int i = 0; i < chartDatas.mOHLCList.size(); i++) {
            bnSum = 0.0;
            if (i >= 5) {
                /**
                 * BIAS=(当日指数或收盘价-N日平均指数或收盘价)÷N日平均指数或收盘价×100％
                 */
                for (int j = i - 5; j <= i; j++) {
                    bnSum += chartDatas.mOHLCList.get(j).getClose();
                }
                bn = bnSum / 6;
                b6 = ((chartDatas.mOHLCList.get(i).getClose() - bn) / bn) * 100;
                chartBIASDatas.getBias6().add(b6);
            } else {
                chartBIASDatas.getBias6().add(0.0);
            }
            bnSum = 0.0;
            if (i >= 11) {
                /**
                 * BIAS=(当日指数或收盘价-N日平均指数或收盘价)÷N日平均指数或收盘价×100％
                 */
                for (int j = i - 11; j <= i; j++) {
                    bnSum += chartDatas.mOHLCList.get(j).getClose();
                }
                bn = bnSum / 12;
                b12 = ((chartDatas.mOHLCList.get(i).getClose() - bn) / bn) * 100;
                chartBIASDatas.getBias12().add(b12);
            } else {
                chartBIASDatas.getBias12().add(0.0);
            }
            bnSum = 0.0;
            if (i >= 23) {
                /**
                 * BIAS=(当日指数或收盘价-N日平均指数或收盘价)÷N日平均指数或收盘价×100％
                 */
                for (int j = i - 23; j <= i; j++) {
                    bnSum += chartDatas.mOHLCList.get(j).getClose();
                }
                bn = bnSum / 24;
                b24 = ((chartDatas.mOHLCList.get(i).getClose() - bn) / bn) * 100;
                chartBIASDatas.getBias24().add(b24);
            } else {
                chartBIASDatas.getBias24().add(0.0);
            }
        }
        return chartBIASDatas;
    }

    /**
     * <li>PSY 26 6
     * <li>
     * <li>1.PSY=N日内上涨天数/N*100
     * <li>2.PSYMA=PSY的M日简单移动平均
     * <li>3.参数N设置为12日，参数M设置为6日
     *
     * @param chartDatas ChartDataContainer中的高开低收数据本身是倒序的，也就是说，0位就是最早的数据
     */
    public ChartPSYDatas getPSYs(ChartDataContainer chartDatas) {
        ChartPSYDatas chartPSYDatas = new ChartPSYDatas();
        /**
         * 参数N设置为12日，计算psy
         */
        int upDays = 0;
        for (int i = 0; i < chartDatas.mOHLCList.size(); i++) {
            if (i >= 25) {
                for (int j = i - 25; j < i + 1; j++) {
                    if (j == 0) {
                        continue;
                    }
                    if (chartDatas.mOHLCList.get(j - 1).getClose() < chartDatas.mOHLCList.get(j).getClose()) {
                        upDays += 1;
                    }
                    // PSY=N日内上涨天数/N*100
                }
                chartPSYDatas.getPsy().add(Double.parseDouble(MathUtil.roundNum((double) upDays / 26 * 100, 2)));
                upDays = 0;
            } else {
                chartPSYDatas.getPsy().add(0.0);
            }
        }

        double psyMaSum = 0.0;
        for (int i = 0; i < chartPSYDatas.getPsy().size(); i++) {
            if (i >= 5) {
                for (int j = i - 5; j <= i; j++) {
                    psyMaSum += chartPSYDatas.getPsy().get(j);
                }
                // PSYMA=PSY的M日简单移动平均
                chartPSYDatas.getPsyMa().add(Double.parseDouble(MathUtil.roundNum(psyMaSum / 6, 2)));
                psyMaSum = 0.0;
            } else {
                chartPSYDatas.getPsyMa().add(0.0);
            }
        }
        return chartPSYDatas;
    }

    /**
     * 计算竞价历史总量指标
     *
     * @param chartDatas
     * @return
     */
    public BidChartTotalDatas getBidTotalData(ChartDataContainer chartDatas) {
        BidChartTotalDatas bidChartTotalDatas = new BidChartTotalDatas();
        if (chartDatas.mOHLCList.isEmpty()) {
            return bidChartTotalDatas;
        }
        List<Double> total5 = bidChartTotalDatas.getTotal5();
        List<Double> total10 = bidChartTotalDatas.getTotal10();

        for (int i = 0; i < chartDatas.mSize; i++) {
            double sum = 0;
            if (i >= 4) {
                for (int j = i - 4; j <= i; j++) {
                    sum += Double.parseDouble(((ChartData) (chartDatas.mOHLCList.get(j))).getVolume());
                }
                total5.add(sum / 5.0);

            } else {
                total5.add(0.0);
            }

            sum = 0;
            if (i >= 9) {
                for (int j = i - 9; j <= i; j++) {
                    sum += Double.parseDouble(((ChartData) (chartDatas.mOHLCList.get(j))).getVolume());
                }
                total10.add(sum / 10.0);
            } else {
                total10.add(0.0);
            }
        }
        return bidChartTotalDatas;
    }

}
