CombinedChart

可以直接使用MPAndroidChart库里面提供的CombinedChart实现组合图形

Demo:CombinedChartDemo

——————分割线(如果想在一个图形上实现,可以参考下面的实现方式)——————


推荐直接使用CombinedChart实现

在GandleStickChart的基础上画均线

之前出过一篇MPAndroidChart的K线图上添加均线,但是在画均线的逻辑上有点问题,画出的均线永远是屏幕上显示的数据的均线,而不是全部数据的均线

在此调整了一下画均线的逻辑,并在上个版本上做了优化,使滑动更流畅,效果图如下:

画K线图的原理

在说画均线之前,先简单说说画K线图的流程

因为公司项目没有开源,现在只是简单聊下思路,贴下简单的代码(都是开源库里有的代码)

如果你已经用过并阅读过MPAndroidChart的代码,那么下面的东西,你一定能看懂。

步骤:

  1. 首先,库已经给我们封装了一个自定义控件,叫做CandleStickChart,专门是用来画K线的,我们把库引入到工程以后,再自定义一个类继承CandleStickChart控件,然后在我们自定义的控件里随意定义我们自己的K线图,就好了。
  2. 自定义的内容一般就是描述文字,X轴、Y轴的一些位置和样式,滑动、缩放动画,等等
  3. 自定义完我们的控件以后,就要显示数据了,如果你下载过Demo,你应该看过显示数据部分的实现,传递的数据一个是X轴的ArrayList和一个是Y轴的ArrayList,X轴一般是时间维度,Y轴传递的是每个时间维度要显示的数据对象,包括index、最高、最低、开盘、收盘,类似这样:

    yVals1.add(new CandleEntry(i, high, low, open, close));
  4. 数据传过去以后,就到了画数据的部分了,画数据的核心方法是CandleStickChartRenderer.javadrawDataSet(Canvas c, CandleDataSet dataSet)方法,在这个方法里,通过mRenderPaint画K线的每个节点(显示在屏幕上的节点)

  5. 动画,缩放等等,我们暂时就不操心了。

整个K线从无到有,大概就是这样的一个流程被画出来,那么如何添加均线呢

画均线思路

通过上面步骤的第三步,想要画均线,每个节点只传开盘、收盘、最高、最低,明显是不够的,那么在传递数据的时候,就需要在外面把每个节点的均值,算出来(均线的计算方法可以参考之前的文章),一块传递过去(用于画均线),修改了一下CandleEntry的数据结构,添加了5节点均线值、10节点均线值、30节点均线值的属性,并添加了get、set方法,如果没有值,用-1表示,如下

  • Code

    public class CandleEntry extends Entry {
    ……
    private float ma_5 = 0f;
    private float ma_10 = 0f;
    private float ma_30 = 0f;
    public CandleEntry(int xIndex, float shadowH, float shadowL, float open, float close,float ma5,float ma10,float ma30) {
    super((shadowH + shadowL) / 2f, xIndex);
    this.mShadowHigh = shadowH;
    this.mShadowLow = shadowL;
    this.mOpen = open;
    this.mClose = close;
    this.ma_5 = ma5;
    this.ma_10 = ma10;
    this.ma_30 = ma30;
    }
    public float getMa_5() {
    return ma_5;
    }
    public void setMa_5(float ma_5) {
    this.ma_5 = ma_5;
    }
    public float getMa_10() {
    return ma_10;
    }
    public void setMa_10(float ma_10) {
    this.ma_10 = ma_10;
    }
    public float getMa_30() {
    return ma_30;
    }
    public void setMa_30(float ma_30) {
    this.ma_30 = ma_30;
    }
    ……
    }

