基于JFreeChart的股票交易K线图停牌日期缺口优化完整解决方案

 JFreeChart绘制K线图停牌日期缺口优化

摘要 这是在绘制股票交易K线图时遇到的一个问题,有关问题的优化方案,与一些具体的实现

方法,以及在这个过程中的心得。

关键词JFreeChartSegmentTimeline 

问题

在绘制股票交易K线图时,遇到如何去除停牌日期的交易数据问题。此问题涉及到两个方面,

周六周日股票停牌无交易日期和特殊假日股票停牌无交易日期。对于周末这个固定的休息日,股 

票是不存在交易数据的,即停牌,在K线图上显示的话就是空白。同样,对于特殊的时间节点

也不存在交易数据,在K线图上也是空白。因此在绘制K线图时,为了保证数据显示的连续性

和美化视角,我们要将这些特殊的日期的横轴坐标从原数据坐标中去掉,或者说隐藏不显示。 

现状分析

在设置K线图的X轴时间线性集合时没有将异常交易日期(即停牌缺口)从时间线性集合

中去除掉。要想实现停牌日期缺口优化,就要设法将缺口日期从时间线性集合去除或使该缺口日 

期隐藏不显示,从而达到K线图的连续不间断,便于统计分析。 

意义 

主要是对停牌日期缺口进行异常处理,以去除掉无交易的日期,保证X轴时间上的连续 

性(有交易),使K线图显示数据变化是连续不间断的,有利于数据分析。

基于JFreeChart的股票交易K线图停牌日期缺口优化完整解决方案_第1张图片

要将停牌缺口从时间线性集合中去除掉,必须涉及到下列相关对象、属性和方法的应用:

SegmentTimeline: 时间线性集合对象,包含已定义的交易时间轴的下限和上限

timeline.setStartTime(SegmentedTimeline.FIRST_MONDAY_AFTER_1900);//设置

时间线起点为1900年(一定要设置起始年份,否则时间轴没有基点,会错乱)

addException(Date date):从已定义的时间轴范围内,去除参数指定日期函数 

DateAxis:时间线性X轴对象

x1Axis.setAutoRange(false);//设置不采用自动设置时间范围

x1Axis.setRange(date1,date2);//设置时间范围 

x1Axis.setTimeline(timeline);//设置X轴时间线性集合 

x1Axis.setAutoTickUnitSelection(false);//设置不采用自动选择刻度值 

    x1Axis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);//设置标记的位置

x1Axis.setStandardTickUnits(DateAxis.createStandardDateTickUnits());//

置标准的时间刻度单位

    x1Axis.setTickUnit(newDateTickUnit(DateTickUnit.DAY,1));//设置时间刻度的

间隔,这里以天为单位 

   x1Axis.setDateFormatOverride(newSimpleDateFormat("yyyy-MM-dd"));//设置

显示时间的格式

   x1DateAxis.setVerticalTickLabels(true);//设置X轴时间标记是否垂直显示

上述是在设置X轴时间线性显示时涉及到的相关对象,设置好相关对象的属性值,就可以

将交易停牌缺口从K线图中去除,从而使得K线图保持连续性且美观。 

思路分析

思路一

第一步:首先应用SegmentTimeline类默认的去除周末日期缺口的函数来构造SegmentTimeline 

对象,即SegmentedTimeline.newMondayThroughFridayTimeline() 

第二步:进一步从去除周末缺口的时间线性集合中出去特殊无交易日期缺口。 

思路二 

SegmentTimeline时间线性集合对象的Calendar(日历对象)进行重新定义,即对时间 

日历对象的time属性进行赋值(calendar.setTime(Date date);),当然date的取值来自数据

源提供的和SegmentTimeline对象的Date相匹配的date属性值,如果不匹配,调用 

SegmentTimeline对象的addException(Date date)方法将其保存在exceptionSegments集合中

且设置该日期对应的无交易时间刻度在X轴显示时隐藏起来,并从Calendar对象去除该日期对 

应的时间,从而实 

现缺口优化。 

解决过程 

分两步:第一步,首先重载SegmentTimeline类的方法,调用默认的构造函数,以去除周

六日这些有周期的日期缺口;第二部,在前一步的基础上,再判断某个某个日期(特殊日期)是

否有交易,有则绘制交易数据,无则隐藏此数据交易不现实。从而达到K线图的数据连续性。 

DateAxisx1Axis=new DateAxis();//设置x轴,也就是时间轴 

x1Axis.setAutoRange(false);//设置不采用自动设置时间范围

