天天看點

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖

如何使用Tushare和Echarts來畫股票K線圖

技術支援

Tushare大資料社群官網

​ 首先介紹一下這次要使用的兩個工具,Tushare是一個基于Python的金融資料接口,擁有豐富的資料内容,如股票、基金、期貨、數字貨币等行情資料,公司财務、基金經理等基本面資料等(詳細介紹進官網)。如果你之前沒有注冊過Tushare,而且恰好對金融量化、金融資料分析感興趣,不妨注冊一個Tushare賬号,可以擷取想要的資料,點選注冊。

ECharts官網

常見的資料可視化庫:

  • D3.js 目前 Web 端評價最高的 Javascript 可視化工具庫(入手難)
  • ECharts.js 百度出品的一個開源 Javascript 資料可視化庫
  • Highcharts.js 國外的前端資料可視化庫,非商用免費,被許多國外大公司所使用
  • AntV 螞蟻金服全新一代資料可視化解決方案 等等
  • Highcharts 和 Echarts 就像是 Office 和 WPS 的關系
ECharts,一個使用 JavaScript 實作的開源可視化庫,可以流暢的運作在 PC 和移動裝置上,相容目前絕大部分浏覽器(IE8/9/10/11,Chrome,Firefox,Safari等),底層依賴矢量圖形庫 ZRender,提供直覺,互動豐富,可高度個性化定制的資料可視化圖表,詳細介紹可進官網檢視.

大白話:

  • 是一個JS插件
  • 性能好可流暢運作PC與移動裝置
  • 相容主流浏覽器
  • 提供很多常用圖表,且可定制(折線圖、柱狀圖、散點圖、餅圖、K線圖)

實作結果

先展示一下最終的結果,下面第一張圖是利用Tushare和Echarts做出而來的貴州茅台的日K圖,第二張圖是同花順網頁版的貴州茅台的日K圖。除了資料的展示不一樣之外,資料的内容是一樣的。

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖
如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖

實作步驟

1.搭建運作環境

我這裡的運作環境是Python 3.8.0,Tushare的版本是1.2.62的,因為Tushare是Python的第三方包,是以需要導入,詳細步驟見:說明。

# 導入tushare
import tushare as ts
# 設定token
ts.set_token('your token here')
# 初始化pro接口
pro = ts.pro_api( )
           

至此資料擷取的環境已經搭建好了,我們來試一下擷取的資料是什麼樣子的。

daily_data=pro.daily(ts_code='600519.SH', start_date='20210101', end_date='20210220')
print(daily_data)
print(type(daily_data))
           

輸出的結果是下面的圖中所顯示的,你會發現有交易日期,開盤價,收盤價,最高價,最低價,成交量等資料。資料的形式是DataFrame類型的,也就是說

daily_data

具備DataFrame的一般方法和屬性,是以資料的顯示是從最新資料顯示在最前面,但是K線需要的是最近成交的資料顯示在最後面,待會我們在來處理資料的問題,這一步說明我們資料接口已經可以使用了。

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖

現在開始要引入資料可視化的JavaScript檔案,點選進入下載下傳位址,會彈出下面的圖檔,需要下載下傳的内容是

echarts.js

或者

echarts.min.js

都可以,下載下傳完後要記得放到對應的工作環境中,友善後面的引入。

2.先畫圖

在畫圖之前,我們有必要對Echarts有個基本的了解,建議先去Echarts官網浏覽5 分鐘上手 ECharts,可以對Echarts有個基本的了解.

使用步驟:

  1. 引入 ECharts:通過标簽方式直接引入建構好的 echarts 檔案。
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <!-- 引入 ECharts 檔案 -->
        <script src="echarts.min.js"></script>
    </head>
    </html>
               
  2. 準備一個具備大小的DOM容器,用來放圖。
  3. 初始化echarts執行個體對象
  4. 指定配置項和資料(option)
    var option = {
        xAxis: {
            type: 'category',
            data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
        },
        yAxis: {
            type: 'value'
        },
        series: [{
            data: [820, 932, 901, 934, 1290, 1330, 1320],
            type: 'line'
        }]
    };
               
  5. 将配置項設定給echarts執行個體對象

