股票蝴蝶效应的画法K线图怎么画 K线图的画法

K线图的画法
&&& K线图源于日本,被当时日本米市的商人用来记录米市的行情与价格波动,后因其细腻独到的标画方式而被引入到股市及期货市场。由于用这种方法绘制出来的图表形状颇似一根根蜡烛,加上这些蜡烛有黑白之分,因而也叫阴阳线图表。通过K线图,我们能够把每日或某一周期的市况表现完全记录下来,  股价经过一段时间的盘档后,在图上即形成一种特殊区域或形态,不同的形态显示出不同意义。我们可以从这些形态的变化中摸索出一些有规律的东西出来。K线图形态可分为反转形态、整理形态及缺口和趋向线等,下面介绍K线图画法 日K线是根据股价(指数)一天的走势中形成的四个价位即:开盘价,收盘价,最高价,最低价绘制而成的.收盘价高于开盘价时,则开盘价在下收盘价在上,二者之间的长方柱用红色或空心绘出,称之为阳线;其上影线的最高点为最高价,下影线的最低点为最低价.收盘价低于开盘价时,则开盘价在上收盘价在下,二者之间的长方柱用黑色或实心绘出,称之为阴线,其上影线的最高点为最高价,下影线的最低点为最低价.根据K线的计算周期可将其分为日K线,周K线,月K线,年K线.周K线是指以周一的开盘价,周五的收盘价,全周最高价和全周最低价来画的K线图.月K线则以一个月的第一个交易日的开盘价,最后一个交易日的收盘价和全月最高价与全月最低价来画的K线图,同理可以推得年K线定义.周K线,月K线常用于研判中期行情.对于短线操作者来说,众多分析软件提供的5分钟K线、15分钟K线、30分钟K线和60分钟K线也具有重要的参考价值.
赞助商链接
猜您想看:
最新更新章节
必读股票书籍
必备炒股软件下载
赞助商链接
当前所属书籍
本书由炒股巴士收集整理汇编,内容比较适合新手学习,是炒股知识旅程必备的书籍,也是用图解的形式,一般新股民学习比较适合,当然对于没有看过的老股民也不妨浏览学习。
Copyright &
About cg84. 炒股巴士网版权所有股票K线图怎么绘制
股票K线图怎么绘制
学习啦【投资理财知识】 编辑:李敏
  股票K线,也称日本蜡烛图,长得像蜡烛一样,常用红色和绿色表示!一条K线代表股票一天的走势,也代表着当天投资者们对它的看法。不同的K线代表不同的意义,透视着不同的信息。如何看K线,到底看懂它对我们的投资有什么帮助?下面学习啦小编和大家深入探讨。
  一、K线图绘制方法
  首先我们找到该日或某一周期的最高和最低价,垂直地连成一条直线;然后再找出当日或某
  一周期的开市和收市价,把这二个价位连接成一条狭长的长方柱体。假如当日或某一周期的收市价较开市价为高(即低开高收),我们便以红色来表示,或是在柱体上留白,这种柱体就称之为&阳线&。如果当日或某一周期的收市价较开市价为低(即高开低收),我们则以蓝色表示,又或是在住柱上涂黑色,这柱体就是&阴线&了。
  二、优点
  能够全面透彻地观察到市场的真正变化。我们从K线图中,既可看到股价(或大市)的趋势,也同时可以了解到每日市况的波动情形。
  三、缺点
  (1)绘制方法十分繁复,是众多走势图中最难制作的一种。
  (2)阴线与阳线的变化繁多,对初学者来说,在掌握分析方面会有相当的困难,不及柱线图那样简单易明。
  四、分析意义
  由于&阴阳线&变化繁多,&阴线&与&阳线&里包涵着许多大小不同的变化,因此其分析的意义,有特别提出一谈的必要。
  在讨论&阴阳线&的分析意义之前,先让我们知道阳线每一个部分的名称。
  我们以阳线为例,最高与收市价之间的部分称之为&上影&,开市价与收市价之间称为&实体&,开市价与最低价之间就称作&下影&。
  1.长红线或大阳线
  此种图表示最高价与收盘价相同,最低价与开盘价一样。上下没有影线。从一开盘,买方就积极进攻,中间也可能出现买方与卖方的斗争,但买方发挥最大力量,一直到收盘。买方始终占优势,使价格一路上扬,直至收盘。表示强烈的涨势,股市呈现高潮,买方疯狂涌进,不限价买进。握有股票者,因看到买气的旺盛,不愿抛售,出现供不应求的状况。
  2.长黑线或大阴线
  此种图表示最高价与开盘价相同,最低价与收盘价一样。上下没有影线。从一开始,卖方就占优势。股市处于低潮。握有股票者不限价疯狂抛出,造成恐慌心理。市场呈一面倒,直到收盘、价格始终下跌,表示强烈的跌势。
  3.先跌后涨型
  这是一种带下影线的红实体。最高价与收盘价相同,开盘后,卖气较足,价格下跌。但在低价位上得到买方的支撑,卖方受挫,价格向上推过开盘价,一路上扬,直至收盘,收在最高价上。总体来讲,出现先跌后涨型,买方力量较大,但实体部分与下影线长短不同,买方与卖方力量对比不同。
  实体部分比下影线长。价位下跌不多,即受到买方支撑,价格上推。破了开盘价之后,还大幅度推进,买方实力很大。
  实体部分与下影线相等,买卖双方交战激烈,但大体上,买方占主导地位,对买方有利。
  实体部分比下影线短。买卖双方在低价位上发生激战。遇买方支撑逐步将价位上推。但从图中可发现,上面实体部分较小,说明买方所占据的优势不太大,如卖方次日全力反攻,则买方的实体很容易被攻占。
  4.下跌抵抗型
  这是一种带下影线的黑实体,开盘价是最高价。一开盘卖方力量就特别大,价位一种下跌,但在低价位上遇到买方的支撑。后市可能会反弹。实体部分与下影线的长短不同也可分为三种情况:
  (1)实体部分比影线长卖压比较大,一开盘,大幅度下压,在低点遇到买方抵抗,买方与卖方发生激战,影线部分较短,说明买方把价位上推不多,从总体上看,卖方占了比较大的优势。
  (2)实体部分与影线同长表示卖方把价位下压后,买方的抵抗也在增加,但可以看出,卖方仍占优势。
  (3)实体部分比影线短卖方把价位一路压低,在低价位上,遇到买方顽强抵抗并组织反击,逐渐把价位上推,最后虽以黑棒收盘,但可以看出卖方只占极少的优势。后市很可能买方会全力反攻,把小黑实体全部吃掉。
  5.上升阻力
  这是一种带上影线的红实体。开盘价即最低价。一开盘买方强盛,价位一路上推,但在高价位遇卖方压力,使股价上升受阻。卖方与买方交战结果为买方略胜一筹。具体情况仍应观察实体与影线的长短。
  红实体比影线长,表示买方在高价位是遇到阻力,部分多头获利回吐。但买方仍是市场的主导力量,后市继续看涨。
  实体与影线同长,买方把价位上推,但卖方压力也在增加。二者交战结果,卖方把价位压回一半,买方虽占优势。但显然不如其优势大。
  实体比影线短。在高价位遇卖方的压力、卖方全面反击,买方受到严重考验。大多短线投资者纷纷获利回吐,在当日交战结束后,卖方已收回大部分失地。买方一块小小的堡垒(实体部分)将很快被消灭,这种K线如出现在高价区,则后市看跌。
  6.先涨后跌型
  这是一种带上影线的黑实体。收盘价即是最低价。一开盘,买方与卖方进行交战。买方占上风,价格一路上升。但在高价位遇卖压阻力,卖方组织力量反攻,买方节节败退,最后在最低价收盘,卖方占优势,并充分发挥力量,使买方陷入&套牢&的困境。
  具体情况仍有以下三种:
  (1)黑实体比影线长表示买方把价位上推不多,立即遇到卖方强有力的反击,把价位压破开盘价后乘胜追击,再把价位下推很大的一段。卖方力量特别强大,局势对卖方有利。
  (2)黑实体与影线相等买方把价位上推;但卖方力量更强,占据主动地位。卖方具有优势。
  (3)黑实体比影线短卖方虽将价格下压,但优势较少,明日入市,买方力量可能再次反攻,黑实体很可能被攻占。
  7.反转试探型
  这是一种上下都带影线的红实体。开盘后价位下跌,遇买方支撑,双方争斗之后,买方增强,价格一路上推,临收盘前,部分买者获利回吐,在最高价之下收盘。这是一种反转信号。如在大涨之后出现,表示高档震荡,如成交量大增,后市可能会下跌。如在大跌后出现,后市可能会反弹。这里上下影线及实体的不同又可分为多种情况:
  (1)上影线长于下影线之红实体:又分为:影线部分长于红实体表示买方力量受挫折。红实体长于影线部分表示买方虽受挫折,但仍占优势。
  (2)下影线长于上影线之红实体:亦可分为:红实体长于影线部分表示买方虽受挫折,仍居于主动地位。影线部分长于红实体表示买方尚需接受考验。
  8.弹升试探型
  这是一种上下都带影线的黑实体,在交易过程中,股价在开盘后,有时会力争上游,随着卖方力量的增加,买方不愿追逐高价,卖方渐居主动,股价逆转,在开盘价下交易,股价下跌。在  低价位遇买方支撑,买气转强,不至于以最低价收盘。有时股价在上半场以低于开盘价成交,下半场买意增强,股价回至高于开盘价成交,临收盘前卖方又占优势,而以低于开盘价之价格收盘。这也是一种反转试探。如在大跌之后出现,表示低档承接,行情可能反弹。如大涨之后出现,后市可能下跌。
  9.十字线型
  这是一种只有上下影线,没有实体的图形。开盘价即是收盘价,表示在交易中,股价出现高于或低于开盘价成交,但收盘价与开盘价相等。买方与卖方几乎势均力敌。
  其中:上影线越长,表示卖压越重。下影线越长,表示买方旺盛。上下影线看似等长的十字线,可称为转机线,在高价位或低价位,意味着出现反转。
  10.&┴&图形
  又称空胜线,开盘价与收盘价相同。当日交易都在开盘价以上之价位成交,并以当日最低价(即开盘价)收盘,表示买方虽强,但卖方更强,买方无力再挺升,总体看卖方稍占优势,如在高价区,行情可能会下跌。
  &T&图形又称多胜线,开盘价与收盘价相同,当日交易以开盘价以下之价位成交,又以当日最高价(即开盘价)收盘。卖方虽强,但买方实力更大,局势对买方有利,如在低价区,行情将会回升。
  11.&一&图形
  此较形不常见,即开盘价、收盘价、最高价、最低价在同一价位。只出现于交易非常冷清,全日交易只有一档价位成交。冷门股此类情形较易发生。
