基于mpandroidchart的几种指标实现

k线介绍

image

股市及期货市场中的K线图的画法包含四个数据,即开盘价、最高价、最低价、收盘价,所有的k线都是围绕这四个数据展开

k线指标介绍

k线指标其实就是技术指标, 认为的根据某些算法来预测价格未来的走势,或者帮助分析价格背后的市场因素。

k线的几种指标实现

[图片上传失败...(image-d8e3a-1617104321100)]

SAR的实现

SAR指标又叫抛物线指标或停损转向操作点指标,其全称叫“Stop and Reverse,缩写SAR”,是由美国技术分析大师威尔斯-威尔德(Wells Wilder)所创造的,是一种简单易学、比较准确的中短期技术分析工具。

更多信息查看百度百科

  • SAR的计算公式
    计算公式

  • 代码实现

    public List getSar(List entries) {
        if (sarList == null) {
            sarList = new ArrayList<>();
        }
        if (!sarList.isEmpty()) {
            sarList.clear();
        }
        int len = entries.size();
        for (int i = 0; i < len; i++) {
            Entry entry = new Entry(calculateSar(i, entries), i);
            entry.setTrendUp(currentTrend);
            sarList.add(entry);
        }
        return sarList;
    }

    /**
     *
     * @param entries source data
     * @param index 下标
     * @param windowSize 窗口size
     * @return
     */
    private float getHighestValue(List entries, int index, int windowSize){
        if (entries.get(index).getHigh() == Float.NaN && windowSize != 1) {
            return  getHighestValue(entries, index - 1, windowSize - 1);
        }
        int end = Math.max(0, index - windowSize + 1);
        float highest = entries.get(index).getHigh();
        for (int i = index - 1; i >= end; i--) {
            if (highest < entries.get(i).getHigh()) {
                highest = entries.get(i).getHigh();
            }
        }
        return highest;
    }

    /**
     *
     * @param entries
     * @param index
     * @param windowSize
     * @return
     */
    private float getLowestValue(List entries, int index, int windowSize){
        if (entries.get(index).getHigh() == Float.NaN && windowSize != 1) {
            return getLowestValue(entries, index - 1, windowSize - 1);
        }
        int end = Math.max(0, index - windowSize + 1);
        float lowest =  entries.get(index).getLow();
        for (int i = index - 1; i >= end; i--) {
            if (lowest > entries.get(i).getLow()) {
                lowest = entries.get(i).getLow();
            }
        }
        return lowest;
    }

    protected float calculateSar(int index, List entries) {
        float sar = 0f;
        Entry entry = null;
        if (index == 0) {
            return entries.get(0).getClose(); // no trend detection possible for the first value
        } else if (index == 1) {// start trend detection
            currentTrend = entries.get(0).getClose() < entries.get(1).getClose();
            if (!currentTrend) { // down trend
                sar = entries.get(index).getHigh(); // put sar on max price of candlestick
            } else { // up trend
                sar = entries.get(index).getLow(); // put sar on min price of candlestick
            }
            currentExtremePoint = sar;
            minMaxExtremePoint = currentExtremePoint;
            return sar;
        }

        float priorSar = sarList.get(index - 1).getVal();
        if (currentTrend) { // if up trend
            sar = priorSar + (accelerationFactor * (currentExtremePoint - priorSar));
            currentTrend = entries.get(index).getLow() > sar;
            if (!currentTrend) { // check if sar touches the min price
                sar = minMaxExtremePoint; // sar starts at the highest extreme point of previous up trend
                currentTrend = false; // switch to down trend and reset values
                startTrendIndex = index;
                accelerationFactor = accelerationStart;
                currentExtremePoint = entries.get(index).getLow(); // put point on max
                minMaxExtremePoint = currentExtremePoint;
            } else { // up trend is going on
                // currentExtremePoint = new HighestValueIndicator(highPriceIndicator, index - startTrendIndex)
                //                        .getValue(index);
                currentExtremePoint = getHighestValue(entries, index, index - startTrendIndex);
                if (currentExtremePoint > minMaxExtremePoint) {
                    incrementAcceleration();
                    minMaxExtremePoint = currentExtremePoint;
                }

            }
        } else { // downtrend
            sar = priorSar - (accelerationFactor * (priorSar - currentExtremePoint));
            currentTrend = entries.get(index).getHigh() > sar;
            if (currentTrend) { // check if switch to up trend
                sar = minMaxExtremePoint; // sar starts at the lowest extreme point of previous down trend
                accelerationFactor = accelerationStart;
                startTrendIndex = index;
                currentExtremePoint = entries.get(index).getHigh();;
                minMaxExtremePoint = currentExtremePoint;
            } else { // down trend io going on
                //currentExtremePoint = new LowestValueIndicator(lowPriceIndicator, index - startTrendIndex)
                //                        .getValue(index);
                currentExtremePoint = getLowestValue(entries, index, index - startTrendIndex);
                if (currentExtremePoint < minMaxExtremePoint) {
                    incrementAcceleration();
                    minMaxExtremePoint = currentExtremePoint;
                }
            }
        }
        return sar;
    }

    /**
     * Increments the acceleration factor.
     */
    private void incrementAcceleration() {
        if (accelerationFactor > maxAcceleration) {
            accelerationFactor = maxAcceleration;
        } else {
            accelerationFactor = accelerationFactor + accelerationIncrement;
        }
    }