需要了解的主要配置:

series

xAxis

yAxis

grid

tooltip

title

legend

color

  • series:系列清單。每個系列通過

    type

    決定自己的圖表類型;大白話:圖示資料,指定什麼類型的圖示,可以多個圖表重疊。
  • xAxis:直角坐标系 grid 中的 x 軸
  • boundaryGap: 坐标軸兩邊留白政策 true,這時候刻度隻是作為分隔線,标簽和資料點都會在兩個刻度之間的帶(band)中間。
  • yAxis:直角坐标系 grid 中的 y 軸
  • grid:直角坐标系内繪圖網格。
  • title:标題元件
  • tooltip:提示框元件
  • legend:圖例元件
  • color:調色盤顔色清單[]

OK,對上面的知識點有了一定的了解之後,我們可以開始來畫我們需要的K線圖了。我先把Echarts的全部代碼先貼出來,後面在分别解釋沒塊代碼的作用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>debug</title>
    <style>
        #k-box{
            height: 100%;
            width: 50%;
            background: white;
            display: inline-block;
        }
    </style>
    <script src="echarts.min.js"></script>
</head>
<body>
    <div id="k-box"></div>
<script>
    const chartDom = document.getElementById('k-box');
    const myChart = echarts.init(chartDom);
    var option;

    const upColor = '#008000';
    const downColor = '#c00c00';

	// 對資料進行處理的函數,将交易日期,成交量,價格資訊分别放置在不同的數組
    function splitData(rawData) {
        var categoryData = [];
        var values = [];
        var volumes = [];
        for (var i = 0; i < rawData.length; i++) {
            categoryData.push(rawData[i].splice(0, 1)[0]);
            values.push(rawData[i]);
            volumes.push([i, rawData[i][4], rawData[i][0] > rawData[i][1] ? 1 : -1]);
        }

        return {
            categoryData: categoryData,
            values: values,
            volumes: volumes
        };
    }
    // 用于計算均線的函數
    function calculateMA(dayCount, data) {
        var result = [];
        for (var i = 0, len = data.values.length; i < len; i++) {
            if (i < dayCount) {
                result.push('-');
                continue;
            }
            var sum = 0;
            for (var j = 0; j < dayCount; j++) {
                sum += data.values[i - j][1];
            }
            result.push(+(sum / dayCount).toFixed(3));
        }
        return result;
    }


       //  data的資料格式是[['交易日期',開盤價,收盤價,最高價,最低價,成交量][][]....]
        var data = splitData(data);
   
    myChart.setOption(option = {
        animation: false,
        legend: {
            bottom: 10,
            left: 'center',
            data: ['Dow-Jones index', 'MA5', 'MA10', 'MA20', 'MA30']
        },
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                type: 'cross'
            },
            borderWidth: 1,
            borderColor: '#ccc',
            padding: 10,
            textStyle: {
                color: '#000'
            },
            position: function (pos, params, el, elRect, size) {
                var obj = {top: 10};
                obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 30;
                return obj;
            }
            // extraCssText: 'width: 170px'
        },
        axisPointer: {
            link: {xAxisIndex: 'all'},
            label: {
                backgroundColor: '#777'
            }
        },
        toolbox: {
            feature: {
                dataZoom: {
                    yAxisIndex: false
                },
                brush: {
                    type: ['lineX', 'clear']
                }
            }
        },
        brush: {
            xAxisIndex: 'all',
            brushLink: 'all',
            outOfBrush: {
                colorAlpha: 0.1
            }
        },
        visualMap: {
            show: false,
            seriesIndex: 5,
            dimension: 2,
            pieces: [{
                value: 1,
                color: downColor
            }, {
                value: -1,
                color: upColor
            }]
        },
        grid: [
            {
                left: '10%',
                right: '8%',
                height: '50%'
            },
            {
                left: '10%',
                right: '8%',
                top: '63%',
                height: '16%'
            }
        ],
        xAxis: [
            {
                type: 'category',
                data: data.categoryData,
                scale: true,
                boundaryGap: false,
                axisLine: {onZero: false},
                splitLine: {show: false},
                splitNumber: 20,
                min: 'dataMin',
                max: 'dataMax',
                axisPointer: {
                    z: 100
                }
            },
            {
                type: 'category',
                gridIndex: 1,
                data: data.categoryData,
                scale: true,
                boundaryGap: false,
                axisLine: {onZero: false},
                axisTick: {show: false},
                splitLine: {show: false},
                axisLabel: {show: false},
                splitNumber: 20,
                min: 'dataMin',
                max: 'dataMax'
            }
        ],
        yAxis: [
            {
                scale: true,
                splitArea: {
                    show: true
                }
            },
            {
                scale: true,
                gridIndex: 1,
                splitNumber: 2,
                axisLabel: {show: false},
                axisLine: {show: false},
                axisTick: {show: false},
                splitLine: {show: false}
            }
        ],
        dataZoom: [
            {
                type: 'inside',
                xAxisIndex: [0, 1],
                start: 98,
                end: 100
            },
            {
                show: true,
                xAxisIndex: [0, 1],
                type: 'slider',
                top: '85%',
                start: 98,
                end: 100
            }
        ],
        series: [
            {
                name: 'Dow-Jones index',
                type: 'candlestick',
                data: data.values,
                itemStyle: {
                    color: upColor,
                    color0: downColor,
                    //改動過
                    borderColor: upColor,
                    borderColor0: downColor
                },
                tooltip: {
                    formatter: function (param) {
                        param = param[0];
                        return [
                            'Date: ' + param.name + '<hr size=1 style="margin: 3px 0">',
                            'Open: ' + param.data[0] + '<br/>',
                            'Close: ' + param.data[1] + '<br/>',
                            'Lowest: ' + param.data[2] + '<br/>',
                            'Highest: ' + param.data[3] + '<br/>'
                        ].join('');
                    }
                }
            },
            {
                name: 'MA5',
                type: 'line',
                data: calculateMA(5, data),
                smooth: true,
                lineStyle: {
                    opacity: 0.5
                }
            },
            {
                name: 'MA10',
                type: 'line',
                data: calculateMA(10, data),
                smooth: true,
                lineStyle: {
                    opacity: 0.5
                }
            },
            {
                name: 'MA20',
                type: 'line',
                data: calculateMA(20, data),
                smooth: true,
                lineStyle: {
                    opacity: 0.5
                }
            },
            {
                name: 'MA30',
                type: 'line',
                data: calculateMA(30, data),
                smooth: true,
                lineStyle: {
                    opacity: 0.5
                }
            },
            {
                name: 'Volume',
                type: 'bar',
                xAxisIndex: 1,
                yAxisIndex: 1,
                data: data.volumes
            }
        ]
    }, true);
    option && myChart.setOption(option);
