MPAndroidChart的K线图上添加均线

简介: MPAndroidChart的K线图上添加均线效果图 均线计算方法: 通常说的5日均线,10日均线,其实就是根据当前K线节点的时间维度来说的,当前每个节点代表一天,那么上面...

MPAndroidChart的K线图上添加均线

  • 效果图
    这里写图片描述

均线计算方法:

通常说的5日均线,10日均线,其实就是根据当前K线节点的时间维度来说的,当前每个节点代表一天,那么上面的均线就叫做日均线(几日均线),下面就统一说成几节点均线

那么5节点均线,10节点均线等等,是怎么计算出来的呢

5节点均线为例,5节点均线是从第五根柱子开始画,一直画到最后一柱子(10节点均线就是从第10根柱子开始画,画到最后一根)

用第1、2、3、4、5个节点的收盘价之和,算出一个平均值,点在第5个节点上
用第2、3、4、5、6个节点的收盘价之和,算出一个平均值,点在低6个节点上
依此类推……

最后将画在5、6、7、8……上的点连起来,就是5节点均线。(如果当前一个节点代表一天,那这条线就是5日均线)


源码

MPAndroidChart地址:https://github.com/PhilJay/MPAndroidChart

在CandleStickChartRenderer.java下添加画均线的方法

思路:在draw K线柱子的时候获取每个柱子的收盘值,根据收盘值,计算均值

Demo Code

均线的实现,请移步到在MPAndroidChart库K线图的基础上画均线

下面实现的均线是第一版,见效果图,实现逻辑上略有问题,可直接忽略

@Override
public void drawData(Canvas c) {

    CandleData candleData = mChart.getCandleData();

    for (CandleDataSet set : candleData.getDataSets()) {

        if (set.isVisible() && set.getEntryCount() > 0)
            drawDataSet(c, set);
    }
}

protected void drawDataSet(Canvas c, CandleDataSet dataSet) {

    Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());

    float phaseX = mAnimator.getPhaseX();
    float phaseY = mAnimator.getPhaseY();

    int dataSetIndex = mChart.getCandleData().getIndexOfDataSet(dataSet);

    List<CandleEntry> entries = dataSet.getYVals();

    int minx = Math.max(mMinX, 0);
    int maxx = Math.min(mMaxX + 1, entries.size());

    int range = (maxx - minx) * 4;
    int to = (int) Math.ceil((maxx - minx) * phaseX + minx);

    CandleBodyBuffer bodyBuffer = mBodyBuffers[dataSetIndex];
    bodyBuffer.setBodySpace(dataSet.getBodySpace());
    bodyBuffer.setPhases(phaseX, phaseY);
    bodyBuffer.limitFrom(minx);
    bodyBuffer.limitTo(maxx);
    bodyBuffer.feed(entries);

    trans.pointValuesToPixel(bodyBuffer.buffer);

    CandleShadowBuffer shadowBuffer = mShadowBuffers[dataSetIndex];
    shadowBuffer.setPhases(phaseX, phaseY);
    shadowBuffer.limitFrom(minx);
    shadowBuffer.limitTo(maxx);
    shadowBuffer.feed(entries);

    trans.pointValuesToPixel(shadowBuffer.buffer);

    mRenderPaint.setStrokeWidth(dataSet.getShadowWidth());

    ArrayList<Float> closes = new ArrayList<Float>();
    ArrayList<Float> jx = new ArrayList<Float>();
    // draw the body
    for (int j = 0; j < range; j += 4) {

        // get the entry
        CandleEntry e = entries.get(j / 4 + minx);

        if (!fitsBounds(e.getXIndex(), mMinX, to))
            continue;

        if (dataSet.getShadowColorSameAsCandle()) {

            if (e.getOpen() > e.getClose())
                mRenderPaint.setColor(
                        dataSet.getDecreasingColor() == ColorTemplate.COLOR_NONE ?
                                dataSet.getColor(j) :
                                dataSet.getDecreasingColor()
                );

            else if (e.getOpen() < e.getClose())
                mRenderPaint.setColor(
                        dataSet.getIncreasingColor() == ColorTemplate.COLOR_NONE ?
                                dataSet.getColor(j) :
                                dataSet.getIncreasingColor()
                );

            else
                mRenderPaint.setColor(
                        dataSet.getShadowColor() == ColorTemplate.COLOR_NONE ?
                                dataSet.getColor(j) :
                                dataSet.getShadowColor()
                );

        } else {
            mRenderPaint.setColor(
                    dataSet.getShadowColor() == ColorTemplate.COLOR_NONE ?
                            dataSet.getColor(j) :
                            dataSet.getShadowColor()
            );
        }

        mRenderPaint.setStyle(Paint.Style.STROKE);

        // draw the shadow
        c.drawLine(shadowBuffer.buffer[j], shadowBuffer.buffer[j + 1],
                shadowBuffer.buffer[j + 2], shadowBuffer.buffer[j + 3],
                mRenderPaint);

        float leftBody = bodyBuffer.buffer[j];
        float open = bodyBuffer.buffer[j + 1];
        float rightBody = bodyBuffer.buffer[j + 2];
        float close = bodyBuffer.buffer[j + 3];
        closes.add(close);
        jx.add((leftBody + rightBody) / 2);

        // draw body differently for increasing and decreasing entry
        if (open > close) { // decreasing

            if (dataSet.getDecreasingColor() == ColorTemplate.COLOR_NONE) {
                mRenderPaint.setColor(dataSet.getColor(j / 4 + minx));
            } else {
                mRenderPaint.setColor(dataSet.getDecreasingColor());
            }

            mRenderPaint.setStyle(dataSet.getDecreasingPaintStyle());
            // draw the body
            c.drawRect(leftBody, close, rightBody, open, mRenderPaint);

        } else if (open < close) {

            if (dataSet.getIncreasingColor() == ColorTemplate.COLOR_NONE) {
                mRenderPaint.setColor(dataSet.getColor(j / 4 + minx));
            } else {
                mRenderPaint.setColor(dataSet.getIncreasingColor());
            }

            mRenderPaint.setStyle(dataSet.getIncreasingPaintStyle());
            // draw the body
            c.drawRect(leftBody, open, rightBody, close, mRenderPaint);
        } else { // equal values

            mRenderPaint.setColor(dataSet.getShadowColor());
            c.drawLine(leftBody, open, rightBody, close, mRenderPaint);
        }

        // 5节点均线
        drawLine(c, 5, closes, jx);
        // 10节点均线
        drawLine(c, 10, closes, jx);
        // 30节点均线
        drawLine(c, 30, closes, jx);
    }
}