[股票K线图怎么绘制]相关的文章
【投资理财知识】图文推荐趋势线的画法 k线图如何画趋势线- 盛博股票学习网
当前位置:
趋势线的画法 k线图如何画趋势线
来源: 网络作者:匿名时间: 20:05
趋势线的画法 k线图如何画趋势线很多股民不会画趋势线图,因此无法对股票做出更深层次的分析。那么在k线图如何画趋势线呢?今天笔者就针对这个问题,给大家做一些详细的介绍,希望股民能够有所掌握。一、趋势线画法可以切过实体边缘,但不要切过实体为原则。而突破和跌破趋势线,要以收盘价为有效突破或跌破的确认特别是这条趋势线近于水平走势时。趋势线的角度决定了当时走势的强弱。但这只是一个相对分析。二、突破与跌破的确认突破与跌破行为,不在于突破或跌破多少百分比,或是突破或跌破几天,而在于关键价位的分析。真突破必须针对压力或关卡进行多头表态,也就是以明显的多头走势站上颈线(如中长阳线),且当比K线的收盘价必须收在颈线之上,而当笔K线的低点即为观察点,未来股价没有跌破该低点,并满足某一个测量幅度,就是真突破。跌破的判断亦然。三、骗线当出现骗线时,代表操作的停损机制要立即激活,同时进行逆向思考。四、支撑压力的转换“支撑压力交换规律”。当压力被突破后,该趋势线将转换为支撑;当支撑被跌破后,支撑将转换为压力。原始的上升趋势线被跌破后转为压力线,同时有机会反弹回测,不代表一定会回测。五、“中心趋势线”用意:1.如果股价针对该趋势线呈现真突破,理应出现强势多头行情。2.如果无法呈现真突破,又结束惯性反弹走势,则容易出现主跌段。六、趋势三条线原始上升趋势线(基本趋势线)、第一上升修正趋势线(主趋势线)、第二上升修争趋势线(次要趋势线)。上升趋势中,没有跌破主趋势线L1以前,代表股价仍有机会创新高。当股价跌破次要趋势线L2时,往往代表多头走势即将结束或已经结束,并有机会测试主趋势线。原始上升趋势线的角度较为平缓,同时也不容易被跌破,万一被跌破则强烈暗示主趋势已经被改变,未来股价出现上涨都视为反弹。L1主趋势线有重要参考价值,很有可能为顶部的转折点。下降趋势三条线同理。七、扇形三条线扇形三条线有一个明显的特色,趋势线之间的夹角大致相等,这可作为协助我们取线的辅助观察法。当股价突破第三条趋势线后,意味着将进行反向运动。八、轨道的转换在上涨走势中,利用谷底决定上升趋势(支撑线),再取并行线切过股价波动的上缘(压力线),这两条线合称“上升通道”。积极性的投资人可以在轨道中以高抛低吸操作,直到轨道线被破坏。计算公式:D = B + C - AD = B x C / A若股价沿着原本平缓的上升通道前进时,忽然突破上轨,代表当时多方的买盘力道强劲,股价将有机会进入一个角度较陡的轨道线。轨道的角度决定趋势强弱程度。以上都是有关K线图如何画趋势线的相关介绍,如果您还想要了解更多股票相关知识与资讯,可关注盛博股票学习网(),我们将为您提供更多的股票消息!
股市热词 :
股票入门教材
周K线选股技巧:一文教你用周K线选出黑马股。下面由盛博股票小编为您介绍。
K线形态分析,从K线识别主力意图。下面由盛博股票小编为您介绍。
1、K线形态之高位中阴线或者大阴线。往往是主力出货的标志,如果伴随着较大的成交量,同时主力统计显示该股主力机构是绿色,那么后期的反弹是出货的
最全K线买卖法则,K线形态判断个股的走向。下面由盛博股票小编为您介绍。
K线选股绝招实战图解,怎么看K线选股?下面由盛博股票小编为您介绍。
一、比翼齐飞Android(312)
股票图,K线图,蜡烛图,高仿雪球股票,教你一步步实现股票图
讲K线图之前,先来一个引言.
前两天听了大神的知乎live,其中说到一点,作为Android开发者需要立即提升的三项技能:
分别是:UI,网络,线程,而UI又分:布局,绘制,以及触摸事件的反馈.凯哥强调:其实UI确实只有这么几个最主要的东西,但是很多人却没能搞明白.
UI的这三方面,说容易也容易,说难也难.有同学当时也问到:怎么样才能算是掌握了这三个方面呢?
凯哥当时的回答是:给出一个不算是为难的界面,能布局出来,绘制好,并掌握相应的触摸反馈,就算是基本上掌握UI了.
实际上UI容易也是在这里,初步上手,对大部分比较认真的同学来说都是可以做到的,但是深入了解的,却比较少.例如,触摸Touch事件是如何分发的,
它的原理是什么,这就需要大家更加深入的学习了.
前面说到的UI的三个方面,其实在股票图里面都有比较好的体现,下面就这三个方法,讲解一下实现股票图的思路
股票图基本知识
了解股票图如何绘制,首先应该了解股票图的业务逻辑是怎样的,这篇文章是仿雪球股票写的,建议大家下载雪球股票软件体验一下.在写这个股票图之前,我对股票是一无所知(原谅我穷买不起股票),
所以花了一点时间了解了一下股票图的基本信息,如果知道股票图是如何解读的,可以跳过这节.
股票图的种类特别多,不同的种类的股票图也不一样,例如股票有港股,美股,上证,深圳,创业板等等.然后上证又有:分时,日K,月K等等.
复杂程度完全可以直接绕晕人,没错,我就是看不懂所以不敢买.
股票图的种类之多,本文也没有一一编写,这里主要是仿照了雪球股票之上证指数的:分时图,以及日K图.
也就是股票的两大图种:分时图,以及蜡烛图.
分时图有股票当天的涨跌情况,以及一些最高点,最低点,比分比,
长按分时图,可以定位当时手指按下的时间所对应的股票点是多少点,并且可以左右滑动
股票的开盘时间是早上09:30~11:30,下午是13:00~15:00.
蜡烛图和分时图类似,先除去那三条折线.分时图是把涨跌情况用折线表示,而蜡烛图是用一个矩形加一条竖线表示,和一根蜡烛一样,所以形象的称它为蜡烛图,
其中竖线的最高点代表当日最高涨到了多少点,最低表示最低跌到了多少点.
矩形的顶端,表示当日开盘是多少点,底端,表示收盘是多少点.
颜色红,代表收盘后,相对于昨天,涨了,颜色绿,则表示跌了.
三条折线分别代表了MA线,MA是“移动平均线”的简称,后面的数字:5、10、20.....是时间周期。MA5即5天收盘股票的平均点,其他的类推.博主这个例子没有实现MA线,作为大家的补充练手
日K图每个月一个间隔.
下面就分时图,蜡烛图,分别讲解其布局,绘制,触摸反馈
布局无论是xml引用layout编写,亦或是java直接new出来,或者是使用canvas直接绘制,最重要的不是应该使用
RelativeLayout还是LinearLayout,而是应该剖析它的层次与结构.
根据上面的基本介绍,分时图的可以分为以下几个层次:
第1层:横线,竖线,以及底部时间(底部时间没有其他的元素,可以处于任意一层)
第2层:折线,以及阴影部分
第3层:文字,包括最高点,最低点,百分比
分时图的结构相对简单,在基本介绍上已经说明其基本信息.
股票的开盘时间是早上09:30~11:30,下午是13:00~15:00,所以其分上午,下午两部分.
中间的虚线是昨天收盘的股票点,以此为基准线,计算折线图的位置.
布局分析好之后,就开始绘制这些基本信息.普通View的绘制,是写好xml或者java代码,然后交给每个view自己绘制,这里我们自己控制其绘制.
绘制的步骤,其实就是布局中所说的层次,绘制的规则,则是布局中的结构.换句话说,这个结构,规则,就是数学中的公式,步骤就是我们解题的思路.
详细绘制步骤
自定义一个View,覆写其四个构造方法(注意最好四个构造方法都覆写,这样就可以通过多种途径新建这个View),覆写onDraw()方法,画图的时候就是在这个方法进行绘制的.
public class KLineView extends View {
public KLineView(Context context) {
super(context);
public KLineView(Context context, AttributeSet attrs) {
super(context, attrs);
public KLineView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public KLineView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
一般还需要初始化一些信息.为了让自己能看到每一步的绘制效果,编写一个添加测试数据方法,初始化的时候执行该方法即可.
private Paint mP
private void init() {
mPaint = new Paint();
createTestData();
private void createTestData() {
baseData = 3120.50f;
times = new ArrayList&&();
prices = new ArrayList&&();
@SuppressLint(&SimpleDateFormat&) SimpleDateFormat dateFormat = new SimpleDateFormat
(&yyyy-MM-dd HH:mm:ss&);
Date date = dateFormat.parse(& 09:30:00&);
for (int i = 0; i & 240; i++) {
if (i == 120) {
date = dateFormat.parse(& 13:00:00&);
date.setTime(date.getTime() + 60 * 1000);
times.add(formatTime(dateFormat.format(date)));
if (i == 0) tmp = (float) (baseData + 5 - Math.random() * 10);
else tmp = (float) (prices.get(i - 1) + 5 - Math.random() * 10);
tmp = formatPrice(tmp);
if (tmp & maxPrice) {
maxPrice =
if (tmp & minPrice) {
minPrice =
prices.add(tmp);
} catch (ParseException e) {
e.printStackTrace();
使用MarkMan量取,分时图在720*1280分辨率下,高度是是410,则我们可以把其高度分成410份.
它一共有5条横线,从上到下,每条线距离顶部的距离依次为:10,30,190,360,380.其中第3条为虚线.还有一条竖线,水平居中.
依次画出每一条线.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int viewHeight = getHeight();
int viewWidth = getWidth();
float item = viewHeight / 410f;
drawLines(canvas, viewWidth, item);
viewWidth the view's width
the view's height divided into 410
private void drawLines(Canvas canvas, int viewWidth, float item) {
mPaint.setColor(Color.parseColor(&#AAAAAA&));
mPaint.setStrokeWidth(0f);
canvas.drawLine(0, item * 10, viewWidth, item * 10, mPaint);
canvas.drawLine(0, item * 30, viewWidth, item * 30, mPaint);
drawDashEffect(canvas, 0, item * 190, viewWidth, item * 190);
canvas.drawLine(0, item * 360, viewWidth, item * 360, mPaint);
canvas.drawLine(0, item * 380, viewWidth, item * 380, mPaint);
canvas.drawLine(viewWidth / 2.0f, item * 10, viewWidth / 2.0f, item * 380, mPaint);
canvas canvas
private void drawDashEffect(Canvas canvas, float x, float y, float endX, float endY) {
PathEffect effects = new DashPathEffect(new float[]{8, 8, 8, 8}, 1);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(Color.parseColor(&#AAAAAA&));
p.setPathEffect(effects);
p.setStyle(Paint.Style.STROKE);
Path path = new Path();
path.moveTo(x, y);
path.lineTo(endX, endY);
canvas.drawPath(path, p);
时间的最简单,三个时间是固定的,位置也是固定的.
需要注意的是,绘制文字的x,y坐标,x=文字的左边,y=文字的baseline,文字的baseline默认等于-mPaint.getFontMetrics().top
想了解更多关于文字绘制的细节,请移步到这篇文章
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int viewHeight = getHeight();
int viewWidth = getWidth();
float item = viewHeight / 410f;
drawTimes(canvas, viewWidth, item);
viewWidth view's width
the view's height divided into 410
private void drawTimes(Canvas canvas, int viewWidth, float item) {
mPaint.setTextSize(TypedValue.PLEX_UNIT_DIP, 8f,
getResources().getDisplayMetrics()));
mPaint.setColor(Color.parseColor(&#999999&));
float textWidth = mPaint.measureText(&09:30&);
canvas.drawText(&09:30&, item * 10, -mPaint.getFontMetrics().top + item * 380, mPaint);
canvas.drawText(&11:30&, viewWidth / 2.0f - textWidth / 2.0f, -mPaint.getFontMetrics()
.top + item * 380, mPaint);
canvas.drawText(&15:00&, viewWidth - textWidth - item * 10, -mPaint.getFontMetrics().top
+ item * 380, mPaint);
绘制折线,以及折线的阴影面积.
转到canvas上来说,其实就是绘制路径,在前面绘制横线的时候,绘制虚线其实就是绘制路径.
注意绘制阴影的时候,要把画笔设置为实心的,这样才会有阴影的效果,同时路径path要多连接几个点,包括右下角,左下角,表明折线下方,第五条横线上方,就是阴影部分.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int viewHeight = getHeight();
int viewWidth = getWidth();
float item = viewHeight / 410f;
drawBrokenLine(canvas, viewWidth, item, &#504F76DB&, Paint.Style.FILL);
drawBrokenLine(canvas, viewWidth, item, &#4F76DB&, Paint.Style.STROKE);
viewWidth view's width
the view's height divided into 410
paint color
paint style,FILL: draw shadow, STROKE:draw line
private void drawBrokenLine(Canvas canvas, int viewWidth, float item, String color, Paint
.Style style) {
Path path = new Path();
Paint paint = new Paint();
float xItem = viewWidth / 2.0f / 120f;
float yCount = maxPrice - baseData & baseData - minPrice ? maxPrice - baseData : baseData
float yItem = 330 * item / yCount / 2.0f;
path.moveTo(0, item * 195);
for (int i = 0; i & times.size(); i++) {
path.lineTo(xItem * (i + 1), item * 195 + yItem * (baseData - prices.get(i)));
if (Paint.Style.FILL == style) {
path.lineTo(viewWidth, item * 380);
path.lineTo(0, item * 380);
path.lineTo(0, item * 195);
path.close();
paint.setStrokeWidth(2f);
paint.setColor(Color.parseColor(color));
paint.setAntiAlias(true);
paint.setStyle(style);
canvas.drawPath(path, paint);
绘制最高点,最低点,以及百分比.
有了绘制时间的经验,我们知道x,y分别代表的是文字的左下角,baseline,直接绘制即可.
绘制最低点的时候需要注意,最低点距离第四条横线的距离,应该与第二条线距离最高点的距离一致.放大雪球股票的图,发现其K线图,以及后面要绘制的蜡烛图,这
两个距离都不相等,虽然无伤大雅.但是如果我们能做到,那就更好不过.
凯哥live中说到,设计或者产品出来一个交互,一个需求,你做不到,没什么关系,因为别人也做不到.但是假设别人做不到,但是你做到了,那么很明显,你就强于别人
在前面绘制文字的时候提到过这篇文章,发布到郭霖的公众号后,有部分同学说,为什么这么麻烦搞这么多,感觉不需要这么复杂.
实际上如果只是单纯做一个需求,确实不需要多复杂的代码,直接绘制是最简单的,但是绘制也涉及到留白的问题,在一个要求不是特别精确的View,一两个像素的差距,确实可有可无,甚至有同学直接根据
实际运行出来的效果图,调整空白大小.
但是你为什么调整空白大小,为什么要这么调,调了以后其他的机型适配吗?如果在一个很大的View上,字体大小很大,此时能保证也能满足正常视觉吗?
故有时候追求一些细节,对自己的代码,以及技术,都是一种负责任的态度.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int viewHeight = getHeight();
int viewWidth = getWidth();
float item = viewHeight / 410f;
drawPriceAndPercent(canvas, viewWidth, item);
viewWidth view's width
the view's height divided into 410
private void drawPriceAndPercent(Canvas canvas, int viewWidth, float item) {
float yCount = maxPrice - baseData & baseData - minPrice ? maxPrice - baseData : baseData
mPaint.setStrokeWidth(2f);
mPaint.setColor(Color.RED);
canvas.drawText(yCount + baseData + &&, item * 10, -mPaint.getFontMetrics().top + item *
30, mPaint);
String percentStr = formatPrice(yCount * 100 / baseData) + &%&;
float textWidth = mPaint.measureText(percentStr);
canvas.drawText(percentStr, viewWidth - textWidth - item * 10, -mPaint.getFontMetrics()
.top + item * 30, mPaint);
mPaint.setColor(Color.parseColor(&#008000&));
canvas.drawText(baseData - yCount + &&, item * 10, item * 360 - (mPaint.getFontMetrics()
.descent - mPaint.getFontMetrics().ascent - mPaint.getTextSize() + mPaint
.getFontMetrics().ascent - mPaint.getFontMetrics().top), mPaint);
percentStr = &-& + percentS
textWidth = mPaint.measureText(percentStr);
canvas.drawText(percentStr, viewWidth - textWidth - item * 10, item * 360 - (mPaint
.getFontMetrics().descent - mPaint.getFontMetrics().ascent -
mPaint.getTextSize() + mPaint.getFontMetrics().ascent - mPaint.getFontMetrics()
.top), mPaint);
至此,绘制基本已经结束了,直接运行,就能看到一个基本K线图,但是还差K线图的交互,也就是长按K线图的交互,这其实就是一个触摸反馈的过程
网上有很多的触摸文章教程,这里就不展开篇幅讲解了,这里直接使用手势识别类:GestureDetector
但是实际使用发现,假设手指长按了,就不能再接收到
手指的移动事件,看GestureDetector发现,如果它判断是长按就直接break了,同时发现它也没有发送手指离开屏幕的事件,这都不是我想要的,所以我就把它源码直接复制出来了,删掉了一些用不到的事件,并
添加了手指离开事件.第二个手指按下,离开事件.
boolean onDown2(MotionEvent e);
boolean onUp2(MotionEvent e);
boolean onUp(MotionEvent e);
更多详情,请点击这个改造过的
添加手势触摸监听,首先在init初始化GestureDetector,并在onTouch中拦截触摸事件
private void init() {
detector = new GestureDetector(getContext(), new GestureDetector.OnGestureListener() {
public void onLongPress(MotionEvent e) {
showTouchLine(e.getRawX());
Log.e(&onLongPress&, getActionName(e));
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float
distanceY) {
Log.e(&onScroll&, getActionName(e2) + &
Y: & + distanceY + &
e2: & + e2.getRawY
if (e2.getAction() == MotionEvent.ACTION_MOVE && longPressFlag) {
showTouchLine(e2.getRawX());
return true;
public boolean onDown2(MotionEvent e) {
return false;
public boolean onUp2(MotionEvent e) {
return false;
public boolean onUp(MotionEvent e) {
Log.e(&onUp&, getActionName(e));
hideTouchLine();
return true;
public boolean onDown(MotionEvent e) {
return true;
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float
velocityY) {
return true;
public boolean onSingleTapUp(MotionEvent e) {
Log.e(&onSingleTapUp&, getActionName(e));
return true;
public void onShowPress(MotionEvent e) {
public boolean onTouchEvent(MotionEvent event) {
return detector.onTouchEvent(event);
private void hideTouchLine() {
touchIndex = -1;
longPressFlag = false;
if (touchMoveListener != null) {
touchMoveListener.change(&&, &&, &&, &&);
postInvalidate();
private void showTouchLine(float touchX) {
longPressFlag = true;
float itemX = (float) getWidth() / prices.size();
for (int i = 1; i &= prices.size(); i++) {
if (itemX * i &= touchX) {
touchIndex = i - 1;
postInvalidate();
if (touchMoveListener != null && touchIndex &= 0) {
touchMoveListener.change(times.get(touchIndex), prices.get(touchIndex) + &&,
formatPrice((prices.get(touchIndex) - baseData) / baseData * 100) + &%&,
&4613.93万&);
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int viewHeight = getHeight();
int viewWidth = getWidth();
float item = viewHeight / 410f;
drawTouchLines(canvas, viewWidth, item);
viewWidth view's width
the view's height divided into 410
private void drawTouchLines(Canvas canvas, int viewWidth, float item) {
if (longPressFlag) {
float yCount = maxPrice - baseData & baseData - minPrice ? maxPrice - baseData :
baseData - minP
float xItem = viewWidth / 2.0f / 120f;
float yItem = 330 * item / yCount / 2.0f;
float x = xItem * (touchIndex + 1);
float y = item * 195 + yItem * (baseData - prices.get(touchIndex));
mPaint.setColor(Color.parseColor(&#999999&));
canvas.drawLine(0, y, viewWidth, y, mPaint);
canvas.drawLine(x, item * 10, x, item * 380, mPaint);
mPaint.setColor(Color.parseColor(&#FFC125&));
mPaint.setStrokeWidth(10f);
canvas.drawPoint(x, y, mPaint);
分时图总结
至此,分时图的布局,绘制,触摸反馈都已经完整,如果再加上设置数据的方法,就可以作为一个基本的分时图使用了.
详细代码请点击:
第1层:横竖刻度线第2层:股票点,时间第3层:蜡烛,以及MA线(MA其实就是绘制折线,这个Demo中没有绘制)
蜡烛图的结构相对复杂,首先是,数据是从右往左的呈现的,最右边是最新的数据,越往左时间越久.
其次,蜡烛图没有昨天收盘的时候的股票点,也就是它没有基准线,它的涨跌情况都是与前一天对比.所有它的刻度范围是不固定的,需要根据
当前呈现的数据,动态计算它的最高点和最低点
创建类,并初始化,并构建测试数据方便调试
public class CandleView extends View {
public CandleView(Context context) {
super(context);
public CandleView(Context context, AttributeSet attrs) {
super(context, attrs);
public CandleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CandleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
private void init() {
candles = new ArrayList&&();
mPaint = new Paint();
createTestData();
private void createTestData() {
Date date = new Date();
@SuppressLint(&SimpleDateFormat&) SimpleDateFormat dateFormat = new SimpleDateFormat
(&yyyy-MM-dd HH:mm:ss&);
Float todayStart = 3150.10f;
for (int i = 0; i & 1200; i++) {
Candle candle = new Candle();
date.setTime(date.getTime() - 24L * 60L * 60L * 1000L);
candle.time = formatTime(dateFormat.format(date));
candle.time = dateFormat.format(date);
if (i == 0) candle.start = todayS
candle.start = formatPrice((float) (candles.get(i - 1).end + 100 - Math.random()
candle.end = formatPrice((float) (candle.start + candle.start * 0.05 - Math.random()
* candle.start * 0.1));
float tmp = formatPrice((float) (candle.start * 0.05 - Math.random() * candle.start *
candle.max = formatPrice(candle.start + (tmp & 0 ? 0 : tmp));
tmp = formatPrice((float) (candle.start * 0.05 - Math.random() * candle.start * 0.1));
candle.min = formatPrice(candle.start + (tmp & 0 ? 0 : tmp));
candles.add(candle);
for (int i = 0; i & candles.size(); i++) {
float total = 0f;
if (i & candles.size() - 5) {
for (int j = j & i + 5; j++) {
total += candles.get(j).
candles.get(i).ma5 = total / 5;
candles.get(i).ma5 = candles.get(i).
total = 0f;
if (i & candles.size() - 10) {
for (int j = j & i + 10; j++) {
total += candles.get(j).
candles.get(i).ma10 = total / 10;
candles.get(i).ma10 = candles.get(i).
total = 0f;
if (i & candles.size() - 20) {
for (int j = j & i + 20; j++) {
total += candles.get(j).
candles.get(i).ma20 = total / 20;
candles.get(i).ma20 = candles.get(i).
绘制横竖线,并绘制刻度,时间
蜡烛图的高度与分时图一致,总体高度410,第1条线距离顶部是10,View可绘制高度是370.
在绘制刻度之前,要先计算出当前展示的数据的最小值,最大值,以及刻度的比例,才能根据比例来绘制刻度.
private void getYData() {
maxPrice = 0;
minPrice = Float.MAX_VALUE;
for (int i = startI i & startIndex + i++) {
if (candles.get(i).start & maxPrice) maxPrice = candles.get(i).
if (candles.get(i).start & minPrice) minPrice = candles.get(i).
if (candles.get(i).end & maxPrice) maxPrice = candles.get(i).
if (candles.get(i).end & minPrice) minPrice = candles.get(i).
if (candles.get(i).max & maxPrice) maxPrice = candles.get(i).
if (candles.get(i).max & minPrice) minPrice = candles.get(i).
if (candles.get(i).min & maxPrice) maxPrice = candles.get(i).
if (candles.get(i).min & minPrice) minPrice = candles.get(i).
yScale = 1;
int diff = (int) (maxPrice - minPrice);
if (diff / 100000 &= 1) {
yScale = 100000;
minY = (int) minPrice / 100000 * 100000;
maxY = ((int) maxPrice / 100000 + 1) * 100000;
} else if (diff / 10000 &= 1) {
yScale = 10000;
minY = (int) minPrice / 10000 * 10000;
maxY = ((int) maxPrice / 10000 + 1) * 10000;
} else if (diff / 1000 &= 1) {
yScale = 1000;
minY = (int) minPrice / 1000 * 1000;
maxY = ((int) maxPrice / 1000 + 1) * 1000;
} else if (diff / 100 &= 1) {
yScale = 100;
minY = (int) minPrice / 100 * 100;
maxY = ((int) maxPrice / 100 + 1) * 100;
} else if (diff / 10 &= 1) {
yScale = 10;
minY = (int) minPrice / 10 * 10;
maxY = ((int) maxPrice / 10 + 1) * 10;
Log.e(&siyehua&, maxPrice + &
& + minPrice + &
& + maxY + &
& + minY + &
yScale + &
计算好Y轴刻度后,则开始绘制
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int viewHeight = getHeight();
int viewWidth = getWidth();
float itemW = (float) viewWidth /
float itemH = viewHeight / 410f;
drawLinesAndText(canvas, viewWidth, viewHeight, itemW, itemH);
the view's width
viewHeight the view's height
the view's wight divided into count
the view's height divided into 410
private void drawLinesAndText(Canvas canvas, int viewWidth, int viewHeight, float itemW,
float itemH) {
mPaint.setColor(Color.parseColor(&#AAAAAA&));
mPaint.setStrokeWidth(0f);
mPaint.setTextSize(TypedValue.PLEX_UNIT_DIP, 8f,
getResources().getDisplayMetrics()));
getYData();
int lineCount = (maxY - minY) / yS
if (lineCount & 5) {
yScale *= 2;
lineCount = (maxY - minY) / yS
canvas.drawLine(0, itemH * 10, viewWidth, itemH * 10, mPaint);
float percent = 370 / (float) lineC
for (int i = 1; i & lineC i++) {
String content = minY + (lineCount - i) * yScale + &&;
canvas.drawText(content, itemH * 10, itemH * (10 + percent * i) - mPaint
.getFontMetrics().bottom, mPaint);
canvas.drawLine(0, itemH * (10 + percent * i), viewWidth, itemH * (10 + percent * i),
canvas.drawLine(0, itemH * 380, viewWidth, itemH * 380, mPaint);
String tmpMonth = candles.get(startIndex).time.substring(5, 7);
for (int i = startIndex + 1; i & startIndex + i++) {
if (!tmpMonth.equals(candles.get(i + 1).time.substring(5, 7))) {
tmpMonth = candles.get(i + 1).time.substring(5, 7);
String timeStr = candles.get(i).time.substring(0, 7);
float tmp = itemW * (count + startIndex - i) - itemW / 2;
float timeWidth = mPaint.measureText(timeStr);
canvas.drawText(timeStr, tmp - timeWidth / 2, itemH * 380 + -mPaint
.getFontMetrics().top, mPaint);
canvas.drawLine(tmp, itemH * 10, tmp, itemH * 380, mPaint);
绘制好线与文字,就可以绘制蜡烛了.蜡烛图在View的视觉上占了很大的份量,但是绘制的时候,实际上很简单,当刻度计算好后,只需要绘制一条线,以及一个实心的矩形即可.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int viewHeight = getHeight();
int viewWidth = getWidth();
float itemW = (float) viewWidth /
float itemH = viewHeight / 410f;
drawCandles(canvas, viewWidth, viewHeight, itemW, itemH);
the view's width
viewHeight the view's height
the view's wight divided into count
the view's height divided into 410
private void drawCandles(Canvas canvas, int viewWidth, int viewHeight, float itemW, float
mPaint.setStrokeWidth(2f);
mPaint.setStyle(Paint.Style.FILL);
String tmpMonth = candles.get(startIndex).time.substring(5, 7);
for (int i = startI i & startIndex + i++) {
if (candles.get(i).end & candles.get(i + 1).end) {
mPaint.setColor(Color.RED);
} else mPaint.setColor(Color.GREEN);
float left, top, right,
float tmp = itemW * (count + startIndex - i) - itemW / 2;
top = ((maxY - candles.get(i).max) / (maxY - minY) * 370 + 10) * itemH;
bottom = ((maxY - candles.get(i).min) / (maxY - minY) * 370 + 10) * itemH;
if (top & bottom) {
canvas.drawLine(left, top, right, bottom, mPaint);
left = itemW * (count - 1 + startIndex - i) + 2f;
top = ((maxY - candles.get(i).start) / (maxY - minY) * 370 + 10) * itemH;
right = itemW * (count + startIndex - i) - 2f;
bottom = ((maxY - candles.get(i).end) / (maxY - minY) * 370 + 10) * itemH;
if (top & bottom) {
canvas.drawRect(left, top, right, bottom, mPaint);
绘制其他元素
雪球股票的蜡烛图,还有三条折线,以及左上角的文字提示.这些在分时图已经讲解了如何绘制了,只需要依样画葫芦即可.
因为蜡烛图的复杂不在于它的绘制,而在于它的触摸反馈,所以这里把更多的精力花在触摸反馈的处理上.
初始化触摸类
private void init() {
detector = new GestureDetector(getContext(), new GestureDetector.OnGestureListener() {
public boolean onDown2(MotionEvent e) {
Log.e(&onDown2&, e.getX(1) + &&);
flag1 = flag2 = false;
down2X = e.getX(1);
return true;
public boolean onUp2(MotionEvent e) {
flag2 = true;
if (flag1) type = 1;
return true;
public boolean onUp(MotionEvent e) {
if (type == 2) {
flag1 = true;
if (flag2) type = 1;
} else hideTouchLine();
return true;
public boolean onDown(MotionEvent e) {
Log.e(&onDown&, e.getRawX() + &&);
downIndex = startI
downX = e.getX(0);
return true;
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float
distanceY) {
if (refreshFlag) {
refreshFlag = false;
handler.sendEmptyMessageDelayed(10086, 15);
if (type == 1) {
showTouchLine(e2.getRawX());
if (e2.getPointerCount() &= 2) {
float moveDistance = Math.abs(e2.getX(0) - e2.getX(1)) - Math.abs
(downX - down2X);
Log.e(&onScroll&, Math.abs(e2.getX(0) - e2.getX(1)) + &
& + Math
.abs(downX - down2X) + &
& + moveDistance + &
& + getWidth()
scaleCandle(moveDistance);
return true;
public void onLongPress(MotionEvent e) {
if (type == 1) {
longPressFlag = true;
showTouchLine(e.getRawX());
public boolean onSingleTapUp(MotionEvent e) {
return true;
public void onShowPress(MotionEvent e) {
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float
velocityY) {
return true;
public boolean onTouchEvent(MotionEvent event) {
return detector.onTouchEvent(event);
单根手指触摸
private void showTouchLine(float touchX) {
float itemX = (float) getWidth() /
if (longPressFlag) {
for (int i = 1; i &= i++) {
if (itemX * i &= touchX) {
touchIndex = i + 1;
if (touchMoveListener != null && touchIndex &= 0) {
touchMoveListener.change(candles.get(count + startIndex - touchIndex).time
.substring(0, 10), candles.get(count + startIndex - touchIndex).end + &&,
formatPrice((candles.get(count + startIndex - touchIndex).end - candles
.get(count + startIndex - touchIndex + 1).end) / candles.get
(count + startIndex - touchIndex + 1).end * 100) + &%&, &4613& +
int number = (int) ((touchX - downX) / itemX);
startIndex = downIndex +
if (startIndex & 0) startIndex = 0;
if (startIndex & candles.size() - count - 1) startIndex = candles.size() - count - 1;
postInvalidate();
the view's width
viewHeight the view's height
the view's wight divided into count
the view's height divided into 410
private void drawTouchLines(Canvas canvas, int viewWidth, int viewHeight, float itemW, float
if (longPressFlag) {
float x = itemW * touchIndex - itemW / 2;
float a = ((maxY - candles.get(count + startIndex - touchIndex).start) / (maxY -
minY) * 370 + 10) * itemH;
float b = ((maxY - candles.get(count + startIndex - touchIndex).end) / (maxY - minY)
* 370 + 10) * itemH;
if (candles.get(count + startIndex - touchIndex).end & candles.get(count + startIndex
- touchIndex + 1).end) {
y = a & b ? a :
} else y = a & b ? a :
mPaint.setColor(Color.parseColor(&#999999&));
canvas.drawLine(0, y, viewWidth, y, mPaint);
canvas.drawLine(x, itemH * 10, x, itemH * 380, mPaint);
多根手指缩放
屏幕默认分为60根蜡烛,缩放后,只需要修改默认的蜡烛数目即可.
private void scaleCandle(float moveDistance) {
if (moveDistance & getWidth() / 30) {
if (count == 20) count = 10;
else if (count == 10) return;
else count -= 20;
} else if (moveDistance & -getWidth() / 30) {
if (count == 240) return;
else count += 20;
postInvalidate();
蜡烛图总结
蜡烛图的需求,功能基本上已经实现,除了三条折线没有绘制.只需要再添加设置数据方法,该类便可直接使用.
本文从布局,绘制,触摸,三个方面讲解了分时图,蜡烛图的一步步实现过程.其实股票图的业务上还有很多是没有讲解到的,例如大家应该都有注意到截图中
下面有柱状图,其实这个应该也是图的一部分,还有一些高亮显示等问题.
但其实基本的原理都是不变的,一个View的三个方面都有详细的讲解到,涉及到更多业务逻辑,无非也就是在这个基础上,绘制自己业务想要的效果,万变不离其宗,只要掌握好方法,再复杂的图也信手捏来.
之所以要画这两个图,是因为之前有人问博主有没有别人写好的能直接用的股票图,搜了好久没发现有比较成熟的Android股票图绘制,有的都必须在项目的基础上改造,而且BUG也比较多
最后在CSDN看了一个教程,
这个教程的绘制是依赖另外一库的基础上改造的,而且也不是很成熟.作者花了大量的篇幅,主要问题并不是教大家如何绘制,而是教大家如何处理绘制股票图中遇到的一些问题,
例如数组越界了等一些实质性的问题,最后还把这个系列商用了.如果大家在股票图的应用中遇到了一下问题,也可以参考这个系列的教程
就目前来讲,Android暂时还没有一个较为成熟的股票图项目可以依赖,而使用半成熟的项目,本身就会遇到许多bug,与其花精力去修改别人的bug,不如自己编写一个.
博主本人公司并没有涉及到股票图的绘制,个人对股票也不是很熟悉,以上所有的讲解都是个人理解,难免会有错误,欢迎大家留言交流指正.
Copyright 2017 siyehua
Licensed under the Apache License, Version 2.0 (the &License&);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an &AS IS& BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:76206次
积分:1931
积分:1931
排名:第19387名
原创:53篇
转载:339篇
评论:26条
(73)(61)(47)(89)(25)(34)(24)(26)(17)(4)

我要回帖

更多关于 股票通道线的画法 的文章

 

随机推荐