每个节点的均值计算以及数据传递的代码大概是下面这个样子:

  • Code

    for (int i = 0; i < kLineInfo.getData().size(); i++) {
    float high = kLineInfo.getData().get(i).getHigh();
    float low = kLineInfo.getData().get(i).getLow();
    float open = kLineInfo.getData().get(i).getOpen();
    float close = kLineInfo.getData().get(i).getClose(); float ma5 = -1;
    if (i >= 4) {
    ma5 = 0;
    for (int a = i - 4; a <= i; a++) {
    ma5 += kLineInfo.getData().get(a).getClose();
    }
    ma5 /= 5;
    }
    float ma10 = -1;
    if (i >= 9) {
    ma10 = 0;
    for (int a = i - 9; a <= i; a++) {
    ma10 += kLineInfo.getData().get(a).getClose();
    }
    ma10 /= 10;
    }
    float ma30 = -1;
    if (i >= 29) {
    ma30 = 0;
    for (int a = i - 29; a <= i; a++) {
    ma30 += kLineInfo.getData().get(a).getClose();
    }
    ma30 /= 30;
    }
    yVals1.add(new CandleEntry(i, high, low, open, close, ma5, ma10, ma30));
    }

显示

在画均线的之前,需要通过如下代码将传递过来的数据转换成在页面上显示的具体位置,存储到buffer里:

因为我们自己添加了ma5、ma10、ma30的属性,所以在转换的过程我们也要做一定的处理

  • Code

    package ……;
    import ……;
    public class CandleBodyBuffer extends AbstractBuffer<CandleEntry> {
    ……
    private void addBody(float left, float top, float right, float bottom, float ma5, float ma10, float ma30) {
    buffer[index++] = left;
    buffer[index++] = top;
    buffer[index++] = right;
    buffer[index++] = bottom;
    buffer[index++] = ma5;
    buffer[index++] = ma5;
    buffer[index++] = ma10;
    buffer[index++] = ma10;
    buffer[index++] = ma30;
    buffer[index++] = ma30;
    }
    @Override
    public void feed(List<CandleEntry> entries) {
    int size = (int) Math.ceil((mTo - mFrom) * phaseX + mFrom);
    for (int i = mFrom; i < size; i++) {
    CandleEntry e = entries.get(i);
    addBody(e.getXIndex() - 0.5f + mBodySpace, e.getClose() * phaseY, e.getXIndex() + 0.5f - mBodySpace, e.getOpen() * phaseY, e.getMa_5() * phaseY, e.getMa_10() * phaseY, e.getMa_30() * phaseY);
    }
    reset();
    }
    }

  • Code

    package   ……;
    import ……;
    public class CandleShadowBuffer extends AbstractBuffer<CandleEntry> {
    public CandleShadowBuffer(int size) {
    super(size);
    }
    private void addShadow(float x1, float y1, float x2, float y2, float ma5, float ma10, float ma30) {
    buffer[index++] = x1;
    buffer[index++] = y1;
    buffer[index++] = x2;
    buffer[index++] = y2;
    buffer[index++] = ma5;
    buffer[index++] = ma5;
    buffer[index++] = ma10;
    buffer[index++] = ma10;
    buffer[index++] = ma30;
    buffer[index++] = ma30;
    }
    @Override
    public void feed(List<CandleEntry> entries) {
    int size = (int)Math.ceil((mTo - mFrom) * phaseX + mFrom);
    for (int i = mFrom; i < size; i++) {
    CandleEntry e = entries.get(i);
    addShadow(e.getXIndex(), e.getHigh() * phaseY, e.getXIndex(), e.getLow() * phaseY, e.getMa_5() * phaseY, e.getMa_10() * phaseY, e.getMa_30() * phaseY);
    }
    reset();
    }
    }

在DataRenderer.java里定义一个画均线的画笔

protected Paint mMAPaint;
public DataRenderer(ChartAnimator animator, ViewPortHandler viewPortHandler) {
super(viewPortHandler);
……
mMAPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mMAPaint.setStrokeWidth(1);
mMAPaint.setColor(0xFFC7238B);
}

画均线