/**
 * 画均线
 * @param c
 * @param i
 * @param closes
 * @param jx
 */
private void drawLine(Canvas c, int i, ArrayList<Float> closes, ArrayList<Float> jx) {
    Paint paint = new Paint();
    // 画线宽度
    paint.setStrokeWidth(1);
    // 画线颜色
    if (5 == i) {
        paint.setColor(Color.BLUE);
    } else if (10 == i) {
        paint.setColor(Color.RED);
    } else if (30 == i) {
        paint.setColor(Color.BLACK);
    } else {
        paint.setColor(Color.GREEN);
    }

    if (closes.size() >= i + 1) {
        float startX = jx.get(closes.size() - 2);
        float startY = 0;
        for (int x = 0; x < i; x++) {
            startY += closes.get(closes.size() - 2 - x);
        }
        startY = startY / i;
        float endX = jx.get(closes.size() - 1);
        float endY = 0;
        for (int y = 0; y < i; y++) {
            endY += closes.get(closes.size() - 1 - y);
        }
        endY = endY / i;
        c.drawLine(startX, startY, endX, endY, paint);
    }
}

图形联动

博客MPAndroidChart图形联动

相关文章
|
存储 弹性计算 运维
深度解读|NebulaGraph x 阿里云计算巢,云上构建超大规模图数据库
本文是NebulaGraph上架到计算巢的方案介绍,原文请查看:https://mp.weixin.qq.com/s/cj8ah7pfXqMFD74JOkmwow近期,杭州悦数科技有限公司与阿里云计算巢达成合作,NebulaGraph 作为首款图数据库产品正式入驻阿里云计算巢,为用户带来了云端一键部署企业级图数据库集群的全新体验。同时,该服务集成了多款 NebulaGraph 周边可视化图数据库管
581 0
深度解读|NebulaGraph x 阿里云计算巢,云上构建超大规模图数据库
|
JavaScript
vue-element-admin 安装依赖 npm install 报错ERESOLVE unable to resolve dependency tree解决方案
vue-element-admin 安装依赖 npm install 报错ERESOLVE unable to resolve dependency tree解决方案
|
存储 安全 API
NFS 的版本
【10月更文挑战第13天】
676 62
|
10月前
|
算法 搜索推荐 Java
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
430 6
|
人工智能 运维 IDE
通义灵码初体验:创新与惊喜并存
作为一名DevOps开发运维人员,我通过使用通义灵码个人版(v1.4.5)的代码生成和补全功能,显著提升了50%的工作效率。本文档详细记录了从安装配置到具体功能使用的全过程,包括代码解释、自动生成单元测试代码及根据需求生成新代码等功能的实际体验,展示了其高效、准确的特点,并提出了改进建议。
|
11月前
|
存储 数据可视化 Linux
语雀停机事件后,你也在找替代方案吗?
2023年10月23日,语雀遭遇长达8小时的服务中断,严重影响了用户的日常工作和生活。事后官方提供了6个月免费会员作为补偿。此次事件引发用户对云笔记产品的可靠性思考,Obsidian和思源笔记因注重本地存留而受到关注。Obsidian支持双向链接、Markdown、本地存储及插件系统,适合个人知识管理;思源笔记则强调关系图谱和快速引用功能。此外,也有用户选择印象笔记、腾讯文档等云产品或使用编辑器+网盘的方式。如何选择合适的工具取决于个人需求和偏好。
1032 2
|
监控 安全 数据安全/隐私保护
【Docker专栏】Docker容器安全:防御与加固策略
【5月更文挑战第7天】本文探讨了Docker容器安全,指出容器化技术虽带来便利,但也存在安全隐患,如不安全的镜像、容器逃逸、网络配置不当等。建议采取使用官方镜像、镜像扫描、最小权限原则等防御措施,并通过安全的Dockerfile编写、运行时安全策略、定期更新和访问控制等加固容器安全。保持警惕并持续学习安全实践至关重要。
1141 7
【Docker专栏】Docker容器安全:防御与加固策略
|
网络协议 Shell Linux
【Shell 命令集合 网络通讯 】⭐⭐⭐Linux 查看和配置网络接口的信息 ifconfig使用指南
【Shell 命令集合 网络通讯 】⭐⭐⭐Linux 查看和配置网络接口的信息 ifconfig使用指南
354 0
|
机器学习/深度学习 Python
Python应用专题 | 3:python读取文件由于编码问题失败汇总
汇总Python读取文件过程中常见的一些问题及其解决方法
|
JavaScript 前端开发
【前端】【Vue】Vue3自适应瀑布流解决方案
【前端】【Vue】Vue3自适应瀑布流解决方案
1706 0
【前端】【Vue】Vue3自适应瀑布流解决方案