TiDB User Day 2024のアーカイブ動画を公開中!詳細を見る
streamlit_banner

※このブログは2023年5月10日に公開された英語ブログ「Building an Interactive Web App with TiDB Cloud and Streamlit」の拙訳です。

今日のようなデータドリブンの世界では、大規模なデータセットを迅速かつ簡単に分析することが不可欠です。TiDB CloudやStreamlitのような強力なツールを使えば、開発者はデータの分析や可視化を容易にするインタラクティブなUIを構築することができます。

TiDB Cloudは、先進的なオープンソースの分散型SQLデータベースであるTiDBのフルマネージドサービスであり、低レイテンシーと水平スケーラビリティでトランザクションデータへのリアルタイムなアクセスを実現します。Streamlitと組み合わせることで、TiDB Cloudは金融データへのリアルタイムアクセスを提供し、ユーザーがリアルタイムでデータを分析・可視化することを可能にします。

一方のStreamlitはオープンソースであるPythonフレームワークで、ウェブアプリケーションの構築プロセスを簡素化するものです。開発者が最小限の労力で強力なデータ・アプリケーションを作成できる、直観的なAPIを提供しています。

この投稿では、TiDB CloudとStreamlitを使ってインタラクティブな株式データ用のウェブアプリケーションを構築する方法を紹介します。一部のアプリケーションの構成要素は、コードを順に追いながら説明します。まずTiDB Cloudに接続し、次にYahoo Finance APIからデータを取得し、最後にPlotlyを使ってデータを視覚化する方法を学びます。このチュートリアルが終わるころには、データ分析と可視化のワークフローを合理化する同様のアプリケーションを構築する強力なツールの活用方法について理解を深めていることでしょう。

前提条件

作業を始める前に、以下の設定が必要となります。

初期設定

ストック・データ・プロジェクトのセットアップ

1.TiDB CloudとStreamlitの結合サンプルコードリポジトリをクローンします。ターミナルまたはコマンドプロンプト (Windowsユーザー) から、以下のコマンドを実行します。

git clone https://github.com/tidbcloud/streamlit-stockdata-analysis.git 

2. プロジェクトのルート・ディレクトリ “streamlit-stockdata-analysis” に移動し、以下を入力します。

cd streamlit-stockdata-analysis

3. requirements.txtに記載されているproject dependenciesをインストールします。ターミナル・ウィンドウで以下を入力します。

python3 -m pip install -r requirements.txt

データベース・シークレットの保存

TiDB Cloudクラスタの接続情報を格納するsecretsファイルを作成します。Streamlitアプリはこのファイルを参照して、TiDBデータベースとの接続を行います。StreamlitアプリとTiDBとの接続の詳細については、Streamlitチュートリアル「Connect Streamlit to TiDB (英語) 」を参照してください。

  1. プロジェクトのルートディレクトリに、.streamlit/secrets.tomlという名前のファイルを作成します。
  2. プレースホルダーの値をTiDB Cloudクラスタの情報に置き換えて、以下の内容をファイルに追加します。
#.streamlit/secrets.toml
[tidb]
host = "<TiDB_cluster_host>"
port = 4000
database = "test"
user = "<TiDB_cluster_user>"
password = "<TiDB_cluster_password>"
ssl_ca = "<path_to_CA_store>"

認証局 (CA) の保存パスはオペレーティングシステムによって異なります。このパスはTiDB CloudクラスタのConnectionタブで確認できます。たとえば、macOSの場合のパスは/etc/ssl/cert.pemになります。

TiDBとStreamlitアプリの接続について、詳細はStreamlitのドキュメント (英語) を参照してください。

株式データを保存するTiDBテーブルの作成

ティッカーシンボルの日次ヒストリカルデータをTiDBに保存するには、以下の手順に従います。

  1. TiDB Consoleにログインし、クラスタの概要ページに移動します。
  2. 左側のナビゲーションペインでChat2Queryを選択し、以下のSQLスクリプトを実行します。スクリプトはtestデータベース内に ”stock_price_history” テーブルを作成します。このテーブルには、株式の取引量、配当金、始値と終値などの情報が格納されます。
SQL
CREATE TABLE test.stock_price_history
(
  id int PRIMARY KEY AUTO_INCREMENT,
  Opening_Price DOUBLE,
  High DOUBLE,
  Low DOUBLE,
  Closing_Price DOUBLE,
  Volume BIGINT,
  Dividends DOUBLE,
  Market_Date DATE,
  Ticker VARCHAR(10)
);

株式データプロジェクトの動き

初期設定が完了したら、いよいよプロジェクトを実行に移しましょう。このチュートリアルでは、マイクロソフト (MSFT) とグーグル (GOOGL) の10年分の株価ヒストリカルデータを収集し、分析します。他の銘柄を追跡したい場合は、お好きなティッカーシンボルに置き換えてください。このアプリケーションはYahoo Finance APIからデータを取得し、TiDB Cloudに保存し、Plotlyの3Dチャートを使って可視化します。

  1. ローカルマシンでプロジェクトを実行します。ターミナルまたはコマンドプロンプト (Windowsユーザー) から、 streamlit run stocks.pyと入力してください。
  2. ウェブブラウザ (http://localhost:8502) でアプリケーションを起動します。
  3. デフォルトのメニューで、Collect Trade Dataを選択し、分析したい銘柄のティッカーシンボル (この場合はMSFT) を入力します。
  4. 開始日と終了日をデフォルト値のままにしてGet Dataをクリックすると、選択した銘柄の10年分のヒストリカルデータを取得できます。
  5. Save Dataをクリックすると、取得した銘柄データがTiDB Cloudに保存されます。
  6. Googleのデータを取得するには、ティッカーシンボルGOOGLを使い、手順3~5を繰り返します。
  7. データを分析するには、Visualize Trade Dataをクリックし、対応するティッカーシンボルを入力し、日付はデフォルトのままにして、Visualizeをクリックします。

この操作により、TiDB上で分析クエリを実行し、その結果を3Dチャートで表示し、Google株とMicrosoft株の配当金支払総額と取引高を長期間で比較することができます。

コードのチュートリアル

このセクションでは、株式データプロジェクトの重要な要素となるコードについて説明します。アプリケーションのコンポーネントと、それらがどのように相互作用して過去の株式データを収集、分析、視覚化しているかを探ります。また、使用されている様々なパッケージと、それらがアプリケーションの全体的な機能にどのように貢献しているかについても説明します。

使用するパッケージ

import streamlit as st
import yfinance as yf
import pandas as pd
import plotly.express as px
import pymysql
パッケージ説明
streamlitデータサイエンスおよび機械学習プロジェクトのためのウェブアプリケーション構築
yfinanceYahoo Financeから過去の株価データを取得・分析
pandasデータ操作と分析
plotly.expressインタラクティブなビジュアライゼーション
pymysqlTiDBとの相互作用

こうしたパッケージとTiDBを組み合わせることで、データを分析、視覚化、保存するインタラクティブなウェブページを構築するための強力なツールキットとなります。

TiDBへのアクセス

TiDBと連動する関数によって、プロジェクトの分析・可視化機能の基盤が提供されます。

データベースへの接続

init_connection() 関数は、Streamlit Secrets Manager (英語) に保存されているクレデンシャルを使用してTiDBデータベースに接続します。この関数は、データの取得と保存に使用する接続オブジェクトを返します。

def init_connection():
    config = st.secrets["tidb"]
    return pymysql.connect(
        host=config["host"],
        port=config["port"],
        user=config["user"],
        password=config["password"],
        database=config["database"],
        ssl_verify_cert=True,
        ssl_verify_identity=True,
        ssl_ca= config["ssl_ca"]
    ) 

conn = init_connection()

データの保存

get_ticker_data() 関数は、指定されたティッカーシンボル、開始日、終了日の過去の株式データを取得します。Yahoo Financeの yfinance ライブラリを使用し、この関数は株価の始値、高値、安値、終値、出来高、配当を含む pandas.DataFrame を返します。

def get_ticker_data(symbol, start_date, end_date):
    ticker = yf.Ticker(symbol)
    data = ticker.history(start=start_date, end=end_date)
    return data

save_data() 関数は、 pymysql ライブラリのバルクインサートメソッドexecutemany を使用してTiDBデータベースに株式データを挿入します。この関数は pandas.DataFrame とティッカーシンボルを入力として受取り、データを整形してデータベースに挿入します。

def save_data(data, symbol):
    data["Date"] = data.index
    data["Ticker"] = symbol
    data.reset_index(drop=True, inplace=True)

    df = data.loc[:, ['Open', 'High', 'Low', 'Close', 'Volume', 'Dividends', 'Date', 'Ticker']]

    cur = conn.cursor()

    data = [tuple(row) for row in df.itertuples(index=False)]

    query = 'INSERT INTO stock_price_history (Opening_Price, High, Low, Closing_Price,Volume, Dividends , Market_Date, Ticker) VALUES (  %s,  %s,  %s,  %s, %s,  %s, %s, %s);'
    cur.executemany(query, data)

    rows_upserted = cur.rowcount

    # commit the changes
    conn.commit()
    cur.close()
    conn.close()
    st.success( str(rows_upserted) +  " data saved successfully!")

データの取得

The fetch_data() 関数は、TiDBのHybrid Transactional & Analytical Processing (HTAP) 機能を活用してSQLクエリを実行し、集約された株式データ情報を取得します。

この関数は、2つの銘柄ティッカーシンボルと日付範囲を受け取り、ティッカーシンボル、年、総配当、平均取引量を含むpandas.DataFrame を返します。

def fetch_data(symbol1, symbol2, start_date, end_date):
    cursor = conn.cursor()
    query = f"""
    SELECT Ticker, YEAR(Market_Date) AS Year, ROUND(SUM(Dividends), 2) AS Total_Dividends, CAST(ROUND(AVG(Volume), 2) AS DOUBLE) AS Avg_Volume
    FROM stock_price_history
    WHERE Ticker IN ('{symbol1}', '{symbol2}') AND Market_Date BETWEEN '{start_date}' AND '{end_date}'
    GROUP BY Ticker, YEAR(Market_Date)
    ORDER BY Ticker, YEAR(Market_Date) ASC;
    """
    cursor.execute(query)
    data = cursor.fetchall()
    cols = ['Ticker', 'Year', 'Total_Dividends', 'Avg_Volume']
    df = pd.DataFrame(data, columns=cols)
    return df

ウェブアプリケーション

このウェブアプリケーションでは、過去の株式取引データを収集、視覚化することができます。

取引データの収集

取引データの収集ページでは、ユーザーは銘柄ティッカーシンボル、開始日、終了日を入力します。ユーザーがGet Dataをクリックすると、アプリは指定された日付範囲内の指定された銘柄の過去の取引データを取得し、テーブルに表示します。このデータは、ユーザーが保存するかページを離れるまで、セッションに保存されます。

# Define the inputs
symbol = st.text_input("Ticker Symbol").upper()
start_date = st.date_input("Start Date", value=pd.to_datetime("today").floor("D") - pd.offsets.DateOffset(years=10))
end_date = st.date_input("End Date", value=pd.to_datetime("today").floor("D"))

# Define the button to retrieve the data
if st.button("Get Data"):
    data = get_ticker_data(symbol, start_date, end_date)
    st.write(data)
# store data in session
    st.session_state.data = data

Save Dataボタンをクリックすると、TiDBにデータが追加され、セッションがクリアされます。

# Define the button to save the data to TiDB
if st.button("Save Data"):
    if st.session_state.get("data") is None:
        st.write("No data to save.")
        return
    data = st.session_state.data
    save_data(data, symbol)
    del st.session_state['data']

取引データの可視化

取引データの可視化ページでは、ユーザーは2つの銘柄ティッカーシンボル、開始日、終了日を入力します。Visualizeをクリックすると、指定された日付範囲内で特定の銘柄について過去の取引データが取得され、各銘柄の取引量に対する支払配当金の3D折れ線グラフが表示されます。

# Create two text boxes for entering the stock symbols
symbol1 = st.text_input("Enter Ticker Symbol").upper()
symbol2 = st.text_input("Enter Ticker Symbol to Compare").upper()

# Create two date pickers for selecting the start and end dates
start_date = st.date_input("Start Date", value=pd.to_datetime("today").floor("D") - pd.offsets.DateOffset(years=10))
end_date = st.date_input("End Date", value=pd.to_datetime("today").floor("D"))

if st.button("Visualize"):
    # Fetch data from the database
    data = fetch_data(symbol1, symbol2, start_date, end_date)

    if data.empty:
        st.warning('No data found for the selected criteria. Please adjust the inputs.')
    else:
        # Display the chart
        plot_3d_line(data)

プロット3Dチャート

plot_3d_line関数は、Plotlyライブラリを使用して3D折れ線グラフを作成します。このライブラリは、データをより意味のあるものにする様々なインタラクティブな可視化ツールを提供します。各銘柄ティッカーの配当支払額、売買高、年の相関関係を視覚化することで、ユーザーは銘柄の長期的なパフォーマンスに関する洞察を深めて、より多くの情報に基づいた投資判断を行うことが可能になります。

def plot_3d_line(data):
    fig = px.line_3d(data, x='Year', y='Total_Dividends', z='Avg_Volume', color='Ticker')
    fig.update_layout(title=f"Dividend Paid Vs Volume Traded", height=600, width=800, scene=dict(xaxis_title="Year", yaxis_title="Dividends Paid", zaxis_title="Volume Traded"))
    st.plotly_chart(fig)

まとめ

PythonとStreamlitを使い株式データ分析アプリを構築すれば、金融データを可視化し分析するための強力なツールとなります。さらに、バックエンドデータベースとしてTiDBを使用することで、アプリケーションに水平スケーラビリティと高可用性を提供することができます。

TiDBを体験するには、コミュニティエディションまたはTiDB Cloud無料トライアルをお試しください。日本語ドキュメントのTiDBクイックスタートガイド、またはTiDB Cloudワークショップガイドのご利用をお勧めします。ご不明な点などございましたら、お問い合わせフォームよりご連絡ください。また、GitHubにて問題を報告することもできます。


Have questions? Let us know how we can help.

Contact Us

TiDB Cloud Dedicated

TiDB Cloudのエンタープライズ版。
専用VPC上に構築された専有DBaaSでAWSとGoogle Cloudで利用可能。

TiDB Cloud Serverless

TiDB Cloudのライト版。
TiDBの機能をフルマネージド環境で使用でき無料かつお客様の裁量で利用開始。