OBV的实现

OBV 的英文全称是:On Balance Volume,是由美国的投资分析家Joe Granville所创。该指标通过统计成交量变动的趋势来推测股价趋势。OBV以“N”字型为波动单位,并且由许许多多“N”型波构成了OBV的曲线图,对一浪高于一浪的“N”型波,称其为“上升潮”(UP TIDE),至于上升潮中的下跌回落则称为“跌潮”(DOWN FIELD)。

更多信息查看百度百科

  • OBV的计算公式
    计算公式
  • 代码实现
    private float calculateObv(int index, List entries) {
        if (index == 0) {
            return 0f;
        }
        final float prevClose = entries.get(index - 1).getClose();
        final float currentClose = entries.get(index).getClose();

        final float obvPrev = obvList.get(index - 1).getVal();
        if (prevClose > currentClose) {
            return obvPrev - (entries.get(index).getAmount());
        } else if (prevClose < currentClose) {
            return obvPrev + (entries.get(index).getAmount());
        } else {
            return 0;
        }
    }

RSI的实现

RSI最早被用于期货交易中,后来人们发现用该指标来指导股票市场投资效果也十分不错,并对该指标的特点不断进行归纳和总结。现在,RSI已经成为被投资者应用最广泛的技术指标之一。投资的一般原理认为,投资者的买卖行为是各种因素综合结果的反映,行情的变化最终取决于供求关系,而RSI指标正是根据供求平衡的原理,通过测量某一个期间内股价上涨总幅度占股价变化总幅度平均值的百分比,来评估多空力量的强弱程度,进而提示具体操作的。RSI的应用法则表面上比较复杂,包括了交叉、数值、形态和背离等多方面的判断原则。