</script>
</body>
</html>
           

初始化echarts執行個體對象,前面的DOM容器已經放好。

var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option;
// 設定股票上漲和下跌的顔色
var upColor = '#008000';
var downColor = '#c00c00';
           

開始将圖檔畫在網頁上,我們先設定标題,即圖檔展示後顯示的名稱。

myChart.setOption(option = {
	// 圖檔的名稱,字型等樣式.
    title: {
        text: '股票日K',
        left: 0,
        // 設定字型樣式
        textStyle: {
            fontSize:28,
        }
    },
    // 是否開啟動畫效果.
    animation: true,
},true);
           

legend圖例元件展現了不同系列的标記(symbol),顔色和名字。可以通過點選圖例控制哪些系列不顯示。

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖
legend: {
    	// 距離top 9個像數.的值可以是像 20 這樣的具體像素值,可以是像 '20%' 這樣相對于容器高寬的			百分比,也可以是 'top', 'middle', 'bottom'。
            top: 9,
            left: '45%',
            data: ['日K', 'MA5', 'MA10', 'MA20', 'MA30']
        },
           

tooltip是否顯示提示框元件,包括提示框浮層和 axisPointer。

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖
tooltip: {
    trigger: 'axis',
    backgroundColor: 'rgba(255,255,255,0.6)',
    // 坐标軸訓示器是訓示坐标軸目前刻度的工具。
    axisPointer: {
        type: 'cross'
    },
    borderWidth: 1,
    borderColor: '#ccc',
    padding: 10,
    textStyle: {
        color: '#000'
    },
    position: function (pos, params, el, elRect, size) {
        var obj = {top: 10};
        obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 30;
        return obj;
    }
},
           

