設為首頁收藏本站

艾歐踢論壇

 找回密碼
 立即註冊

QQ登錄

只需一步,快速開始

搜索
熱搜: 活動 交友 discuz

利用JFreeChart繪制股票K線圖完整解决方案

已有 2514 次閱讀2015-1-18 02:18 |個人分類:java| 解决方案

在進行源代碼講解之前,有必要將本人所領悟到的一些關於jfreechart的概念講述下,jfreechart工具基本上把一個圖形分成了幾個邏輯部分。 

      1.首先是整個的畫布對象(chart),畫布就相當與一個大的容器,包含一些圖形元素,比如为一張白紙 
      2.然後是畫圖區域對象(plot),就是實際圖形所占據的區域,比如为白紙上的一個長方形 
      3.然後是圖形所需要兩條軸對象(axis),比如为白紙上的兩條軸線 
      4.最後是如何進行圖像的繪制對象(render),比如为一只畫圖的筆 
      5.除開上面的這些對象,還有一個最主要的就是通過必須的數據集(dataset)來生成圖形了 
至於一些具體的對象細節,就只好請各位去閱讀相關的API文檔了,在這裏就不詳細的說明 
package chart; 
import java.awt.Color;//顏色系統 
import java.text.SimpleDateFormat;//時間格式 
import java.awt.Paint;//畫筆系統 
import org.jfree.data.time.*; 
import org.jfree.data.time.Day; 
import org.jfree.data.time.ohlc.OHLCSeries; 
import org.jfree.data.time.ohlc.OHLCSeriesCollection; 
import org.jfree.chart.renderer.xy.*; 
import org.jfree.chart.axis.*; 
import org.jfree.chart.plot.*; 
import org.jfree.chart.*; 

