2024-01-30

QThreadPool を使う ~ PySide6

PySide (Qt for Python) は、Qt(キュート)の Python バインディングで、GUI などを構築するためのクロスプラットフォームなライブラリです。Linux/X11, macOS および Microsoft Windows をサポートしています。配布ライセンスは LGPL で公開されています。

以前、本ブログで PySide2 と mplfinance を組み合わせた GUI サンプルを紹介しました [1]。また、PySide6 に GUI ライブラリを更新したサンプルも既に紹介しています [2]

今回は yfinance の API を利用して株価データを取得する部分を、QThreadPool / QRunnable で別スレッドにして読み込むようにしました。データの読み込みにそれほど時間が掛かるわけでもないのですが、スレッドの練習題材にしたくて、ローソク足チャートのサンプルを再び取り上げました。

下記の OS 環境で動作確認をしています。

Fedora Workstation 39 x86_64
Python 3.12.1
PySide6 6.6.1
matplotlib 3.8.2
mplfinance 0.12.10b0
pandas 2.2.0
yfinance 0.2.36

サンプル

サンプルはあまりコンパクトにできなかったので、下記の4つのファイルに分けました。

  • qt_mpl_finance_2.py
    • GUI サンプルのメイン
  • qt_mpl_finance_2_func.py
    • 関数処理
  • qt_mpl_finance_2_sub.py
    • GUI のサブ・コンポーネント
  • qt_mpl_finance_2_thread.py
    • QRunner によるスレッド処理

qt_mpl_finance_2.py は、本サンプルのメイン部分で、下記の GUI を QMainWindow で構成しています。

qt_mpl_finance_2.py の実行例 (1)
qt_mpl_finance_2.py

qt_mpl_finance_2_func.py は、yfinance で株価データを読み込む処理と、mplfinance でデータフレームをキャンバス上に描画する処理を関数としてまとめてあります。

qt_mpl_finance_2_func.py

qt_mpl_finance_2_sub.py は、メインの QMainWindow の GUI を構成する、ツールバー、中心部のチャート用のキャンバス、Matplotlib のナビゲーション・ツールバーを表示する下部のドックを記述しています。

qt_mpl_finance_2_sub.py

qt_mpl_finance_2_thread.py は、yfinance で株価データを読み込む処理を別スレッドで実行する QRunnable クラスを継承した ThreadWorker クラスです。

qt_mpl_finance_2_thread.py

QRunnable クラスを継承した ThreadWorker のインスタンスでは、別スレッドで処理を実行させることができますが、そのままでは、処理の終了や結果を Signal を発して親スレッドへ送ることができません。そのため、このサンプルでは、QObject を継承したシグナル専用のクラス ThreadWorkerSignal を作成しておいて、QRunnable と一緒に多重継承して、ThreadWorkerSignal で定義したシグナルを利用できるようにしています。

class ThreadWorkerSignal(QObject):
    finished = Signal(str, pd.DataFrame)


class ThreadWorker(QRunnable, ThreadWorkerSignal):
    def __init__(self, ticker: str):
        super().__init__()
        self.ticker = ticker

    def run(self):
        df = get_trade_info(self.ticker)
        self.finished.emit(self.ticker, df)

この ThreadWorker は、本体 qt_mpl_finance_2.py 側で、下記のメソッド内でインスタンス worker を生成して、QThreadPool のインスタンス self.threadpoolstart メソッドにインスタンス worker を渡します。この start メソッドが実行されると、別スレッドで worker.run() が実行されます。

    def on_ticker_entered(self, ticker: str):
        worker = ThreadWorker(ticker)
        worker.finished.connect(self.on_draw_chart)
        self.threadpool.start(worker)

worker の処理が終わると、finished シグナルが発せられるので、これを self.on_draw_chart メソッド(スロット)で処理します。

    def on_draw_chart(self, ticker: str, df: pd.DataFrame):
        chart: QWidget | StockChart = self.centralWidget()
        draw_chart(chart, ticker, df)

サンプルの使い方

東証に上場している銘柄であれば、ツールボックスの QLineEdit のインスタンスに、銘柄コードに .T を付加した文字列(例 1301.T)を入力して Enter すると、過去3ヶ月分の日足チャートが出力されます。

qt_mpl_finance_2.py の実行例 (2)

日経平均の指数は ^N255 と入力して Enter します。米国銘柄はアルファベットのシンボルを入力します。

qt_mpl_finance_2.py の実行例 (3)

サンプルということで、存在しないコードを入力したときなどのエラー処理は一切していません。🙇🏻

参考サイト

  1. bitWalk's: ローソク足チャート ~ python/mplfinance [2021-05-02]
  2. bitWalk's: ローソク足チャート ~ PySide6, mplfinance [2023-08-15]
  3. QThreadPool - Qt for Python
  4. QRunnable - Qt for Python
  5. ranaroussi/yfinance: Download market data from Yahoo! Finance's API
  6. matplotlib/mplfinance: Financial Markets Data Visualization using Matplotlib

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ オープンソースへ
にほんブログ村

オープンソース - ブログ村ハッシュタグ
#オープンソース



このエントリーをはてなブックマークに追加

0 件のコメント: