flaskで作った株価チャート配信サーバー


はじめに

株価の時系列データが入ったcsvファイルがあればmplfinanceを使用すれば、pythonが動作する環境で簡単に株価チャートを表示させることができます。この株価チャートをwebブラウザでいつでも見れるようにするのが本稿の趣旨です。

使用するのは、python, mplfinance, flaskでこれらをまとめてdocker-composeでサクッと動かします。

実行環境

ディレクトリ構成

working_dir/
    Dockerfile
    docker-compose.yml
    opt/
        flask_chart.py
        share/
            data/
                1000/
                    1001.csv
                    1002.csv
                    ...
                2000/
                ...
                9000/
                    9001.csv
                    ...

data/ ディレクトリの中に、1000/ ~ 9000/ のサブディレクトリを切ってその中に、「証券コード.csv」という名前の株価日足時系列データが置かれているものとします。

株価日足時系列データのcsvファイルの例は以下。

1301.csv
2015/01/05,275,277,274,275,239000000
2015/01/06,274,275,270,272,480000000
2015/01/07,270,273,270,271,217000000
  ...
2020/11/25,2839,2846,2795,2831,27800000
2020/11/26,2820,2826,2801,2809,8700000
2020/11/27,2807,2825,2803,2819,22000000

Flaskによる株価チャートサーバ

Flaskはpythonでwebサーバの振る舞いを記述できるんでとても便利。matplotlibで作ったグラフをFlaskで配信する例がネットに多くありますが、matplotlibだけでなく、mplfinanceのplotも同じ方法で出来ちゃうんです。

title=flask_chart.py
import os
import numpy as np
import io
from flask import Flask, send_file, request
from flask_cors import CORS
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

import pandas as pd
import mplfinance as mpf

app = Flask(__name__)
CORS(app)

# http://サーバ名:5000/
@app.route('/')
def root():
    return "Chart Server"

# http://サーバ名:5000/candle?code=1001&term=200&volume=True
@app.route("/candle")
def candle():
    code = request.args.get('code', default=None, type=int)
    term = request.args.get('term', default=200, type=int)
    volume = request.args.get('volume', default="True", type=str)
    code_dir = int(code/1000)*1000
    input_path = "/root/opt/share/data/" + str(code_dir) + "/" + str(code) + ".csv"
    df = load_stock_price_csv(input_path, term=term)
    image = io.BytesIO()
    if len(df)>1:
        mpf.plot(df, title=str(code), type='candle',
                 mav=[5, 25, 75], volume=str2bool(volume))
    plt.savefig(image, format='png')
    image.seek(0)
    return send_file(image, attachment_filename="image.png")

def str2bool(s):
     return s.lower() in ["True", "true", "TRUE", "1"]

def load_stock_price_csv(path, term=0):
    if os.path.exists(path):
        df = pd.read_csv(path, header=None, names=['Date','Open','High','Low','Close','Volume'], encoding='UTF-8')
    else:
        df = pd.DataFrame([[0, 0, 0, 0, 0, 0]])
        df.columns = ['Date','Open','High','Low','Close','Volume']
    df['Date'] = pd.to_datetime(df['Date'])
    df = df.set_index("Date")
    if term>0:
        df = df.tail(term)
    return df

if __name__ == '__main__':
     app.run(host='0.0.0.0', port=5000, debug=True)

http://サーバ名:5000/

によりroot()が走ります。ここでは、クライアントに"Chart Server"という文字列を表示させるだけです。

http://サーバ名:5000/candle?code=6897&term=200&volume=True

によりcandle()が走ります。

candle()では、urlパラメータを抽出し、それに従いmpl.plot()でチャートを表示し、それを(メモリ上の)imageにpngでセーブし、クライアントに返します。

docker-composeによる実装

pythonの実行イメージを作って、そこでflaskサーバを稼働させています。

title=Dockerfile
FROM python:3
USER root

RUN apt-get update
RUN apt-get -y install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm

RUN apt-get install -y vim
RUN pip install --upgrade pip && \
    pip install --upgrade setuptools && \
    pip install --upgrade Flask flask_cors mplfinance
CMD ["python", "/root/opt/flask_chart.py"]

株価データが置かれている場所を、opt/shareにマウントしています。

title=docker-compose.yml
version: '3'
services:
  chart:
    restart: always
    build: .
    container_name: 'chart'
    working_dir: '/root/opt'
    tty: true
    ports:
      - 5000:5000
    volumes:
      - ./opt:/root/opt
      - /home/samba/share/muzinzo:/root/opt/share

株価サーバの起動

$ docker-compose up -d --build

必要に応じてサーバの5000番ポートを開けて、webブラウザで、

http://サーバ名:5000/candle?code=6897&term=120&volume=True

を叩けば株価チャートが見れます。

とてもお手軽に、株価チャート配信サーバを構築できました。サーバでスクリーニングした結果を表示させたり、ページをデコったりと、夢は広がります。

参考までに、株価データを用意したり、チャートを描画したりは、拙文

がお役に立てるかもしれません。

2020/02/11追記

その後、少しWebアプリっぽくしてみました。とは言っても、単なる実装なんで、あえて追記するほどのものではありません。ソースはGutHubに置いています。

2021/2/16追記

作成したサイトをFrozen-Flaskで静的htmlサイトに変換し、GitHubに置いてデモサイトを作ってみました。レスポンシブデザインではないので、PC専用ですが。。

以上