x1Axis.setRange(dateFormat.parse("2007-08-20"),dateFormat.parse("2007-10-11 

"));//设置时间范围,注意时间的最大值要比已有的时间最大值要多一天 

//x1Axis.setTimeline(SegmentedTimeline.newMondayThroughFridayTimeline()); 

置时间线显示的规则,用这个方法就摒除掉了周六和周日这些没有交易的日期(很多人都不知道 

有此方法),使图形看上去连续 

Mapmap = new HashMap();//将有交易的日期以键值对的形

式存放到Map集合中(后面要用来验证时间是否匹配) 

for(intindex = 0;index <series.getItemCount();index++) {

  RegularTimePeriodperiod =series.getPeriod(index);

  Stringss =new SimpleDateFormat("yyyy-MM-dd").format(period.getStart());

  map.put(ss,period.getStart()); 

} 

//自定义时间线性集合,作为X轴显示的时间集合(匿名内部类调用其父类的方法) 

SegmentedTimelinetimeline = new

SegmentedTimeline(SegmentedTimeline.DAY_SEGMENT_SIZE, 5, 2){ 

       publicboolean containsDomainValue(Datedate) { 

         StringstringDate =date.toString();

         System.out.println(date); 

         String key=new SimpleDateFormat("yyyy-MM-dd").format(date);

         Date d=map.get(key);

         if(d ==null) {//判断当前日期是否存在交易

            this.addException(date);//不存在交易即为异常日期,添加到异常日期 

集合中,并在Calendar对象中去除该时间

         }

         returnsuper.containsDomainValue(date);//判断当前日期是否包含在 

SegmentTimeline的日期集合中 

        }

       }; 

timeline.setStartTime(SegmentedTimeline.FIRST_MONDAY_AFTER_1900); 

x1Axis.setTimeline(timeline);//设置X轴时间线性集合

x1Axis.setAutoTickUnitSelection(false);//设置不采用自动选择刻度值

x1Axis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);//设置标记的位置 

x1Axis.setStandardTickUnits(DateAxis.createStandardDateTickUnits());//设置标 

准的时间刻度单位 

x1Axis.setTickUnit(newDateTickUnit(DateTickUnit.DAY,1));//设置标准的时间刻

度间隔单位(此处以一天为例则是1,如果以一周为例则是7

x1Axis.setDateFormatOverride(newSimpleDateFormat("yyyy-MM-dd"));//设置显示时间的格式 

NumberAxisy1Axis=new NumberAxis();//设定y轴,就是数字轴 

y1Axis.setAutoRange(false);//设置是否采用自动设置Y轴数值范围

y1Axis.setRange(minValue*0.9,highValue*1.1);//设定y轴值的范围,比最大值要大一些, 

这样图形看起来会美观些

y1Axis.setTickUnit(newNumberTickUnit((highValue*1.1-minValue*0.9)/10));//设置刻度

显示的密度

XYPlotplot1=new XYPlot(seriesCollection,x1Axis,y1Axis,candlestickRender);//设置画图区域对象

CombinedDomainXYPlotcombineddomainxyplot =new

CombinedDomainXYPlot(x1Axis);//建立一个联合图形区域对象,以x轴为共享轴

combineddomainxyplot.add(plot1);

combineddomainxyplot.add(plot1);//添加图形区域对象,后面的数字(如果有数字)是计算这个区域对象应该占据多大的区域2/3

JFreeChartchart =newJFreeChart("xx公司股票", JFreeChart.DEFAULT_TITLE_FONT,combineddomainxyplot,false);

ChartFrameframe =newChartFrame("xx公司xx股票",chart);

frame.pack();

frame.setVisible(true);

 

解决后的效果图

基于JFreeChart的股票交易K线图停牌日期缺口优化完整解决方案_第2张图片

 

总结

    addException(Date date)函数的具体实现步骤过程中涉及到如下图所示的相关函数的实现:

  1. 调用异常日期保存方法将date保存在list集合中,并从SegmentTimeline中对当前异常时间线段进行截取标记(即将这一段从SegmentTime中去除掉)后面再次验证时就不会存在该日期的段。

  2. addException()函数中调用inIncludeSegments()是验证date是否包含在周一至周五(这个时间段)。包含的话就调binarySearchExceptionSegments(Segmentsegment)方法返回一 int类型的值,用来作为add(index ,segement)index值。 

  3. 对当前的segment对象进行是否属于验证(调用inExceptionSegments()函数验证其是否是异 常段),通过验证就说明segmentTimeline中包含该时间段,对应的坐标标记和数据可以显示。

  4. 验证segment是否包含在exceptionSegments集合中,同时为在addException()时的index 引赋值 。

  5. K线图对于不包含在SegmentTimeline时间线性集合中日期进行隐藏设置,使其不显示在X轴上。super.containsDomainValue(date);里调inIncludeSegments()验证是否是工作日;是工作日在进一步验证是否是异常集合中的元素,是的话,设置X轴时间标记标签时执行回滚操作(rollDate())。

  6. 执行回滚时是刻度单位(DateTickUnit)对象执行回滚操作(rollDate()),进而得到有效的标 记标签的文本值和对应的x变量值。 

  7. 设置时间线段时使date在起始日期的基础上以天为单位进行叠加,直至达到时间线段的上 限值(upperDate)。 

    isHiddenValue(long millis)返回true时,TickUnit(时间刻度单位)对象调rollDate()方法将Calendar对象的日期按卷单元指定的数量(2天)滚动日期(如当前日期为2017-04-30,下一个日期2017-05-01无交易,需要跳过,即下一个日期应该为2017-05-02,此处调用calendar.add(intFiled , count)函数后,日期会设置为2007-05-02);

     当返回false时,TickUnit调用addToDate()方法对date进行“1天”时间线段的设置。


    rollDate()addToDate()这两个函数是在绘制X轴的timelineLabel标记标签时用到的函 数,目的是在segmentTimeline中将异常日期的标签按指定单位和数量回滚过去,以达到在X 轴不显示缺口标签的目的。

     

    addException()则是通过添加exceptionSegments集合元素来验证segmentTimeline中的 段(缺口)是否是异常段,异常就会在绘制X轴标记标签时进行回滚。



你可能感兴趣的:(基于JFreeChart的股票交易K线图停牌日期缺口优化完整解决方案)