public class KLineCombineChart { 

public static void main(String[] args) { 
     SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");//設置日期格式 
     double highValue = Double.MIN_VALUE;//設置K線數據當中的最大值 
     double minValue = Double.MAX_VALUE;//設置K線數據當中的最小值 
     double high2Value = Double.MIN_VALUE;//設置成交量的最大值 
     double min2Value = Double.MAX_VALUE;//設置成交量的最低值 
     OHLCSeries series = new OHLCSeries("");//高開低收數據序列,股票K線圖的四個數據,依次是開,高,低,收 
     series.add(new Day(28, 9, 2007), 9.2, 9.58, 9.16, 9.34); 
     series.add(new Day(27, 9, 2007), 8.9, 9.06, 8.83, 8.96); 
     series.add(new Day(26, 9, 2007), 9.0, 9.1, 8.82, 9.04); 
     series.add(new Day(25, 9, 2007), 9.25, 9.33, 8.88, 9.00); 
     series.add(new Day(24, 9, 2007), 9.05, 9.50, 8.91, 9.25); 
     series.add(new Day(21, 9, 2007), 8.68, 9.05, 8.40, 9.00); 
     series.add(new Day(20, 9, 2007), 8.68, 8.95, 8.50, 8.69); 
     series.add(new Day(19, 9, 2007), 8.80, 8.94, 8.50, 8.66); 
     series.add(new Day(18, 9, 2007), 8.88, 9.17, 8.69, 8.80); 
     series.add(new Day(17, 9, 2007), 8.26, 8.98, 8.15, 8.89); 
     series.add(new Day(14, 9, 2007), 8.44, 8.45, 8.13, 8.33); 
     series.add(new Day(13, 9, 2007), 8.13, 8.46, 7.97, 8.42); 
     series.add(new Day(12, 9, 2007), 8.2, 8.4, 7.81, 8.13); 
     series.add(new Day(11, 9, 2007), 9.0, 9.0, 8.1, 8.24); 
     series.add(new Day(10, 9, 2007), 8.6, 9.03, 8.40, 8.95); 
     series.add(new Day(7, 9, 2007), 8.89, 9.04, 8.70, 8.73); 
     series.add(new Day(6, 9, 2007), 8.4, 9.08, 8.33, 8.88); 
     series.add(new Day(5, 9, 2007), 8.2, 8.74, 8.17, 8.36); 
     series.add(new Day(4, 9, 2007), 7.7, 8.46, 7.67, 8.27); 
     series.add(new Day(3, 9, 2007), 7.5, 7.8, 7.48, 7.69); 
     series.add(new Day(31, 8, 2007), 7.4, 7.6, 7.28, 7.43); 
     series.add(new Day(30, 8, 2007), 7.42, 7.56, 7.31, 7.40); 
     series.add(new Day(29, 8, 2007), 7.42, 7.66, 7.22, 7.33); 
     series.add(new Day(28, 8, 2007), 7.31, 7.70, 7.15, 7.56); 
     series.add(new Day(27, 8, 2007), 7.05, 7.46, 7.02, 7.41); 
     series.add(new Day(24, 8, 2007), 7.05, 7.09, 6.90, 6.99); 
     series.add(new Day(23, 8, 2007), 7.12, 7.16, 7.00, 7.03); 
     series.add(new Day(22, 8, 2007), 6.96, 7.15, 6.93, 7.11); 
     series.add(new Day(21, 8, 2007), 7.10, 7.15, 7.02, 7.07); 
     series.add(new Day(20, 8, 2007), 7.02, 7.19, 6.94, 7.14); 
     final OHLCSeriesCollection seriesCollection = new OHLCSeriesCollection();//保留K線數據的數據集,必須申明为final,後面要在匿名內部類裏面用到 
     seriesCollection.addSeries(series); 
     TimeSeries series2=new TimeSeries("");//對應時間成交量數據 
     series2.add(new Day(28, 9, 2007), 260659400/100); 
     series2.add(new Day(27, 9, 2007), 119701900/100); 
     series2.add(new Day(26, 9, 2007), 109719000/100); 
     series2.add(new Day(25, 9, 2007), 178492400/100); 
     series2.add(new Day(24, 9, 2007), 269978500/100); 
     series2.add(new Day(21, 9, 2007), 361042300/100); 
     series2.add(new Day(20, 9, 2007), 173912600/100); 
     series2.add(new Day(19, 9, 2007), 154622600/100); 
     series2.add(new Day(18, 9, 2007), 200661600/100); 
     series2.add(new Day(17, 9, 2007), 312799600/100); 
     series2.add(new Day(14, 9, 2007), 141652900/100); 
     series2.add(new Day(13, 9, 2007), 221260400/100); 
     series2.add(new Day(12, 9, 2007), 274795400/100); 
     series2.add(new Day(11, 9, 2007), 289287300/100); 
     series2.add(new Day(10, 9, 2007), 289063600/100); 
     series2.add(new Day(7, 9, 2007), 351575300/100); 
     series2.add(new Day(6, 9, 2007), 451357300/100); 
     series2.add(new Day(5, 9, 2007), 442421200/100); 
     series2.add(new Day(4, 9, 2007), 671942600/100); 
     series2.add(new Day(3, 9, 2007), 349647800/100); 
     series2.add(new Day(31, 8, 2007), 225339300/100); 
     series2.add(new Day(30, 8, 2007), 160048200/100); 
     series2.add(new Day(29, 8, 2007), 247341700/100); 
     series2.add(new Day(28, 8, 2007), 394975400/100); 
     series2.add(new Day(27, 8, 2007), 475797500/100); 
     series2.add(new Day(24, 8, 2007), 297679500/100); 
     series2.add(new Day(23, 8, 2007), 191760600/100); 
     series2.add(new Day(22, 8, 2007), 232570200/100); 
     series2.add(new Day(21, 8, 2007), 215693200/100); 
     series2.add(new Day(20, 8, 2007), 200287500/100); 
     TimeSeriesCollection timeSeriesCollection=new TimeSeriesCollection();//保留成交量數據的集合 
     timeSeriesCollection.addSeries(series2); 
  
     //獲取K線數據的最高值和最低值 
     int seriesCount = seriesCollection.getSeriesCount();//一共有多少個序列,目前为一個 
     for (int i = 0; i < seriesCount; i++) { 
      int itemCount = seriesCollection.getItemCount(i);//每一個序列有多少個數據項 
      for (int j = 0; j < itemCount; j++) { 
       if (highValue < seriesCollection.getHighValue(i, j)) {//取第i個序列中的第j個數據項的最大值 
        highValue = seriesCollection.getHighValue(i, j); 
       } 
       if (minValue > seriesCollection.getLowValue(i, j)) {//取第i個序列中的第j個數據項的最小值 
        minValue = seriesCollection.getLowValue(i, j); 
       } 
      } 

     } 
     //獲取最高值和最低值 
     int seriesCount2 = timeSeriesCollection.getSeriesCount();//一共有多少個序列,目前为一個 
     for (int i = 0; i < seriesCount2; i++) { 
      int itemCount = timeSeriesCollection.getItemCount(i);//每一個序列有多少個數據項 
      for (int j = 0; j < itemCount; j++) { 
       if (high2Value < timeSeriesCollection.getYValue(i,j)) {//取第i個序列中的第j個數據項的值 
        high2Value = timeSeriesCollection.getYValue(i,j); 
       } 
       if (min2Value > timeSeriesCollection.getYValue(i, j)) {//取第i個序列中的第j個數據項的值 
        min2Value = timeSeriesCollection.getYValue(i, j); 
       } 
      } 

     } 
     final CandlestickRenderer candlestickRender=new CandlestickRenderer();//設置K線圖的畫圖器,必須申明为final,後面要在匿名內部類裏面用到 
     candlestickRender.setUseOutlinePaint(true); //設置是否使用自定義的邊框線,程序自帶的邊框線的顏色不符合中國股票市場的習慣 
     candlestickRender.setAutoWidthMethod(CandlestickRenderer.WIDTHMETHOD_AVERAGE);//設置如何對K線圖的寬度進行設定 
     candlestickRender.setAutoWidthGap(0.001);//設置各個K線圖之間的間隔 
     candlestickRender.setUpPaint(Color.RED);//設置股票上漲的K線圖顏色 
     candlestickRender.setDownPaint(Color.GREEN);//設置股票下跌的K線圖顏色 
     DateAxis x1Axis=new DateAxis();//設置x軸,也就是時間軸 
     x1Axis.setAutoRange(false);//設置不采用自動設置時間範圍 
     try{ 
      x1Axis.setRange(dateFormat.parse("2007-08-20"),dateFormat.parse("2007-09-29"));//設置時間範圍,注意時間的最大值要比已有的時間最大值要多一天 
     }catch(Exception e){ 
      e.printStackTrace(); 
     } 
     x1Axis.setTimeline(SegmentedTimeline.newMondayThroughFridayTimeline());//設置時間線顯示的規則,用這個方法就摒除掉了周六和周日這些沒有交易的日期(很多人都不知道有此方法),使圖形看上去連續 
     x1Axis.setAutoTickUnitSelection(false);//設置不采用自動選擇刻度值 
     x1Axis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);//設置標記的位置 
     x1Axis.setStandardTickUnits(DateAxis.createStandardDateTickUnits());//設置標准的時間刻度單位 
     x1Axis.setTickUnit(new DateTickUnit(DateTickUnit.DAY,7));//設置時間刻度的間隔,一般以周为單位 
     x1Axis.setDateFormatOverride(new SimpleDateFormat("yyyy-MM-dd"));//設置顯示時間的格式 
     NumberAxis y1Axis=new NumberAxis();//設定y軸,就是數字軸 
     y1Axis.setAutoRange(false);//不不使用自動設定範圍 
     y1Axis.setRange(minValue*0.9, highValue*1.1);//設定y軸值的範圍,比最低值要低一些,比最大值要大一些,這样圖形看起來會美觀些 
     y1Axis.setTickUnit(new NumberTickUnit((highValue*1.1-minValue*0.9)/10));//設置刻度顯示的密度 
     XYPlot plot1=new XYPlot(seriesCollection,x1Axis,y1Axis,candlestickRender);//設置畫圖區域對象 
  
