赞
踩
画K线图的原理
在说画均线之前,先简单说说画K线图的流程
因为公司项目没有开源,现在只是简单聊下思路,贴下简单的代码(都是开源库里有的代码)
如果你已经用过并阅读过MPAndroidChart的代码,那么下面的东西,你一定能看懂。
首先,库已经给我们封装了一个自定义控件,叫做CandleStickChart,专门是用来画K线的,我们把库引入到工程以后,再自定义一个类继承CandleStickChart控件,然后在我们自定义的控件里随意定义我们自己的K线图,就好了。
自定义的内容一般就是描述文字,X轴、Y轴的一些位置和样式,滑动、缩放动画,等等
自定义完我们的控件以后,就要显示数据了,如果你下载过Demo,你应该看过显示数据部分的实现,传递的数据一个是X轴的ArrayList和一个是Y轴的ArrayList,X轴一般是时间维度,Y轴传递的是每个时间维度要显示的数据对象,包括index、最高、最低、开盘、收盘,类似这样:
yVals1.add(new CandleEntry(i, high, low, open, close));
数据传过去以后,就到了画数据的部分了,画数据的核心方法是CandleStickChartRenderer.java 的 drawDataSet(Canvas c, CandleDataSet dataSet)方法,在这个方法里,通过mRenderPaint画K线的每个节点(显示在屏幕上的节点)
动画,缩放等等,我们暂时就不操心了。
整个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]; **自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。** **深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!** **因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。** ![img](https://img-blog.csdnimg.cn/img_convert/7236f124879e1034fb9307416cd1f972.png) ![img](https://img-blog.csdnimg.cn/img_convert/268765538da945d194bdb2be6288f2a2.png) ![img](https://img-blog.csdnimg.cn/img_convert/19af0c8bce1f60abed0902ad0e8e16da.png) ![img](https://img-blog.csdnimg.cn/img_convert/136b9289704fe597c9bc73904163f932.png) ![img](https://img-blog.csdnimg.cn/img_convert/fba811e527c1bc5369ad0de494803483.png) ![img](https://img-blog.csdnimg.cn/img_convert/e8bf85461d874833627c300ba2788a27.png) ![img](https://img-blog.csdnimg.cn/13f2cb2e05a14868a3f0fd6ac81d625c.png) **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!** **由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新** **如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)** ![img](https://img-blog.csdnimg.cn/img_convert/8ac73b475bb5a0238e35521db491bd8b.png) ### 最后 希望大家能有一个好心态,想进什么样的公司要想清楚,并不一定是大公司,我选的也不是特大厂。当然如果你不知道选或是没有规划,那就选大公司!希望我们能先选好想去的公司再投或内推,而不是有一个公司要我我就去!还有就是不要害怕,也不要有压力,平常心对待就行,但准备要充足。最后希望大家都能拿到一份满意的 offer !如果目前有一份工作也请好好珍惜好好努力,找工作其实挺累挺辛苦的。 > 这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。 由于篇幅有限,这里以图片的形式给大家展示一小部分。 ![](https://img-blog.csdnimg.cn/img_convert/6cff902decd33031f6a69679a0949190.webp?x-oss-process=image/format,png) **一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!** ![img](https://img-blog.csdnimg.cn/img_convert/4dfd62cd58f27b6d397f8e91a14e0464.png) 希望大家能有一个好心态,想进什么样的公司要想清楚,并不一定是大公司,我选的也不是特大厂。当然如果你不知道选或是没有规划,那就选大公司!希望我们能先选好想去的公司再投或内推,而不是有一个公司要我我就去!还有就是不要害怕,也不要有压力,平常心对待就行,但准备要充足。最后希望大家都能拿到一份满意的 offer !如果目前有一份工作也请好好珍惜好好努力,找工作其实挺累挺辛苦的。 > 这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。 由于篇幅有限,这里以图片的形式给大家展示一小部分。 [外链图片转存中...(img-tLEXKn7V-1712899512242)] **一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!** [外链图片转存中...(img-x8Usut4m-1712899512243)]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。