@Override
public void initBuffers() {
CandleData candleData = mChart.getCandleData();
mShadowBuffers = new CandleShadowBuffer[candleData.getDataSetCount()];
mBodyBuffers = new CandleBodyBuffer[candleData.getDataSetCount()]; for (int i = 0; i < mShadowBuffers.length; i++) {
CandleDataSet set = candleData.getDataSetByIndex(i);
mShadowBuffers[i] = new CandleShadowBuffer(set.getValueCount() * 10);
mBodyBuffers[i] = new CandleBodyBuffer(set.getValueCount() * 10);
}
} protected void drawDataSet(Canvas c, CandleDataSet dataSet) { ……
int range = (maxx - minx) * 10;
……
float tempMA5X = -1;
float tempMA5Y = -1;
float tempMA10X = -1;
float tempMA10Y = -1;
float tempMA30X = -1;
float tempMA30Y = -1;
// draw the body
for (int j = 0; j < range; j += 10) { …… float leftBody = bodyBuffer.buffer[j];
float open = bodyBuffer.buffer[j + 1];
float rightBody = bodyBuffer.buffer[j + 2];
float close = bodyBuffer.buffer[j + 3]; float ma5 = bodyBuffer.buffer[j + 5];
float ma10 = bodyBuffer.buffer[j + 7];
float ma30 = bodyBuffer.buffer[j + 9]; …… // 画5均线
if (e.getMa_5() != -1) {
if (tempMA5X != -1 && tempMA5Y != -1) {
// 画线
mMAPaint.setColor(0xFFC7238B);
c.drawLine(tempMA5X, tempMA5Y, (leftBody + rightBody) / 2, ma5, mMAPaint);
}
// 赋值
tempMA5X = (leftBody + rightBody) / 2;
tempMA5Y = ma5;
} // 画10均线
if (e.getMa_10() != -1) {
if (tempMA10X != -1 && tempMA10Y != -1) {
// 画线
mMAPaint.setColor(0xFFDFAA2A);
c.drawLine(tempMA10X, tempMA10Y, (leftBody + rightBody) / 2, ma10, mMAPaint);
}
// 赋值
tempMA10X = (leftBody + rightBody) / 2;
tempMA10Y = ma10;
} // 画30均线
if (e.getMa_30() != -1) {
if (tempMA30X != -1 && tempMA30Y != -1) {
// 画线
mMAPaint.setColor(0xFF268BC6);
c.drawLine(tempMA30X, tempMA30Y, (leftBody + rightBody) / 2, ma30, mMAPaint);
}
// 赋值
tempMA30X = (leftBody + rightBody) / 2;
tempMA30Y = ma30;
}
}
}

到此,搞定!解决了上一个方案重复绘制均线,导致滑动不是很流畅的问题。

说明

对于上面buffer为什么存了2遍

buffer[index++] = ma5;
buffer[index++] = ma5;
buffer[index++] = ma10;
buffer[index++] = ma10;
buffer[index++] = ma30;
buffer[index++] = ma30;

因为之前,里边只有4个属性,现在加了3个属性以后,他转换的计算有点问题

以前的方法可能是针对这4个属性转换的,我debug观察了下转换后的结果,数组的奇数角标和偶数角标位置的计算逻辑是不一样的

那么为了不改它太深层的东西(怕影响到其他图形,也不想给自己添加麻烦),我干脆就都赋值了两遍

但是我取值的时候,只取我想要的

float ma5 = bodyBuffer.buffer[j + 5];
float ma10 = bodyBuffer.buffer[j + 7];
float ma30 = bodyBuffer.buffer[j + 9];

this all!!