axisPointer滑鼠移動到一定位置後Y軸和X軸上顯示的文字說明.

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖
axisPointer: {
    link: {xAxisIndex: 'all'},
    label: {
       // {# 滑鼠移到那裡x軸和y軸顯示的數字#}
        backgroundColor: '#777'
    }
},
           

toolbox 工具欄。内置有導出圖檔,資料視圖,動态類型切換,資料區域縮放,重置五個工具,具體需要什麼功能看個人需要。

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖
toolbox: {
    feature: {
        dataZoom: {
            yAxisIndex: false
        },
        brush: {
            type: ['lineX', 'clear']
        }
    }
},
           

brush

是區域選擇元件,使用者可以選擇圖中一部分資料,進而便于向使用者展示被選中資料,或者他們的一些統計計算結果,隐藏K線資料和5日均線資料。

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖
brush: {
    xAxisIndex: 'all',
    brushLink: 'all',
    outOfBrush: {
        colorAlpha: 0.1
    }
},
           

visualMap

是視覺映射元件,用于進行『視覺編碼』,也就是将資料映射到視覺元素(視覺通道)。

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖
visualMap: {
    show: false,
    seriesIndex: 5,
    dimension: 2,
    pieces: [{
        value: 1,
        color: downColor
    }, {
        value: -1,
        color: upColor
    }]
},
           

grid直角坐标系内繪圖網格,單個 grid 内最多可以放置上下兩個 X 軸,左右兩個 Y 軸。可以在網格上繪制折線圖,柱狀圖,散點圖(氣泡圖)。

grid: [
    {  // 用于控制圖像與左邊的邊距
        left: '5%',
        right: '8%',
        height: '50%'
    },
    {
        left: '10%',
        right: '8%',
        top: '63%',
        height: '16%'
    }
],
           

xAxis設定X軸等相關的資料,樣式,字型樣式,寬高等。

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖
xAxis: [
    {
        type: 'category',
        // 日期,格式是['2016-03-01','2016-03-02','2016-03-03'.......]
        data: data.categoryData,
        scale: true,
        boundaryGap: false,
        axisLine: {onZero: false},
        splitLine: {show: false},
        splitNumber: 20,
        min: 'dataMin',
        max: 'dataMax',
        axisPointer: {
            z: 100
        }
    },
    {   
        type: 'category',
        gridIndex: 1,
        data: data.categoryData,
        scale: true,
        boundaryGap: false,
        axisLine: {onZero: false},
        axisTick: {show: false},
        splitLine: {show: false},
        axisLabel: {show: false},
        splitNumber: 20,
        min: 'dataMin',
        max: 'dataMax'
    }
],
           

yAxis設定Y軸等相關的資料,樣式,字型樣式,寬高等。

yAxis: [
    {
        scale: true,
        splitArea: {
            show: true
        }
    },
    {
        scale: true,
        gridIndex: 1,
        splitNumber: 2,
        axisLabel: {show: false},
        axisLine: {show: false},
        axisTick: {show: false},
        splitLine: {show: false}
    }
],
           

dataZoom

元件 用于區域縮放,進而能自由關注細節的資料資訊,或者概覽資料整體,或者去除離群點的影響。

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖
dataZoom: [
    {
        type: 'inside',
        xAxisIndex: [0, 1],
        start: 98,
        end: 100
    },
    {
        show: true,
        xAxisIndex: [0, 1],
        type: 'slider',
        top: '85%',
        start: 98,
        end: 100
    }
],
           

series-candlestickCandlestick 即我們常說的