更多信息查看百度百科

  • 代码实现
    public Triple, List, List> getRsiIndicator(List candleEntries) {
        if (candleEntries == null || candleEntries.size() == 0) {
            return new Triple<>(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
        }
        List rsiList = new ArrayList<>();
        List rsiList12 = new ArrayList<>();
        List rsiList24 = new ArrayList<>();
        float lastSmValue6 = 0, lastSmValue12 = 0, lastSmValue24 = 0;
        float lastSaValue6 = 0, lastSaValue12 = 0, lastSaValue24 = 0;
        CandleEntry lastEntry = candleEntries.get(0);
        int len = candleEntries.size();
        for (int i = 1; i < len; i++) {
            CandleEntry entry = candleEntries.get(i);
            float m = Math.max(entry.getClose() - lastEntry.getClose(), 0);
            float a = Math.abs(entry.getClose() - lastEntry.getClose());

            if (i >= 5) {
                lastSmValue6 = (m + 5 * lastSmValue6) / 6;
                lastSaValue6 = (a + 5 * lastSaValue6) / 6;
                rsiList.add(new Entry(lastSmValue6 / lastSaValue6 * 100, entry.getXIndex()));
            }

            if (i >= 11) {
                lastSmValue12 = (m + 11 * lastSmValue12) / 12;
                lastSaValue12 = (a + 11 * lastSaValue12) / 12;
                rsiList12.add(new Entry(lastSmValue12 / lastSaValue12 * 100, entry.getXIndex()));
            }

            if (i >= 23) {
                lastSmValue24 = (m + 23 * lastSmValue24) / 24;
                lastSaValue24 = (a + 23 * lastSaValue24) / 24;
                rsiList24.add(new Entry(lastSmValue24 / lastSaValue24 * 100, entry.getXIndex()));
            }
            lastEntry = candleEntries.get(i);
        }

        return new Triple<>(rsiList, rsiList12, rsiList24);
    }

TRIX的实现

三重指数平滑平均线(TRIX)属于中长线指标。它过滤掉许多不必要的波动来反映股价的长期波动趋势。在使用均线系统的交叉时,有时会出现骗线的情况,有时还会出现频繁交叉的情况,通常还有一个时间上的确认。为了解决这些问题,因而发明了TRIX这个指标把均线的数值再一次地算出平均数,并在此基础上算出第三重的平均数。这样就可以比较有效地避免频繁出现交叉信号。 TRIX指标又叫三重指数平滑移动平均指标,其英文全名为“Triple Exponentially Smoothed Average”,是一种研究股价趋势的长期技术分析工具。

更多信息查看百度百科

  • TRIX计算公式
    百度百科

  • 代码实现

    /**
     * EMA算法
     * EMA(N) = 2/(N+1)*C + (N-1)/(N+1)*EMA', EMA'为前一天的ema; 通常N取12和26
     *
     * @param entries
     * @param n
     * @return
     */
    public static List getEMA(List entries, int n) {
        List result = new ArrayList<>();
        float lastEma = entries.get(0).getClose();// 第一个EMA为第一个数据的价格

        float[] emaFactor = getEMAFactor(n);
        for (int i = n - 1; i < entries.size(); i++) {
            float ema = emaFactor[0] * entries.get(i).getClose() + emaFactor[1] * lastEma;
            result.add(new Entry(ema, entries.get(i).getXIndex()));
            lastEma = ema;
        }
        return result;
    }

    /**
     * EMA算法
     * EMA(N) = 2/(N+1)*C + (N-1)/(N+1)*EMA', EMA'为前一天的ema; 通常N取12和26
     *
     * @param entries
     * @param n
     * @return
     */
    public static List getEMAFromEntry(List entries, int n) {
        List result = new ArrayList<>();
        float lastEma = entries.get(0).getVal();// 第一个EMA为第一个数据的价格

        float[] emaFactor = getEMAFactor(n);
        for (int i = n - 1; i < entries.size(); i++) {
            float ema = emaFactor[0] * entries.get(i).getVal() + emaFactor[1] * lastEma;
            result.add(new Entry(ema, entries.get(i).getXIndex()));
            lastEma = ema;
        }
        return result;
    }
    
    private List trixList;
    private List trixMaList;
    public Pair, List> getTrix(List entries) {
        int n = 12, m = 9;
        if (entries == null) {
            return new Pair<>(new ArrayList<>(), new ArrayList<>());
        }
        if (trixList == null) {
            trixList = new ArrayList<>();
            trixMaList = new ArrayList<>();
        }

        //clear;
        trixList.clear();
        trixMaList.clear();

        List ema1 = getEMA(entries, n);
        List ema2 = getEMAFromEntry(ema1, n);
        List ema3 = getEMAFromEntry(ema2, n);
        int len = ema3.size();

        for (int i = 1; i < len; i++) {
            float trixValue = (ema3.get(i).getVal() - ema3.get(i - 1).getVal()) * 100 / ema3.get(i - 1).getVal();
            trixList.add(new Entry(trixValue, ema3.get(i).getXIndex()));
        }

        float ma = 0.0f;
        int index = m - 1;
        len = trixList.size();
        for (int i = 0; i < len; i++) {
            if (i >= index) {
                float sum = getSumFromEntry(i - index, i, trixList);
                ma = sum / m;
                trixMaList.add(new Entry(ma, trixList.get(i).getXIndex()));
            }
        }

        return new Pair<>(trixList, trixMaList);

    }

CCI的实现

顺势指标又叫CCI指标,CCI指标是美国股市技术分析 家唐纳德·蓝伯特(Donald Lambert)于20世纪80年代提出的,专门测量股价、外汇或者贵金属交易是否已超出常态分布范围。属于超买超卖类指标中较特殊的一种。波动于正无穷大和负无穷大之间。但是,又不需要以0为中轴线,这一点也和波动于正无穷大和负无穷大的指标不同。

更多信息查看

  • CCI的计算公式
    计算公式

  • 代码实现

    private List cciList;
    private List tpList;
    private List cciMaList;
    private List mdList;
    public List getCciData(List entries){
        int n = 20;
        if (entries == null || entries.size() < n) {
            return new ArrayList<>();
        }
        if (cciList == null) {
            cciList = new ArrayList<>();
            tpList = new ArrayList<>();
            mdList = new ArrayList<>();
            cciMaList = new ArrayList<>();
        }

        //clear
        cciList.clear();
        tpList.clear();
        mdList.clear();
        cciMaList.clear();

        int len = entries.size();
        for (int i = 0; i < len; i++) {
            float tpValue = getTp(i, entries);
            tpList.add(tpValue);
            float maValue = getSum(Math.max(0, i - n + 1), i, tpList) / Math.min(n, i + 1);
            cciMaList.add(maValue);

            final int startIndex = Math.max(0, i - n + 1);
            final int nbValues = i - startIndex + 1;
            float absoluteDeviations = 0;
            for (int j = startIndex; j <= i; j++) {
                // For each period...
                absoluteDeviations = absoluteDeviations + (Math.abs(tpList.get(j) - maValue));
            }

            float mdValue = absoluteDeviations / nbValues;
            mdList.add(mdValue);

            if (mdValue == 0) {
                if (i >= n - 1) {
                    cciList.add(new Entry(0, i));
                }
            } else {
                if (i >= n - 1) {
                    float cci = (tpList.get(i) - cciMaList.get(i)) / mdList.get(i) / 0.015f;
                    cciList.add(new Entry(cci, i));
                }
            }

        }

        return cciList;
    }

    private float getSum(Integer start, Integer end, List datas) {
        float sum = 0;
        for (int i = start; i <= end; i++) {
            sum += datas.get(i);
        }
        return sum;
    }

    private float getTp(int index, List entries){
        float maxPrice = entries.get(index).getHigh();
        float minPrice = entries.get(index).getLow();
        float closePrice = entries.get(index).getClose();
        return (maxPrice + minPrice + closePrice) / 3;
    }

ROC的实现

变动率指标(ROC),是以当日的收盘价和N天前的收盘价比较,通过计算股价某一段时间内收盘价变动的比例,应用价格的移动比较来测量价位动量,达到事先探测股价买卖供需力量的强弱,进而分析股价的趋势及其是否有转势的意愿,属于反趋势指标之一。

更多信息查看

  • ROC实现公式
    实现公式

  • 代码实现

    private List rocList;
    private List rocMaList;
    public Pair, List> getRoc(List entries) {
        int n = 12, m = 6;
        if (entries == null) {
            return new Pair<>(new ArrayList<>(), new ArrayList<>());
        }
        if (rocList == null) {
            rocList = new ArrayList<>();
            rocMaList = new ArrayList<>();
        }

        //clear;
        rocList.clear();
        rocMaList.clear();
        int len = entries.size();
        for (int i = n; i < len; i++) {
            int nIndex = Math.max(i - n, 0);
            float nPeriodsAgoValue = entries.get(nIndex).getClose();
            float currentValue = entries.get(i).getClose();
            float rocValue = (currentValue - nPeriodsAgoValue) / nPeriodsAgoValue  * 100;
            rocList.add(new Entry(rocValue, i));
        }

        len = rocList.size();
        for (int i = 0; i < len; i++) {
            if (i >= m - 1) {
                float sum = getSumFromEntry(i - m + 1, i, rocList);
                float maValue = sum / m;
                rocMaList.add(new Entry(maValue, rocList.get(i).getXIndex()));
            }
        }

        return new Pair<>(rocList, rocMaList);
    }

后续

MACD的实现 /KDJ的实现/ BOLL的实现 / WR的实现

你可能感兴趣的:(基于mpandroidchart的几种指标实现)