在MPAndroidChart库K线图的基础上画均线的更多相关文章

  1. MPAndroidChart的K线图上添加均线

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

  2. 如何看K线图基础知识

    在日K线图中一般白线.黄线.紫线.绿线依次分别表示:5.10.20.60日移动平均线,但这并不是固定的,会根据设置的不同而不同,比如你也可以在系统里把它们设为5.15.30.60均线. 你看K线图的上 ...

  3. IOS 股票K线图、分时图

    IOS 股票K线图.分时图,网上开源项目很少,质量也是参差不齐:偶尔搜索到看似有希望的文章,点进去,还是个标题党:深受毒害.经过一段时间的探索,终于在开源基础上完成了自己的股票K线图.分时图: 先放出 ...

  4. Android开源图表图形库K线图

    Android开源图表图形库K线图 web端k线图一般使用TradingView,android原生的一般是在MPAndroidChart 基础上做开发的,目前看到一个比较好的K线开源组件是KChar ...

  5. 如何从零绘制k线图 -- 原生js canvas图表绘制

    样式如下图 源码地址: https://github.com/sutianbinde/charts 编写这个需要具备canvas基础,如果没有canvas基础可以学习我前面的cnavas基础博客. 具 ...

  6. 【带着canvas去流浪(5)】绘制K线图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文 ...

  7. vue使用tradingview开发K线图相关问题

    vue使用tradingview开发K线图相关问题 1.TradingView中文开发文档https://b.aitrade.ga/books/tradingview/CHANGE-LOG.html2 ...

  8. 关于k Line Chart (k线图)

    K Line Chart python实现k线图的代码,之前找过matplotlib中文文档但是画k线图的finance方法已经弃用了.所以自己在网上搜寻一下加上改编,很好的实现出k线图, 代码如下: ...

  9. Vue中引入TradingView制作K线图

    **前言: 本文使用的是1.10版本 , 可通过TradingView.version()查看当前版本. 附上开发文档地址:https://zlq4863947.gitbooks.i...** 一.修 ...

随机推荐

  1. 自定义Loader

    自定义Loader涉及到的接口: public delegate byte[] CustomLoader(ref string filePath); public void LuaEnv.AddLoa ...

  2. requests之一:HTTP请求 状态码

    1.请求方法主要有如下几种: Verb 描述 HEAD 只获取某个资源的头部信息,元数据.比如只想了解某个文件的大小,某个资源的修改日期等 GET 获取资源,一个或者多个 POST 创建资源 PATC ...

  3. ASP.NET CORE系列【六】Entity Framework Core 之数据库迁移

    前言 最近打算用.NET Core写一份简单的后台系统,来练练手 然后又用到了Entity Framework Core 发现园子里有些文章讲得不是那么细节,对于新手小白来说,可能会有点懵. 特意整理 ...

  4. 使用 dotnet cli 命令上传 nuget 程序包

    前言 前面写了一篇文章介绍了如何将自己的程序集打包成nuget package并上传到nuget.org,传送门.全部是通过网页端来进行操作的,现在介绍一种比较方便快捷的方法就是用dotnet cli ...

  5. python 装饰器统计某个函数的运行时间

    import datetime def count_time(func): def int_time(*args, **kwargs): start_time = datetime.datetime. ...

  6. ConcurrentHashMap源码分析(1.8)

    0.说明 1.ConcurrentHashMap跟HashMap,HashTable的对比 2.ConcurrentHashMap原理概览 3.ConcurrentHashMap几个重要概念 4.Co ...

  7. hibernate--CRUD初体验

    hibernate的crud操作初体验. 看具体实例 package com.fuwh.model; import javax.persistence.Column; import javax.per ...

  8. [HNOI2007]分裂游戏

    Description 聪聪和睿睿最近迷上了一款叫做分裂的游戏. 该游戏的规则试: 共有 n 个瓶子, 标号为 0,1,2.....n-1, 第 i 个瓶子中装有 p[i]颗巧克力豆,两个人轮流取豆子 ...

  9. [Ioi2011]ricehub

    Description 乡间有一条笔直而长的路称为“米道”.沿着这条米道上 R 块稻田,每块稻田的坐标均 为一个 1 到 L 之间(含 1 和 L)的整数.这些稻田按照坐标以不减的顺序给出,即对于 0 ...

  10. NOIP 2013

    Prob.1 转圈游戏 找到循环节,然后快速幂.代码: #include<cstdio> #include<cstring> #include<iostream> ...