     XYBarRenderer xyBarRender=new XYBarRenderer(){ 
     private static final long serialVersionUID = 1L;//为了避免出現警告消息,特設定此值 
     public Paint getItemPaint(int i, int j){//匿名內部類用來處理當日的成交量柱形圖的顏色與K線圖的顏色保持一致 
       if(seriesCollection.getCloseValue(i,j)>seriesCollection.getOpenValue(i,j)){//收盤價高於開盤價,股票上漲,選用股票上漲的顏色 
        return candlestickRender.getUpPaint(); 
       }else{ 
        return candlestickRender.getDownPaint(); 
       } 
     }}; 
     xyBarRender.setMargin(0.1);//設置柱形圖之間的間隔 
     NumberAxis y2Axis=new NumberAxis();//設置Y軸,为數值,後面的設置,参考上面的y軸設置 
     y2Axis.setAutoRange(false); 
     y2Axis.setRange(min2Value*0.9, high2Value*1.1); 
     y2Axis.setTickUnit(new NumberTickUnit((high2Value*1.1-min2Value*0.9)/4)); 
     XYPlot plot2=new XYPlot(timeSeriesCollection,null,y2Axis,xyBarRender);//建立第二個畫圖區域對象,主要此時的x軸設为了null值,因为要與第一個畫圖區域對象共享x軸 
     CombinedDomainXYPlot combineddomainxyplot = new CombinedDomainXYPlot(x1Axis);//建立一個恰當的聯合圖形區域對象,以x軸为共享軸 
     combineddomainxyplot.add(plot1, 2);//添加圖形區域對象,後面的數字是計算這個區域對象應該占據多大的區域2/3 
        combineddomainxyplot.add(plot2, 1);//添加圖形區域對象,後面的數字是計算這個區域對象應該占據多大的區域1/3 
        combineddomainxyplot.setGap(10);//設置兩個圖形區域對象之間的間隔空間 
        JFreeChart chart = new JFreeChart("中國聯通", JFreeChart.DEFAULT_TITLE_FONT, combineddomainxyplot, false); 
        ChartFrame frame = new ChartFrame("中國聯通股票", chart); 
     frame.pack(); 
     frame.setVisible(true); 




为了能夠保證K線圖的上影線和下影線能夠和K線圖本身的顏色保持一致,找了很多的方法設置都不成功,可以說目前暫不提供單獨繪制K線邊框顏色的方法,所以,經過本人的實驗,對其中的源代碼進行了下修改,具體修改的地方是在下載回來的文件目中source\org\jfree\chart\renderer\xy\CandlestickRenderer.java文件,將 
Paint p = getItemPaint(series, item); 
           Paint outlinePaint = null; 
           outlinePaint = getItemOutlinePaint(series, item); 


修改为如下的代碼,這样就會保證K線圖的上影線和下影線能夠和K線圖本身的顏色保持一致,符合中國股票市場K線圖形顏色的習慣: 
Paint p = getItemPaint(series, item); 
           Paint outlinePaint = null; 
           if (this.useOutlinePaint) { 
            if(yClose>yOpen){ 
             if (this.upPaint != null) { 
              outlinePaint=this.upPaint; 
                   } 
                   else { 
                    outlinePaint=p; 
                   } 
            }else{ 
             if (this.downPaint != null) { 
              outlinePaint=this.downPaint; 
                   } 
                   else { 
                    outlinePaint=p; 
                   } 
            } 
           } 

chart.setBackgroundPaint(Color.white);//設置曲線圖背景色 

XYPlot plot = (XYPlot) chart.getPlot(); 
XYLineAndShapeRenderer xylineandshaperenderer = (XYLineAndShapeRenderer)plot.getRenderer(); 
plot.setBackgroundPaint(Color.white));//設置網格背景顏色 
plot.setDomainGridlinePaint(Color.pink);//設置網格豎線顏色 
plot.setRangeGridlinePaint(Color.pink);//設置網格橫線顏色 
plot.setAxisOffset(new RectangleInsets(0D, 0D, 0D, 10D));//設置曲線圖與xy軸的距離,即曲線與xy軸貼近的距離 
xylineandshaperenderer.setBaseShapesVisible(true);//設置曲線是否顯示數據點

路過

雞蛋

鮮花

握手

雷人

評論 (0 個評論)

facelist

您需要登錄後才可以評論 登錄 | 立即註冊

小黑屋|Archiver|手機版|艾歐踢創新工坊    

GMT+8, 2024-4-29 14:11 , Processed in 0.194963 second(s), 20 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

返回頂部