基于mpandroidchart的幾種指標(biāo)實(shí)現(xiàn)

k線介紹

image

股市及期貨市場中的K線圖的畫法包含四個數(shù)據(jù),即開盤價、最高價、最低價、收盤價,所有的k線都是圍繞這四個數(shù)據(jù)展開

k線指標(biāo)介紹

k線指標(biāo)其實(shí)就是技術(shù)指標(biāo), 認(rèn)為的根據(jù)某些算法來預(yù)測價格未來的走勢,或者幫助分析價格背后的市場因素。

k線的幾種指標(biāo)實(shí)現(xiàn)

[圖片上傳失敗...(image-d8e3a-1617104321100)]

SAR的實(shí)現(xiàn)

SAR指標(biāo)又叫拋物線指標(biāo)或停損轉(zhuǎn)向操作點(diǎn)指標(biāo),其全稱叫“Stop and Reverse,縮寫SAR”,是由美國技術(shù)分析大師威爾斯-威爾德(Wells Wilder)所創(chuàng)造的,是一種簡單易學(xué)、比較準(zhǔn)確的中短期技術(shù)分析工具。

更多信息查看百度百科

    public List<Entry> getSar(List<CandleEntry> 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 下標(biāo)
     * @param windowSize 窗口size
     * @return
     */
    private float getHighestValue(List<CandleEntry> 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<CandleEntry> 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<CandleEntry> 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的實(shí)現(xiàn)

OBV 的英文全稱是:On Balance Volume,是由美國的投資分析家Joe Granville所創(chuàng)。該指標(biāo)通過統(tǒng)計(jì)成交量變動的趨勢來推測股價趨勢。OBV以“N”字型為波動單位,并且由許許多多“N”型波構(gòu)成了OBV的曲線圖,對一浪高于一浪的“N”型波,稱其為“上升潮”(UP TIDE),至于上升潮中的下跌回落則稱為“跌潮”(DOWN FIELD)。

更多信息查看百度百科

  • 代碼實(shí)現(xiàn)
    private float calculateObv(int index, List<KlinePointBean> 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的實(shí)現(xiàn)

RSI最早被用于期貨交易中,后來人們發(fā)現(xiàn)用該指標(biāo)來指導(dǎo)股票市場投資效果也十分不錯,并對該指標(biāo)的特點(diǎn)不斷進(jìn)行歸納和總結(jié)?,F(xiàn)在,RSI已經(jīng)成為被投資者應(yīng)用最廣泛的技術(shù)指標(biāo)之一。投資的一般原理認(rèn)為,投資者的買賣行為是各種因素綜合結(jié)果的反映,行情的變化最終取決于供求關(guān)系,而RSI指標(biāo)正是根據(jù)供求平衡的原理,通過測量某一個期間內(nèi)股價上漲總幅度占股價變化總幅度平均值的百分比,來評估多空力量的強(qiáng)弱程度,進(jìn)而提示具體操作的。RSI的應(yīng)用法則表面上比較復(fù)雜,包括了交叉、數(shù)值、形態(tài)和背離等多方面的判斷原則。

更多信息查看百度百科

  • 代碼實(shí)現(xiàn)
    public Triple<List<Entry>, List<Entry>, List<Entry>> getRsiIndicator(List<CandleEntry> candleEntries) {
        if (candleEntries == null || candleEntries.size() == 0) {
            return new Triple<>(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
        }
        List<Entry> rsiList = new ArrayList<>();
        List<Entry> rsiList12 = new ArrayList<>();
        List<Entry> 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的實(shí)現(xiàn)

三重指數(shù)平滑平均線(TRIX)屬于中長線指標(biāo)。它過濾掉許多不必要的波動來反映股價的長期波動趨勢。在使用均線系統(tǒng)的交叉時,有時會出現(xiàn)騙線的情況,有時還會出現(xiàn)頻繁交叉的情況,通常還有一個時間上的確認(rèn)。為了解決這些問題,因而發(fā)明了TRIX這個指標(biāo)把均線的數(shù)值再一次地算出平均數(shù),并在此基礎(chǔ)上算出第三重的平均數(shù)。這樣就可以比較有效地避免頻繁出現(xiàn)交叉信號。 TRIX指標(biāo)又叫三重指數(shù)平滑移動平均指標(biāo),其英文全名為“Triple Exponentially Smoothed Average”,是一種研究股價趨勢的長期技術(shù)分析工具。

更多信息查看百度百科

  • TRIX計(jì)算公式
    百度百科

  • 代碼實(shí)現(xiàn)

    /**
     * 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<Entry> getEMA(List<CandleEntry> entries, int n) {
        List<Entry> result = new ArrayList<>();
        float lastEma = entries.get(0).getClose();// 第一個EMA為第一個數(shù)據(jù)的價格

        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<Entry> getEMAFromEntry(List<Entry> entries, int n) {
        List<Entry> result = new ArrayList<>();
        float lastEma = entries.get(0).getVal();// 第一個EMA為第一個數(shù)據(jù)的價格

        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<Entry> trixList;
    private List<Entry> trixMaList;
    public Pair<List<Entry>, List<Entry>> getTrix(List<CandleEntry> 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<Entry> ema1 = getEMA(entries, n);
        List<Entry> ema2 = getEMAFromEntry(ema1, n);
        List<Entry> 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的實(shí)現(xiàn)

順勢指標(biāo)又叫CCI指標(biāo),CCI指標(biāo)是美國股市技術(shù)分析 家唐納德·藍(lán)伯特(Donald Lambert)于20世紀(jì)80年代提出的,專門測量股價、外匯或者貴金屬交易是否已超出常態(tài)分布范圍。屬于超買超賣類指標(biāo)中較特殊的一種。波動于正無窮大和負(fù)無窮大之間。但是,又不需要以0為中軸線,這一點(diǎn)也和波動于正無窮大和負(fù)無窮大的指標(biāo)不同。

更多信息查看

    private List<Entry> cciList;
    private List<Float> tpList;
    private List<Float> cciMaList;
    private List<Float> mdList;
    public List<Entry> getCciData(List<CandleEntry> 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<Float> datas) {
        float sum = 0;
        for (int i = start; i <= end; i++) {
            sum += datas.get(i);
        }
        return sum;
    }

    private float getTp(int index, List<CandleEntry> 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的實(shí)現(xiàn)

變動率指標(biāo)(ROC),是以當(dāng)日的收盤價和N天前的收盤價比較,通過計(jì)算股價某一段時間內(nèi)收盤價變動的比例,應(yīng)用價格的移動比較來測量價位動量,達(dá)到事先探測股價買賣供需力量的強(qiáng)弱,進(jìn)而分析股價的趨勢及其是否有轉(zhuǎn)勢的意愿,屬于反趨勢指標(biāo)之一。

更多信息查看

    private List<Entry> rocList;
    private List<Entry> rocMaList;
    public Pair<List<Entry>, List<Entry>> getRoc(List<CandleEntry> 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);
    }

后續(xù)

MACD的實(shí)現(xiàn) /KDJ的實(shí)現(xiàn)/ BOLL的實(shí)現(xiàn) / WR的實(shí)現(xiàn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容