K線圖

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖
series: [
    {
        name: '日K',
        type: 'candlestick',
        // 股票價格,格式是[['開盤價','收盤價','最低價',最高價,成交量],['開盤價','收盤價','最低價',最高價,成交量]....]
        data: data.values,
        itemStyle: {
            color: upColor,
            color0: downColor,
            borderColor: null,
            borderColor0: null
        },
        tooltip: {
            formatter: function (param) {
                param = param[0];
                return [
                    'Date: ' + param.name + '<hr size=1 style="margin: 3px 0">',
                    'Open: ' + param.data[0] + '<br/>',
                    'Close: ' + param.data[1] + '<br/>',
                    'Lowest: ' + param.data[2] + '<br/>',
                    'Highest: ' + param.data[3] + '<br/>'
                ].join('');
            }
        },
        {
                    name: 'Volume',
                    type: 'bar',
                    xAxisIndex: 1,
                    yAxisIndex: 1,
        	   // [0, 168890000, 1]
                    data: data.volumes
                }
    },
           

MA5:5日均線線的樣式二設定,下面的代碼隻展示了5日均線,其他均線的原理其實是一樣的,這裡的

data: calculateMA(5, data)

借助了函數

calculateMA( )

function calculateMA(dayCount, data) {
    var result = [];
    for (var i = 0, len = data.values.length; i < len; i++) {
        if (i < dayCount) {
            result.push('-');
            continue;
        }
        var sum = 0;
        for (var j = 0; j < dayCount; j++) {
            sum += data.values[i - j][1];
        }
        result.push(+(sum / dayCount).toFixed(3));
    }
    return result;
}
           
如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖
{
    name: 'MA5',
    type: 'line',
    data: calculateMA(5, data),
    smooth: true,
    showSymbol: false,
    lineStyle: {
        opacity: 0.8
    }
           
如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖

最後不要忘記将剛才指定的配置項和資料顯示圖表

到現在,資料展示方面的圖已經出做來了,但是如果沒有資料的提供,K線圖還是畫不出來的,接下來,我們要處理資料了,注意資料的格式是

[[内容1],[内容2],[内容3]...]

,二維數組的形式展現.

3.後填資料

​ 在搭建運作環境中,我們已經知道從Tushare中提取的資料是DataFrame形式的,但是提供給JavaScript的資料是二維數組,一般來說,資料的處理應該在後端處理,前端就負責實作資料的展現,是以我建議在後端就把資料處理好,後面直接傳給前端。

​ 股票的K線圖,從上市那天就會有,是以,一般來說我們要擷取的是股票上市那天到今天的交易資料。

import tushare as ts
    import time
    pro = ts.pro_api( )
    # 實際應用用這裡用的是參數傳遞,不會定死。
    ts_code = '600519.SH'
    # 我們需要的是公司的上市日期,是否退市,退市日期
    data = pro.stock_basic(ts_code=ts_code,fields='list_status,list_date,delist_date')
    data=data.iloc[0]		
    # 輸出結果:   0	  L	 20010827	None
    #  L:上市 D:退市 P:暫停上市
    # 如果不是退市,那麼結束日期(YYYYMMDD)定為今天.
    start_date =data['list_date']
    if data['list_status'] !='D':
        end_date = time.strftime("%Y %m %d").replace(' ','')
    else:
        # 如果是退市,,那麼結束日期(YYYYMMDD)定為退市日期
        end_date=data['delist_date']
     # 擷取股票從上市到現在(退市)的所有資訊,
    all_daily_info = pro.daily(ts_code=ts_code, start_date=start_date, end_date=end_date)
    daily_info_list=[]
    
    # ['交易日期','開盤價','收盤價','最低價',最高價,成交量]
sele_daily_info=all_daily_info[['trade_date','open','close','low','high','vol']].sort_index(ascending=False)
    for num in range(len(sele_daily_info)):
        # 将DataFrame格式的資料轉換成清單,再轉換成二維數組
        daily_info_list.append(list(sele_daily_info.iloc[num]))
           

OK,資料也處理好了,現在就需要将資料傳遞到前端了,如果該方法我就不涉及了,方法也挺多的,我用的是Django前端架構,也可以用Ajax傳遞。好了,至此,資料方面和可視化方面已經全部做好了,最終的效果就是上面第一張圖。如果有什麼疑問,歡迎咨詢。

如何使用Tushare和Echarts來畫股票K線圖如何使用Tushare和Echarts來畫股票K線圖