diff --git a/.gitignore b/.gitignore index b6e4761..905e043 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,7 @@ dmypy.json # Pyre type checker .pyre/ + +# Claude Code +.claude/review-state/ +.claude/settings.local.json diff --git a/README.md b/README.md index 115e15c..c507481 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ To use J-Quants API, you need to "Applications for J-Quants API" from [J-Quants J-Quants API を利用するためには[J-Quants API の Web サイト](https://jpx-jquants.com/) から「J-Quants API 申し込み」及び利用プランの選択が必要になります。 -jquants-api-client-python を使用するためには「J-Quants API ログインページで使用するメールアドレスおよびパスワード」または「J-Quants API メニューページから取得したリフレッシュトークン」が必要になります。必要に応じて下記の Web サイトより取得してください。 +jquants-api-client-python を使用するためには「J-Quants API ダッシュボードから取得した API キー」が必要になります。必要に応じて下記の Web サイトより取得してください。 -[J-Quants API ログインページ](https://jpx-jquants.com/login) +[J-Quants API ダッシュボード](https://jpx-jquants.com/dashboard/api-keys) ### サンプルコード (V2) @@ -147,78 +147,6 @@ API レスポンスが Dataframe の形式で取得できます。 - get_mkt_breakdown_range - 売買内訳(範囲指定) - get_fin_details_range - 財務詳細(範囲指定) -## 対応 API (V1) - Deprecated - -> **⚠️ 非推奨**: `Client` クラス (V1) は非推奨となりました。今後は `ClientV2` をご利用ください。 -> V1 API は将来のバージョンで削除される予定です。 - -
-V1 API 一覧(クリックで展開) - -### ラッパー群 - ------------------- Free plan or higher is required ------------------ - -- get_refresh_token -- get_id_token -- get_listed_info -- get_prices_daily_quotes -- get_fins_statements -- get_fins_announcement - ------------------- Light plan or higher is required ------------------ - -- get_markets_trades_spec -- get_indices_topix - ------------------- Standard plan or higher is required ------------------ - -- get_option_index_option -- get_markets_weekly_margin_interest -- get_markets_short_selling -- get_indices -- get_markets_short_selling_positions -- get_markets_daily_margin_interest - ------------------- Premium plan or higher is required ------------------ - -- get_markets_breakdown -- get_prices_prices_am -- get_fins_dividend -- get_fins_fs_details -- get_derivatives_futures -- get_derivatives_options - -### ユーティリティ群 - -- get_market_segments -- get_17_sectors -- get_33_sectors - ------------------- Free plan or higher is required ------------------ - -- get_list -- get_price_range -- get_statements_range - ------------------- Standard plan or higher is required ------------------ - -- get_weekly_margin_range -- get_short_selling_range -- get_index_option_range -- get_markets_short_selling_positions_range -- get_daily_margin_interest_range - ------------------- Premium plan or higher is required ------------------ - -- get_breakdown_range -- get_dividend_range -- get_fins_fs_details_range -- get_derivatives_futures_range -- get_derivatives_options_range - -
- ## レートリミット J-Quants API には、サービスの安定稼働を目的としてレートリミット(利用頻度の制限)が設けられています。 @@ -234,8 +162,6 @@ J-Quants API には、サービスの安定稼働を目的としてレートリ ## 設定 -### V2 (ClientV2) - API キーは設定ファイルおよび環境変数を使用して指定することも可能です。 設定は下記の順に読み込まれ、設定項目が重複している場合は後に読み込まれた値で上書きされます。 @@ -245,7 +171,7 @@ API キーは設定ファイルおよび環境変数を使用して指定する 4. `os.environ["JQUANTS_API_CLIENT_CONFIG_FILE"]` 5. `${JQUANTS_API_KEY}` -#### 設定ファイル例 +### 設定ファイル例 `jquants-api.toml` は下記のように設定します。 @@ -254,33 +180,6 @@ API キーは設定ファイルおよび環境変数を使用して指定する api_key = "*****" ``` -### V1 (Client) - Deprecated - -
-V1 設定方法(クリックで展開) - -認証用のメールアドレス/パスワードおよびリフレッシュトークンは設定ファイルおよび環境変数を使用して指定することも可能です。 -設定は下記の順に読み込まれ、設定項目が重複している場合は後に読み込まれた値で上書きされます。 - -1. `/content/drive/MyDrive/drive_ws/secret/jquants-api.toml` (Google Colab のみ) -2. `${HOME}/.jquants-api/jquants-api.toml` -3. `jquants-api.toml` -4. `os.environ["JQUANTS_API_CLIENT_CONFIG_FILE"]` -5. `${JQUANTS_API_MAIL_ADDRESS}`, `${JQUANTS_API_PASSWORD}`, `${JQUANTS_API_REFRESH_TOKEN}` - -#### 設定ファイル例 - -`jquants-api.toml` は下記のように設定します。 - -```toml -[jquants-api-client] -mail_address = "*****" -password = "*****" -refresh_token = "*****" -``` - -
- ## 動作確認 Google Colab および Python 3.13 で動作確認を行っています。 diff --git a/examples/20220825-000-write-refresh_token.ipynb b/examples/20220825-000-write-refresh_token.ipynb deleted file mode 100644 index 58530ab..0000000 --- a/examples/20220825-000-write-refresh_token.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"cells":[{"attachments":{},"cell_type":"markdown","metadata":{"id":"8gKDRhrY0mrO"},"source":["# リフレッシュトークンの書き込み\n","\n","[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20220825-000-write-refresh_token.ipynb)\n","\n","J-Quants API のリフレッシュトークンを Google Drive の MyDrive/drive_ws/secret/jquantsapi-key.txt に書き込みます。\n","\n","リフレッシュトークンは取得方法は以下のリンク先をご参照ください。\n","\n","https://jpx.gitbook.io/j-quants-ja/outline/getstarted#step2rifuresshutkunnoreapino\n","\n","\n","----\n","\n","**このノートブックはGoogle Driveを使用します。**\n","\n","- Google Drive の以下のファイルにリフレッシュトークンを書き込みます。\n"," - `MyDrive/drive_ws/secret/jquantsapi-key.txt`\n"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"pQVIcLjryiMq"},"outputs":[],"source":["# Google drive をマウントします\n","from google.colab import drive\n","drive.mount('/content/drive')\n","\n","# 必要なモジュールを読み込みます\n","import os\n","from getpass import getpass\n","\n","\n","# refresh_token を入力します\n","refresh_token = getpass(\"Please input refresh token\")\n","\n","# refresh_token の書き込み先を指定します\n","OUTPUT_DIR = \"/content/drive/MyDrive/drive_ws/secret\"\n","OUTPUT_PATH = f\"{OUTPUT_DIR}/jquantsapi-key.txt\"\n","\n","# refresh_token を書き込みます\n","os.makedirs(OUTPUT_DIR, exist_ok=True)\n","with open(OUTPUT_PATH, mode=\"w\") as f:\n"," f.write(refresh_token)\n","\n","# 完了文字列を表示します\n","print(\"Done\")"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"S3wxpLKm0fGN"},"outputs":[],"source":[]}],"metadata":{"colab":{"authorship_tag":"ABX9TyMvkFqt1b8LuOi5OXQ4CqdB","collapsed_sections":[],"name":"20220825-000-write-refresh_token.ipynb","provenance":[]},"kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.11.1"}},"nbformat":4,"nbformat_minor":0} diff --git a/examples/20220825-001-price-movement.ipynb b/examples/20220825-001-price-movement.ipynb deleted file mode 100644 index 492a45c..0000000 --- a/examples/20220825-001-price-movement.ipynb +++ /dev/null @@ -1,351 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "WlEdUu9fEnsO" - }, - "source": [ - "# 株価推移\n", - "\n", - "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20220825-001-price-movement.ipynb)\n", - "\n", - "このノートブックでは指定した日付を基準として複数の銘柄の株価の推移をプロットします。\n", - "\n", - "\n", - "----\n", - "\n", - "**このノートブックはGoogle Driveを使用します。**\n", - "\n", - "- Google Drive の以下のファイルにリフレッシュトークンが書き込まれていることを想定しています。\n", - " - `MyDrive/drive_ws/secret/jquantsapi-key.txt`\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "iND2IbyywrSt" - }, - "outputs": [], - "source": [ - "# 表示する銘柄のコードを指定します (e.g. 8697)\n", - "TARGET_SYMBOLS = [\n", - " \"7201\", # 日産\n", - " \"7203\", # トヨタ\n", - " \"7267\", # ホンダ\n", - "]\n", - "\n", - "# 基準となる営業日付を指定します。(YYYY-MM-DD)\n", - "# 土日や祝日などの営業日以外を入力すると適切に機能しません\n", - "BASE_DATE = \"2022-07-01\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "9REtVkPaGx7Y" - }, - "outputs": [], - "source": [ - "# 必要なモジュールをインストールします。\n", - "! python -m pip install jquants-api-client japanize-matplotlib" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "ilrdZjP4KknF" - }, - "outputs": [], - "source": [ - "# Google drive をマウントします。\n", - "from google.colab import drive\n", - "drive.mount('/content/drive')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "A5fW3HxGN__3" - }, - "outputs": [], - "source": [ - "import os\n", - "from datetime import datetime\n", - "\n", - "import japanize_matplotlib\n", - "import jquantsapi\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pandas as pd\n", - "import seaborn as sns" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "3CeWabhlOGE4" - }, - "outputs": [], - "source": [ - "# pandas の表示制限を調整します\n", - "pd.set_option(\"display.max_rows\", 1000)\n", - "pd.set_option(\"display.max_columns\", 1000)\n", - "pd.set_option(\"display.width\", 2000)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "lLpjTna8OIN-" - }, - "outputs": [], - "source": [ - "# TARGET_SYMBOLS が4桁で入力されている場合は末尾に0を付与する\n", - "for i in range(len(TARGET_SYMBOLS)):\n", - " if len(TARGET_SYMBOLS[i]) == 4:\n", - " TARGET_SYMBOLS[i] += \"0\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "fSG_cbO7Qm4x" - }, - "outputs": [], - "source": [ - "# 一度取得したデータは Google Drive 上に保存して再利用します。\n", - "# 保存先ディレクトリを指定します。\n", - "STORAGE_DIR_PATH = \"/content/drive/MyDrive/drive_ws/marketdata\"\n", - "os.makedirs(STORAGE_DIR_PATH, exist_ok=True)\n", - "STORAGE_DIR_PATH" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "rkEQDOUlQqCN" - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "fIRnvS9kOOqI" - }, - "outputs": [], - "source": [ - "# J-Quants APIのトークンを保存してあるファイルを指定します\n", - "REFRESH_TOKEN_FILE_PATH = \"/content/drive/MyDrive/drive_ws/secret/jquantsapi-key.txt\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "dHm6w6O_QUnS" - }, - "outputs": [], - "source": [ - "def get_refresh_token(refresh_token_file_path: str = REFRESH_TOKEN_FILE_PATH):\n", - " with open(refresh_token_file_path, \"r\") as f:\n", - " refresh_token = f.read()\n", - " return refresh_token.rstrip().lstrip()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "9Ts2dfaRQV9C" - }, - "outputs": [], - "source": [ - "# ファイルからリフレッシュトークンを読み込みます\n", - "refresh_token = get_refresh_token()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "CI9C-h6iQXsG" - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "7ZH_LuWUQYk8" - }, - "outputs": [], - "source": [ - "# J-Quants APIクライアントを初期化します\n", - "jqapi = jquantsapi.Client(refresh_token=refresh_token)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "ximJhjXpQaXa" - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "u02OnzKaHyQa" - }, - "outputs": [], - "source": [ - "# 銘柄情報を取得します\n", - "df_list = jqapi.get_list()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "cKTVKiW2LuoV" - }, - "outputs": [], - "source": [ - "# 取得したデータを表示して確認します\n", - "df_list.head(2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "qXNlF0iBQe8q" - }, - "outputs": [], - "source": [ - "# 株価情報を取得します\n", - "buff = []\n", - "for code in TARGET_SYMBOLS:\n", - " df = jqapi.get_prices_daily_quotes(code=code)\n", - " buff.append(df)\n", - "df_p = pd.concat(buff).reset_index(drop=True)\n", - "\n", - "# 各列のデータ型を調整します\n", - "df_p.loc[:, \"Date\"] = pd.to_datetime(df_p[\"Date\"], format=\"%Y-%m-%d\")\n", - "df_p.loc[:, \"Open\"] = df_p[\"Open\"].astype(np.float64)\n", - "df_p.loc[:, \"High\"] = df_p[\"High\"].astype(np.float64)\n", - "df_p.loc[:, \"Low\"] = df_p[\"Low\"].astype(np.float64)\n", - "df_p.loc[:, \"Close\"] = df_p[\"Close\"].astype(np.float64)\n", - "df_p.loc[:, \"Volume\"] = df_p[\"Volume\"].astype(np.float64)\n", - "df_p.loc[:, \"TurnoverValue\"] = df_p[\"TurnoverValue\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentFactor\"] = df_p[\"AdjustmentFactor\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentOpen\"] = df_p[\"AdjustmentOpen\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentHigh\"] = df_p[\"AdjustmentHigh\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentLow\"] = df_p[\"AdjustmentLow\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentClose\"] = df_p[\"AdjustmentClose\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentVolume\"] = df_p[\"AdjustmentVolume\"].astype(np.float64)\n", - "\n", - "# 日付を絞り込みます\n", - "df_p = df_p.loc[df_p[\"Date\"] >= BASE_DATE]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "I-fpvU4EQiZp" - }, - "outputs": [], - "source": [ - "# 取得したデータを表示して確認します\n", - "df_p.head(2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "K3chIJJNSIva" - }, - "outputs": [], - "source": [ - "# 銘柄\n", - "target_symbols = TARGET_SYMBOLS\n", - "# 基準日\n", - "base_date = BASE_DATE\n", - "\n", - "# 対象銘柄および基準日以降のデータに絞り込み (計算量を減少させるため)\n", - "df_work = df_p.loc[(df_p[\"Code\"].isin(target_symbols)) & (df_p[\"Date\"] >= base_date)].copy()\n", - "\n", - "# # 株価をフィルするために並べ替えます\n", - "df_work.sort_values([\"Code\", \"Date\"], inplace=True)\n", - "# # 株価をフィルするために0をnanに置き換えます\n", - "df_work[\"AdjustmentClose\"].replace({0.0: np.nan}, inplace=True)\n", - "# # 終値が0の場合は前営業日の終値を使用します\n", - "df_work.loc[:, \"AdjustmentClose\"] = df_work.groupby(\"Code\")[\"AdjustmentClose\"].ffill()\n", - "# # 終値がnanの場合は翌営業日の終値を使用します (データの先頭を処理します)\n", - "# df_work.loc[:, \"AdjustmentClose\"] = df_work.groupby(\"Code\")[\"AdjustmentClose\"].bfill()\n", - "\n", - "# 基準日の終値を基準価格としてコピーします\n", - "df_work.loc[:, \"base_price\"] = df_work.loc[df_work[\"Date\"] == base_date, \"AdjustmentClose\"]\n", - "# base_priceをフォーワードフィルします\n", - "df_work.loc[:, \"base_price\"] = df_work.loc[:, \"base_price\"].ffill()\n", - "\n", - "# 基準価格からの変化率を計算\n", - "df_work.loc[:, \"percentage\"] = df_work[\"AdjustmentClose\"].div(df_work[\"base_price\"]) * 100\n", - "\n", - "# 銘柄情報と結合します\n", - "# Date 列が重複しているため df_list から削除して結合しています\n", - "df_work = pd.merge(df_work, df_list.drop(columns=[\"Date\"]), on=\"Code\")\n", - "# 銘柄コードと銘柄名を結合します\n", - "df_work[\"銘柄\"] = df_work[\"CompanyName\"] + \"(\" + df_work[\"Code\"] + \")\"\n", - "\n", - "# プロット用に整形します\n", - "df = df_work.pivot(index='Date', columns='銘柄', values='percentage')\n", - "\n", - "# プロットします\n", - "ax = df.plot(figsize=(20, 8), grid=True)\n", - "\n", - "# 縦軸100の位置に基準線を描画します\n", - "ax.axhline(y=100, color=\"black\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "fgQxPl9xKqZp" - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 3", - "name": "python3" - }, - "language_info": { - "name": "python" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/examples/20220825-002-sector.ipynb b/examples/20220825-002-sector.ipynb deleted file mode 100644 index ec24d96..0000000 --- a/examples/20220825-002-sector.ipynb +++ /dev/null @@ -1,427 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "z_BRLI8MfnMV" - }, - "source": [ - "# セクター別リターン\n", - "\n", - "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20220825-002-sector.ipynb)\n", - "\n", - "このノートブックではセクター別のリターンを算出して表示します。\n", - "\n", - "1. 過去6ヶ月および過去3ヶ月のセクター別リターン\n", - "2. セクター別の月次リターン\n", - "\n", - "\n", - "----\n", - "\n", - "**このノートブックはGoogle Driveを使用します。**\n", - "\n", - "- Google Drive の以下のファイルにリフレッシュトークンが書き込まれていることを想定しています。\n", - " - `MyDrive/drive_ws/secret/jquantsapi-key.txt`\n", - "- Google Drive の以下のフォルダーにデータを書き込みます。\n", - " - `MyDrive/drive_ws/marketdata`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "9REtVkPaGx7Y" - }, - "outputs": [], - "source": [ - "# 必要なモジュールをインストールします。\n", - "! python -m pip install jquants-api-client japanize-matplotlib" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "ilrdZjP4KknF" - }, - "outputs": [], - "source": [ - "# Google drive をマウントします。\n", - "from google.colab import drive\n", - "drive.mount('/content/drive')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "A5fW3HxGN__3" - }, - "outputs": [], - "source": [ - "import os\n", - "from datetime import datetime\n", - "\n", - "import japanize_matplotlib\n", - "import jquantsapi\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pandas as pd\n", - "import seaborn as sns\n", - "from matplotlib.ticker import FormatStrFormatter" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "3CeWabhlOGE4" - }, - "outputs": [], - "source": [ - "# pandas の表示制限を調整します\n", - "pd.set_option(\"display.max_rows\", 1000)\n", - "pd.set_option(\"display.max_columns\", 1000)\n", - "pd.set_option(\"display.width\", 2000)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "lLpjTna8OIN-" - }, - "outputs": [], - "source": [ - "# プロット用の設定をします\n", - "sns.set(rc={'figure.figsize': (15, 10)})\n", - "sns.set(font_scale=2)\n", - "sns.set_style('whitegrid')\n", - "\n", - "japanize_matplotlib.japanize()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "fSG_cbO7Qm4x" - }, - "outputs": [], - "source": [ - "# 一度取得したデータは Google Drive 上に保存して再利用します。\n", - "# 保存先ディレクトリを指定します。\n", - "STORAGE_DIR_PATH = \"/content/drive/MyDrive/drive_ws/marketdata\"\n", - "os.makedirs(STORAGE_DIR_PATH, exist_ok=True)\n", - "STORAGE_DIR_PATH" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "fIRnvS9kOOqI" - }, - "outputs": [], - "source": [ - "# リフレッシュトークンが記載されているファイルを指定します\n", - "REFRESH_TOKEN_FILE_PATH = \"/content/drive/MyDrive/drive_ws/secret/jquantsapi-key.txt\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "dHm6w6O_QUnS" - }, - "outputs": [], - "source": [ - "# リフレッシュトークンを読み込むための関数を定義します\n", - "def get_refresh_token(refresh_token_file_path: str = REFRESH_TOKEN_FILE_PATH):\n", - " with open(refresh_token_file_path, \"r\") as f:\n", - " refresh_token = f.read()\n", - " return refresh_token.rstrip().lstrip()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "9Ts2dfaRQV9C" - }, - "outputs": [], - "source": [ - "# リフレッシュトークンをファイルから読み込みます\n", - "refresh_token = get_refresh_token()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "7ZH_LuWUQYk8" - }, - "outputs": [], - "source": [ - "# J-Quants APIのクライアントクラスを初期化します\n", - "jqapi = jquantsapi.Client(refresh_token=refresh_token)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "JnGHVcqwsR86" - }, - "outputs": [], - "source": [ - "# 銘柄情報を取得します\n", - "now = pd.Timestamp.now(tz=\"Asia/Tokyo\")\n", - "\n", - "list_file = f\"{STORAGE_DIR_PATH}/list_{now.strftime('%Y%m%d')}.csv.gz\"\n", - "if not os.path.isfile(list_file):\n", - " # 保存されているデータが存在しない場合はAPIからデータを取得します\n", - " df_list = jqapi.get_list()\n", - " # 取得したデータをファイルに保存します\n", - " df_list.to_csv(list_file, compression=\"gzip\", index=False)\n", - " print(f\"save file: {list_file}\")\n", - "\n", - "# ファイルからデータを読み込みます\n", - "print(f\"file exists: {list_file}, loading\")\n", - "df_list = pd.read_csv(list_file, dtype=\"str\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "Rr48lPutsU11" - }, - "outputs": [], - "source": [ - "# データを表示して取得できていることを確認します\n", - "df_list.tail(2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "MBPx33apuHXK" - }, - "outputs": [], - "source": [ - "# 市場区分別の銘柄数を把握します。\n", - "ax = df_list.groupby([\"MarketCode\", \"MarketCodeName\"]).size().reset_index().sort_values([0], ascending=False).rename(columns={0: \"銘柄数\"}).set_index(\"MarketCodeName\").plot(kind=\"bar\", figsize=(10, 10), grid=True)\n", - "# 棒グラフに数字を表記します\n", - "for p in ax.patches:\n", - " ax.annotate(str(p.get_height()), (p.get_x() * 1.005, p.get_height() * 1.005))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "PR-jaacasb3Y" - }, - "outputs": [], - "source": [ - "# セクター別の銘柄数を把握します。\n", - "ax = df_list.groupby([\"Sector33Code\", \"Sector33CodeName\"]).size().reset_index().set_index(\"Sector33CodeName\").sort_values(0, ascending=False).rename(columns={0: \"銘柄数\"}).plot(kind=\"bar\", figsize=(20, 8), grid=True)\n", - "# 棒グラフに数字を表記します\n", - "for p in ax.patches:\n", - " ax.annotate(str(p.get_height()), (p.get_x() * 1.005, p.get_height() * 1.005))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "qXNlF0iBQe8q" - }, - "outputs": [], - "source": [ - "%%time\n", - "# 株価情報を取得します (データ取得に約6分待ちます)\n", - "now = pd.Timestamp.now(tz=\"Asia/Tokyo\")\n", - "# 過去6ヶ月のデータを取得\n", - "start_dt = now - pd.Timedelta(190, unit=\"D\") # 計算用に10日分多めに指定しています\n", - "end_dt = now\n", - "if end_dt.hour < 18:\n", - " # データ更新時間前の場合は日付を1日ずらします。\n", - " end_dt -= pd.Timedelta(1, unit=\"D\")\n", - "price_file = f\"{STORAGE_DIR_PATH}/price_{start_dt.strftime('%Y%m%d')}_{end_dt.strftime('%Y%m%d')}.csv.gz\"\n", - "if not os.path.isfile(price_file):\n", - " df_p = jqapi.get_price_range(start_dt=start_dt, end_dt=end_dt)\n", - " df_p.to_csv(price_file, compression=\"gzip\", index=False)\n", - " print(f\"save file: {price_file}\")\n", - "\n", - "# データを読み込みます\n", - "print(f\"file exists: {price_file}, loading\")\n", - "df_p = pd.read_csv(price_file, dtype=\"str\")\n", - "df_p.reset_index(drop=True, inplace=True)\n", - "# 各列のデータ型を調整します\n", - "df_p.loc[:, \"Date\"] = pd.to_datetime(df_p[\"Date\"], format=\"%Y-%m-%d\")\n", - "df_p.loc[:, \"Open\"] = df_p[\"Open\"].astype(np.float64)\n", - "df_p.loc[:, \"High\"] = df_p[\"High\"].astype(np.float64)\n", - "df_p.loc[:, \"Low\"] = df_p[\"Low\"].astype(np.float64)\n", - "df_p.loc[:, \"Close\"] = df_p[\"Close\"].astype(np.float64)\n", - "df_p.loc[:, \"Volume\"] = df_p[\"Volume\"].astype(np.float64)\n", - "df_p.loc[:, \"TurnoverValue\"] = df_p[\"TurnoverValue\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentFactor\"] = df_p[\"AdjustmentFactor\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentOpen\"] = df_p[\"AdjustmentOpen\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentHigh\"] = df_p[\"AdjustmentHigh\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentLow\"] = df_p[\"AdjustmentLow\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentClose\"] = df_p[\"AdjustmentClose\"].astype(np.float64)\n", - "df_p.loc[:, \"AdjustmentVolume\"] = df_p[\"AdjustmentVolume\"].astype(np.float64)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "nPlcBVT0kWIO" - }, - "outputs": [], - "source": [ - "# 取得したデータを確認します\n", - "df_p.tail(2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "I-fpvU4EQiZp" - }, - "outputs": [], - "source": [ - "# 直近3ヶ月および6ヶ月のセクター別リターンをプロットします\n", - "\n", - "# データから最も古い日付を取得します\n", - "base_date = df_p[\"Date\"].min()\n", - "# データから最新日付を取得します\n", - "evaluation_date = df_p[\"Date\"].max()\n", - "# 6ヶ月前の日付を取得します\n", - "base_6months_date = df_p.loc[df_p[\"Date\"] <= (evaluation_date - pd.Timedelta(180, unit=\"D\")).to_datetime64(), \"Date\"].max()\n", - "# 3ヶ月前の日付を取得します\n", - "base_3months_date = df_p.loc[df_p[\"Date\"] <= (evaluation_date - pd.Timedelta(90, unit=\"D\")).to_datetime64(), \"Date\"].max()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "3iTMuqIpWAgz" - }, - "outputs": [], - "source": [ - "# 取引がなかった日付の終値には0が含まれていますがそのままでは計算しずらいため\n", - "# 終値が0の場合は前営業日の終値を使用します\n", - "df_p.sort_values([\"Code\", \"Date\"], inplace=True)\n", - "df_p[\"AdjustmentClose\"].replace({0.0: np.nan}, inplace=True)\n", - "df_p.loc[:, \"AdjustmentClose\"] = df_p.groupby(\"Code\")[\"AdjustmentClose\"].ffill()\n", - "# 終値がnanの場合は翌営業日の終値を使用します (データの先頭をフィルするため)\n", - "df_p.loc[:, \"AdjustmentClose\"] = df_p.groupby(\"Code\")[\"AdjustmentClose\"].bfill()\n", - "\n", - "\n", - "# 基準日の株価を取得します\n", - "filter_base_date = df_p[\"Date\"] == base_date\n", - "df_base = df_p.loc[filter_base_date]\n", - "\n", - "# 6ヶ月前の株価を取得します\n", - "filter_6months_date = df_p[\"Date\"] == base_6months_date\n", - "df_6months = df_p.loc[filter_6months_date]\n", - "\n", - "# 3ヶ月前の株価を取得します\n", - "filter_3months_date = df_p[\"Date\"] == base_3months_date\n", - "df_3months = df_p.loc[filter_3months_date]\n", - "\n", - "# 評価日の株価を取得します\n", - "filter_eval_date = df_p[\"Date\"] == evaluation_date\n", - "df_eval = df_p.loc[filter_eval_date]\n", - "\n", - "# データを結合する際に必要なカラムを指定します\n", - "cols = [\"Code\", \"Date\", \"AdjustmentClose\"]\n", - "\n", - "# 評価日の株価をベースに作業します\n", - "df_work = df_eval[cols]\n", - "# 基準日の株価と結合します\n", - "df_work = pd.merge(df_work, df_base[cols], on=[\"Code\"], how=\"left\", suffixes=(\"\", \"_base\"))\n", - "# 6ヶ月前の株価と結合します\n", - "df_work = pd.merge(df_work, df_6months[cols], on=[\"Code\"], how=\"left\", suffixes=(\"\", \"_6months\"))\n", - "# 3ヶ月前の株価と結合します\n", - "df_work = pd.merge(df_work, df_3months[cols], on=[\"Code\"], how=\"left\", suffixes=(\"\", \"_3months\"))\n", - "\n", - "# 6ヶ月間のリターンを算出します\n", - "df_work[\"return_6months\"] = ((df_work[\"AdjustmentClose\"] / df_work[\"AdjustmentClose_6months\"]) - 1) * 100\n", - "# 3ヶ月間のリターンを算出します\n", - "df_work[\"return_3months\"] = ((df_work[\"AdjustmentClose\"] / df_work[\"AdjustmentClose_3months\"]) - 1) * 100\n", - "\n", - "# 月末営業日を取得します\n", - "eoms = df_p.groupby(pd.Grouper(key=\"Date\", freq=\"M\")).apply(lambda df: df[\"Date\"].max()).tolist()\n", - "# 月末の株価と結合してリターンを算出します\n", - "prev_ym = eoms[0].strftime(\"%Y%m\")\n", - "for i, eom in enumerate(eoms):\n", - " ym = eom.strftime(\"%Y%m\")\n", - " filter_eom = df_p[\"Date\"] == eom\n", - " df = df_p.loc[filter_eom]\n", - " df_work = pd.merge(df_work, df[cols], on=[\"Code\"], how=\"left\", suffixes=(\"\", f\"_{ym}\"))\n", - " if i != 0:\n", - " df_work[f\"return_monthly_{ym}\"] = ((df_work[f\"AdjustmentClose_{ym}\"] / df_work[f\"AdjustmentClose_{prev_ym}\"]) - 1) * 100\n", - " prev_ym = ym\n", - "\n", - "# セクター情報と結合します\n", - "df_work = pd.merge(df_work, df_list[[\"Code\", \"Sector33Code\", \"Sector33CodeName\", \"MarketCode\"]], on=[\"Code\"])\n", - "\n", - "# プライム銘柄に絞り込みます\n", - "df_work = df_work.loc[df_work[\"MarketCode\"] == \"0111\"]\n", - "\n", - "# 6ヶ月、3ヶ月、および基準日を出力します\n", - "display(base_6months_date, base_3months_date, evaluation_date)\n", - "\n", - "# セクター別のリターンをプロットします\n", - "df_work.groupby(\"Sector33CodeName\")[\"return_6months\", \"return_3months\"].mean().sort_values(\"return_6months\", ascending=False).plot(kind=\"bar\", figsize=(20, 8), grid=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "xqmDCy_gqaoT" - }, - "outputs": [], - "source": [ - "# 月毎のリターンの項目名を取得します\n", - "monthly_cols = sorted([c for c in df_work.columns if c.startswith(\"return_monthly_\")])\n", - "# セクター別のリターンを算出します\n", - "df_monthly = df_work.groupby(\"Sector33CodeName\")[monthly_cols].mean()\n", - "# セクター別のリターンを月毎に表示します (最新月は月初から当日までのリターンになっています)\n", - "df_monthly.sort_values(monthly_cols[-1], ascending=False).style.background_gradient(cmap=\"RdYlGn\", axis=0)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "L5A1rYDKBnOM" - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 3", - "name": "python3" - }, - "language_info": { - "name": "python" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/examples/20220825-003-dividend.ipynb b/examples/20220825-003-dividend.ipynb deleted file mode 100644 index 44de27d..0000000 --- a/examples/20220825-003-dividend.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"cells":[{"cell_type":"markdown","metadata":{"id":"OtR4VmnRshQX"},"source":["# 配当利回り\n","\n","[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20220825-003-dividend.ipynb)\n","\n","\n","このノートブックでは J-Quants APIから取得できるデータから配当性向、配当利回り、および直近1,3ヶ月のリターンを一覧で表示します。\n","\n","\n","----\n","\n","**このノートブックはGoogle Driveを使用します。**\n","\n","- Google Drive の以下のファイルにリフレッシュトークンが書き込まれていることを想定しています。\n"," - `MyDrive/drive_ws/secret/jquantsapi-key.txt`\n","- Google Drive の以下のフォルダーにデータを書き込みます。\n"," - `MyDrive/drive_ws/marketdata`"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"9REtVkPaGx7Y"},"outputs":[],"source":["# 必要なモジュールをインストールします。\n","! python -m pip install jquants-api-client japanize-matplotlib"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"ilrdZjP4KknF"},"outputs":[],"source":["# Google drive をマウントします。\n","from google.colab import drive\n","drive.mount('/content/drive')"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"A5fW3HxGN__3"},"outputs":[],"source":["import os\n","from datetime import datetime\n","\n","import japanize_matplotlib\n","import jquantsapi\n","import matplotlib.pyplot as plt\n","import numpy as np\n","import pandas as pd\n","import seaborn as sns"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"3CeWabhlOGE4"},"outputs":[],"source":["# pandas の表示制限を調整します\n","pd.set_option(\"display.max_rows\", 1000)\n","pd.set_option(\"display.max_columns\", 1000)\n","pd.set_option(\"display.width\", 2000)"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"8JRXB-JIQnDg"},"outputs":[],"source":["# プロット用の設定をします\n","sns.set(rc={'figure.figsize': (15, 10)})\n","sns.set(font_scale=1.5)\n","sns.set_style('whitegrid')\n","\n","japanize_matplotlib.japanize()"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"fSG_cbO7Qm4x"},"outputs":[],"source":["# 一度取得したデータは Google Drive 上に保存して再利用します。\n","# 保存先ディレクトリを指定します。\n","STORAGE_DIR_PATH = \"/content/drive/MyDrive/drive_ws/marketdata\"\n","os.makedirs(STORAGE_DIR_PATH, exist_ok=True)\n","STORAGE_DIR_PATH"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"fIRnvS9kOOqI"},"outputs":[],"source":["# J-Quants APIのトークンを保存してあるファイルを指定します\n","REFRESH_TOKEN_FILE_PATH = \"/content/drive/MyDrive/drive_ws/secret/jquantsapi-key.txt\""]},{"cell_type":"code","execution_count":null,"metadata":{"id":"dHm6w6O_QUnS"},"outputs":[],"source":["def get_refresh_token(refresh_token_file_path: str = REFRESH_TOKEN_FILE_PATH):\n"," with open(refresh_token_file_path, \"r\") as f:\n"," refresh_token = f.read()\n"," return refresh_token.rstrip().lstrip()"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"9Ts2dfaRQV9C"},"outputs":[],"source":["# ファイルからリフレッシュトークンを読み込みます\n","refresh_token = get_refresh_token()"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"7ZH_LuWUQYk8"},"outputs":[],"source":["# J-Quants APIクライアントを初期化します\n","jqapi = jquantsapi.Client(refresh_token=refresh_token)"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"2KkfboPHsYd9"},"outputs":[],"source":["# 銘柄情報を取得します\n","now = pd.Timestamp.now(tz=\"Asia/Tokyo\")\n","\n","list_file = f\"{STORAGE_DIR_PATH}/list_{now.strftime('%Y%m%d')}.csv.gz\"\n","if not os.path.isfile(list_file):\n"," df_list = jqapi.get_list()\n"," df_list.to_csv(list_file, compression=\"gzip\", index=False)\n"," print(f\"save file: {list_file}\")\n","\n","# ファイルからデータを読み込みます\n","print(f\"file exists: {list_file}, loading\")\n","df_list = pd.read_csv(list_file, dtype=\"str\")"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"xH2PYF0ENVYa"},"outputs":[],"source":["# 株価情報を取得します\n","now = pd.Timestamp.now(tz=\"Asia/Tokyo\")\n","# 過去3ヶ月のデータを取得\n","start_dt = now - pd.Timedelta(95, unit=\"D\")\n","end_dt = now\n","if end_dt.hour < 18:\n"," # データ更新時間前の場合は日付を1日ずらします。\n"," end_dt -= pd.Timedelta(1, unit=\"D\")\n","price_file = f\"{STORAGE_DIR_PATH}/price_{start_dt.strftime('%Y%m%d')}_{end_dt.strftime('%Y%m%d')}.csv.gz\"\n","if not os.path.isfile(price_file):\n"," df_p = jqapi.get_price_range(start_dt=start_dt, end_dt=end_dt)\n"," df_p.to_csv(price_file, compression=\"gzip\", index=False)\n"," df_p.reset_index(drop=True, inplace=True)\n"," print(f\"save file: {price_file}\")\n","\n","# データを読み込みます\n","print(f\"file exists: {price_file}, loading\")\n","df_p = pd.read_csv(price_file, dtype=\"str\")\n","df_p.reset_index(drop=True, inplace=True)\n","# 各列のデータ型を調整します\n","df_p.loc[:, \"Date\"] = pd.to_datetime(df_p[\"Date\"], format=\"%Y-%m-%d\")\n","df_p.loc[:, \"Open\"] = df_p[\"Open\"].astype(np.float64)\n","df_p.loc[:, \"High\"] = df_p[\"High\"].astype(np.float64)\n","df_p.loc[:, \"Low\"] = df_p[\"Low\"].astype(np.float64)\n","df_p.loc[:, \"Close\"] = df_p[\"Close\"].astype(np.float64)\n","df_p.loc[:, \"Volume\"] = df_p[\"Volume\"].astype(np.float64)\n","df_p.loc[:, \"TurnoverValue\"] = df_p[\"TurnoverValue\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentFactor\"] = df_p[\"AdjustmentFactor\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentOpen\"] = df_p[\"AdjustmentOpen\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentHigh\"] = df_p[\"AdjustmentHigh\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentLow\"] = df_p[\"AdjustmentLow\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentClose\"] = df_p[\"AdjustmentClose\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentVolume\"] = df_p[\"AdjustmentVolume\"].astype(np.float64)"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"dzZL0Krs2gUe"},"outputs":[],"source":["# 過去3ヶ月に発表された財務情報を取得します\n","now = pd.Timestamp.now(tz=\"Asia/Tokyo\")\n","start_dt = now - pd.Timedelta(90, unit=\"D\")\n","end_dt = now\n","if end_dt.hour < 1:\n"," # データ更新時間前の場合は日付を1日ずらします。\n"," end_dt -= pd.Timedelta(1, unit=\"D\")\n","statements_file = f\"{STORAGE_DIR_PATH}/statements_{start_dt.strftime('%Y%m%d')}_{end_dt.strftime('%Y%m%d')}.csv.gz\"\n","if not os.path.isfile(statements_file):\n"," cache_dir = f\"{STORAGE_DIR_PATH}/raw_statements\"\n"," os.makedirs(cache_dir, exist_ok=True)\n"," df_s = jqapi.get_statements_range(\n"," start_dt=start_dt, end_dt=end_dt, cache_dir=cache_dir\n"," )\n"," df_s.to_csv(statements_file, compression=\"gzip\", index=False)\n"," print(f\"save file: {statements_file}\")\n","\n","print(f\"file exists: {statements_file}, loading\")\n","df_s = pd.read_csv(statements_file, dtype=\"str\")\n","# float64にするために\"-\"をnp.nanに置き換えます\n","df_s.replace({\"-\": np.nan}, inplace=True)\n","df_s[\"ResultDividendPerShareFiscalYearEnd\"] = df_s[\"ResultDividendPerShareFiscalYearEnd\"].astype(np.float64)\n","df_s[\"EarningsPerShare\"] = df_s[\"EarningsPerShare\"].astype(np.float64)\n","df_s[\"ForecastDividendPerShareAnnual\"] = df_s[\"ForecastDividendPerShareAnnual\"].astype(np.float64)\n","df_s[\"ForecastEarningsPerShare\"] = df_s[\"ForecastEarningsPerShare\"].astype(np.float64)\n","# 日付型に変換します\n","df_s.loc[:, \"DisclosedDate\"] = pd.to_datetime(\n"," df_s[\"DisclosedDate\"], format=\"%Y-%m-%d\"\n",")\n","df_s.loc[:, \"CurrentPeriodEndDate\"] = pd.to_datetime(\n"," df_s[\"CurrentPeriodEndDate\"], format=\"%Y-%m-%d\"\n",")\n","df_s.loc[:, \"CurrentFiscalYearStartDate\"] = pd.to_datetime(\n"," df_s[\"CurrentFiscalYearStartDate\"], format=\"%Y-%m-%d\"\n",")\n","df_s.loc[:, \"CurrentFiscalYearEndDate\"] = pd.to_datetime(\n"," df_s[\"CurrentFiscalYearEndDate\"], format=\"%Y-%m-%d\"\n",")\n","df_s.sort_values([\"DisclosedDate\", \"DisclosedTime\"], inplace=True)"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"dtWhPh-_oMmt"},"outputs":[],"source":["# 作業用にデータをコピーします\n","df_work = df_s.copy()\n","df_p_work = df_p.copy()"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"bkbOMxaIOSVc"},"outputs":[],"source":["# 財務情報を銘柄ごとに重複を排除して最新の財務情報のみを使用します\n","df_work.sort_values([\"DisclosedDate\", \"DisclosedTime\"], inplace=True)\n","df_work = df_work.drop_duplicates([\"LocalCode\"], keep=\"last\")\n","\n","# 終値が0の場合は前営業日の終値を使用します\n","df_p_work.sort_values([\"Code\", \"Date\"], inplace=True)\n","df_p_work[\"AdjustmentClose\"].replace({0.0: np.nan}, inplace=True)\n","df_p_work.loc[:, \"AdjustmentClose\"] = df_p_work.groupby(\"Code\")[\"AdjustmentClose\"].ffill()\n","# 終値がnanの場合は翌営業日の終値を使用します (データの先頭)\n","df_p_work.loc[:, \"AdjustmentClose\"] = df_p_work.groupby(\"Code\")[\"AdjustmentClose\"].bfill()\n","# 各銘柄の直近のリターンを算出します\n","def _calc_return(df, bdays):\n"," return (df[\"AdjustmentClose\"].iat[-1] / df[\"AdjustmentClose\"].iloc[-bdays:].iat[0]) - 1\n","df_p_work.sort_values([\"Code\", \"Date\"], inplace=True)\n","df_returns_1months = df_p_work.groupby(\"Code\").apply(_calc_return, 20).rename(\"1ヶ月リターン\")\n","df_returns_3months = df_p_work.groupby(\"Code\").apply(_calc_return, 60).rename(\"3ヶ月リターン\")\n","# リターンと結合します\n","df_work = pd.merge(df_work, df_returns_1months, left_on=[\"LocalCode\"], right_index=True, how=\"left\")\n","df_work = pd.merge(df_work, df_returns_3months, left_on=[\"LocalCode\"], right_index=True, how=\"left\")\n","\n","# 配当利回りを計算するために直近の終値を取得します\n","df_close = df_p_work.loc[df_p_work[\"Date\"] == df_p_work[\"Date\"].max(), [\"Code\", \"Date\", \"AdjustmentClose\"]]\n","# 直近の株価と結合します\n","df_work = pd.merge(df_work, df_close, left_on=[\"LocalCode\"], right_on=[\"Code\"], how=\"left\")\n","# 配当利回りを算出します\n","df_work[\"配当利回り\"] = df_work[\"ResultDividendPerShareFiscalYearEnd\"] / df_work[\"AdjustmentClose\"]\n","# 予想配当利回りを算出します\n","df_work[\"予想配当利回り\"] = df_work[\"ForecastDividendPerShareAnnual\"] / df_work[\"AdjustmentClose\"]\n","\n","# 配当性向を算出します\n","df_work[\"配当性向\"] = df_work[\"ResultDividendPerShareFiscalYearEnd\"] / df_work[\"EarningsPerShare\"] \n","# 予想配当性向を算出します\n","df_work[\"予想配当性向\"] = df_work[\"ForecastDividendPerShareAnnual\"] / df_work[\"ForecastEarningsPerShare\"]\n","\n","# 銘柄名と結合します\n","df_work = pd.merge(df_work, df_list, left_on=[\"LocalCode\"], right_on=[\"Code\"])\n","\n","# 表示用に開示日を追加します\n","df_work[\"開示日\"] = df_work[\"DisclosedDate\"].dt.strftime(\"%Y-%m-%d\")"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"3jmgsVicS_tZ"},"outputs":[],"source":["# 表示する項目を指定します\n","output_cols = [\n"," \"LocalCode\",\n"," \"CompanyName\",\n"," \"開示日\",\n"," \"配当性向\",\n"," \"予想配当性向\",\n"," \"配当利回り\",\n"," \"予想配当利回り\",\n"," \"1ヶ月リターン\",\n"," \"3ヶ月リターン\",\n","]\n","# 項目別に表示方法を指定します\n","output_format = {\n"," \"配当性向\": \"{:.2%}\",\n"," \"予想配当性向\": \"{:.2%}\",\n"," \"配当利回り\": \"{:.2%}\",\n"," \"予想配当利回り\": \"{:.2%}\",\n"," \"1ヶ月リターン\": \"{:.2%}\",\n"," \"3ヶ月リターン\": \"{:.2%}\",\n","}"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"X8rQDWRypNgr"},"outputs":[],"source":["# 配当利回り順に上位20銘柄を表示します\n","df_work.sort_values([\"配当利回り\"], ascending=False)[output_cols].head(20).style.format(output_format)"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"-Dki6S63rzhz"},"outputs":[],"source":["# 予想配当利回り順に上位20銘柄を表示します\n","df_work.sort_values([\"予想配当利回り\"], ascending=False)[output_cols].head(20).style.format(output_format)"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"FcI-7y7tpLG5"},"outputs":[],"source":["# 横軸に配当利回り、縦軸に1,3ヶ月リターンとして関係性をプロットします\n","display(\"1ヶ月リターン\")\n","sns.jointplot(x='配当利回り', y='1ヶ月リターン', data=df_work.loc[df_work[\"配当利回り\"] > 0.00], kind=\"reg\")\n","plt.show()\n","\n","display(\"3ヶ月リターン\")\n","sns.jointplot(x='配当利回り', y='3ヶ月リターン', data=df_work.loc[df_work[\"配当利回り\"] > 0.00], kind=\"reg\")\n","plt.show()"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"iTJu84Hi5iZ3"},"outputs":[],"source":["# 横軸に予想配当利回り、縦軸に1,3,6ヶ月リターンとして関係性をプロットします\n","display(\"1ヶ月リターン\")\n","sns.jointplot(x='予想配当利回り', y='1ヶ月リターン', data=df_work.loc[df_work[\"予想配当利回り\"] > 0.00], kind=\"reg\")\n","plt.show()\n","\n","display(\"3ヶ月リターン\")\n","sns.jointplot(x='予想配当利回り', y='3ヶ月リターン', data=df_work.loc[df_work[\"予想配当利回り\"] > 0.00], kind=\"reg\")\n","plt.show()"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"TiOy1x0fk40B"},"outputs":[],"source":["# 予想配当利回りが5%以上の銘柄とリターンの関係性をプロットします\n","display(\"1ヶ月リターン\")\n","sns.jointplot(x='予想配当利回り', y='1ヶ月リターン', data=df_work.loc[df_work[\"予想配当利回り\"] >= 0.05], kind=\"reg\")\n","plt.show()\n","\n","display(\"3ヶ月リターン\")\n","sns.jointplot(x='予想配当利回り', y='3ヶ月リターン', data=df_work.loc[df_work[\"予想配当利回り\"] >= 0.05], kind=\"reg\")\n","plt.show()"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"jUJ68lwLxdSd"},"outputs":[],"source":[]}],"metadata":{"colab":{"authorship_tag":"ABX9TyOqKO9mZDov80L8FnzwcklK","collapsed_sections":[],"name":"20220825-003-dividend.ipynb","provenance":[]},"kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python"}},"nbformat":4,"nbformat_minor":0} diff --git a/examples/20220825-004-annual-dividend-history.ipynb b/examples/20220825-004-annual-dividend-history.ipynb deleted file mode 100644 index b4d5ee7..0000000 --- a/examples/20220825-004-annual-dividend-history.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"cells":[{"cell_type":"markdown","metadata":{"id":"OtR4VmnRshQX"},"source":["# 年間配当額の推移\n","\n","[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20220825-004-annual-dividend-history.ipynb)\n","\n","このノートブックでは J-Quants APIから取得できるデータを利用して特定銘柄についての年間配当額の推移を表示します。\n","\n","\n","----\n","\n","**このノートブックはGoogle Driveを使用します。**\n","\n","- Google Drive の以下のファイルにリフレッシュトークンが書き込まれていることを想定しています。\n"," - `MyDrive/drive_ws/secret/jquantsapi-key.txt`"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"uFa-kSGyDhpY"},"outputs":[],"source":["# 年間配当額の推移を表示する銘柄コードを指定します (e.g. 8697)\n","TARGET_SYMBOL = \"8697\" # 日本取引所グループ"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"9REtVkPaGx7Y"},"outputs":[],"source":["# 必要なモジュールをインストールします。\n","! python -m pip install jquants-api-client japanize-matplotlib mplfinance"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"ilrdZjP4KknF"},"outputs":[],"source":["# Google drive をマウントします。\n","from google.colab import drive\n","drive.mount('/content/drive')"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"A5fW3HxGN__3"},"outputs":[],"source":["import os\n","from datetime import datetime\n","\n","import japanize_matplotlib\n","import jquantsapi\n","import mplfinance as mpf\n","import matplotlib.pyplot as plt\n","import numpy as np\n","import pandas as pd\n","import seaborn as sns"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"3CeWabhlOGE4"},"outputs":[],"source":["# pandas の表示制限を調整します\n","pd.set_option(\"display.max_rows\", 1000)\n","pd.set_option(\"display.max_columns\", 1000)\n","pd.set_option(\"display.width\", 2000)"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"8JRXB-JIQnDg"},"outputs":[],"source":["# プロット用の設定をします\n","sns.set(rc={'figure.figsize': (15, 10)})\n","sns.set(font_scale=1.5)\n","sns.set_style('whitegrid')\n","\n","japanize_matplotlib.japanize()"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# 銘柄コードが4桁で指定されていた場合は末尾に0を付与します\n","if len(TARGET_SYMBOL) == 4:\n"," TARGET_SYMBOL += \"0\""]},{"cell_type":"code","execution_count":null,"metadata":{"id":"fIRnvS9kOOqI"},"outputs":[],"source":["# J-Quants APIのトークンを保存してあるファイルを指定します\n","REFRESH_TOKEN_FILE_PATH = \"/content/drive/MyDrive/drive_ws/secret/jquantsapi-key.txt\""]},{"cell_type":"code","execution_count":null,"metadata":{"id":"dHm6w6O_QUnS"},"outputs":[],"source":["def get_refresh_token(refresh_token_file_path: str = REFRESH_TOKEN_FILE_PATH):\n"," with open(refresh_token_file_path, \"r\") as f:\n"," refresh_token = f.read()\n"," return refresh_token.rstrip().lstrip()"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"9Ts2dfaRQV9C"},"outputs":[],"source":["# ファイルからリフレッシュトークンを読み込みます\n","refresh_token = get_refresh_token()"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"7ZH_LuWUQYk8"},"outputs":[],"source":["# J-Quants APIクライアントを初期化します\n","jqapi = jquantsapi.Client(refresh_token=refresh_token)"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"2KkfboPHsYd9"},"outputs":[],"source":["# 銘柄情報を取得します\n","df_list = jqapi.get_list()"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# 対象銘柄の株価情報を取得します\n","df_p_org = jqapi.get_prices_daily_quotes(code=TARGET_SYMBOL)"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# 作業用にコピーします\n","df_p = df_p_org.copy()\n","\n","# 各列のデータ型を調整します\n","df_p.loc[:, \"Date\"] = pd.to_datetime(df_p[\"Date\"], format=\"%Y-%m-%d\")\n","df_p.loc[:, \"Open\"] = df_p[\"Open\"].astype(np.float64)\n","df_p.loc[:, \"High\"] = df_p[\"High\"].astype(np.float64)\n","df_p.loc[:, \"Low\"] = df_p[\"Low\"].astype(np.float64)\n","df_p.loc[:, \"Close\"] = df_p[\"Close\"].astype(np.float64)\n","df_p.loc[:, \"Volume\"] = df_p[\"Volume\"].astype(np.float64)\n","df_p.loc[:, \"TurnoverValue\"] = df_p[\"TurnoverValue\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentFactor\"] = df_p[\"AdjustmentFactor\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentOpen\"] = df_p[\"AdjustmentOpen\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentHigh\"] = df_p[\"AdjustmentHigh\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentLow\"] = df_p[\"AdjustmentLow\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentClose\"] = df_p[\"AdjustmentClose\"].astype(np.float64)\n","df_p.loc[:, \"AdjustmentVolume\"] = df_p[\"AdjustmentVolume\"].astype(np.float64)\n","# 株価が0のレコードを除外します\n","df_p = df_p.replace({0.0: np.nan}).dropna()\n","# 月足のOHLCVを作成します\n","df_p_m_ohlc = df_p.set_index(\"Date\")[[\n"," \"AdjustmentOpen\",\n"," \"AdjustmentHigh\",\n"," \"AdjustmentLow\",\n"," \"AdjustmentClose\",\n"," \"AdjustmentVolume\"\n","]].rename(columns={\n"," \"AdjustmentOpen\": \"Open\",\n"," \"AdjustmentHigh\": \"High\",\n"," \"AdjustmentLow\": \"Low\",\n"," \"AdjustmentClose\": \"Close\",\n"," \"AdjustmentVolume\": \"Volume\",\n","}).resample(\"M\").agg({\"Open\": \"first\", \"High\": \"max\", \"Low\": \"min\", \"Close\": \"last\", \"Volume\": \"sum\"})"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"2lVEBIjaElfr"},"outputs":[],"source":["# 対象銘柄の財務情報を取得します\n","df_s_org = jqapi.get_fins_statements(code=TARGET_SYMBOL)"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"kd9nlfs4GE6Y"},"outputs":[],"source":["# 作業用にコピーします\n","df_s = df_s_org.copy()\n","\n","# 年度末情報に絞り込みます\n","df_s = df_s.loc[df_s[\"TypeOfCurrentPeriod\"] == \"FY\"]\n","# float64にするために\"-\"および\"\"をnp.nanに置き換えます\n","df_s.replace({\"-\": np.nan, \"\": np.nan}, inplace=True)\n","df_s.loc[:, \"ResultDividendPerShareAnnual\"] = df_s[\"ResultDividendPerShareAnnual\"].astype(np.float64)\n","df_s.loc[:, \"ForecastDividendPerShareAnnual\"] = df_s[\"ForecastDividendPerShareAnnual\"].astype(np.float64)\n","df_s.loc[:, \"EarningsPerShare\"] = df_s[\"EarningsPerShare\"].astype(np.float64)\n","\n","# 日付型に変換します\n","df_s.loc[:, \"DisclosedDate\"] = pd.to_datetime(\n"," df_s[\"DisclosedDate\"], format=\"%Y-%m-%d\"\n",")\n","df_s.loc[:, \"CurrentPeriodEndDate\"] = pd.to_datetime(\n"," df_s[\"CurrentPeriodEndDate\"], format=\"%Y-%m-%d\"\n",")\n","df_s.loc[:, \"CurrentFiscalYearStartDate\"] = pd.to_datetime(\n"," df_s[\"CurrentFiscalYearStartDate\"], format=\"%Y-%m-%d\"\n",")\n","df_s.loc[:, \"CurrentFiscalYearEndDate\"] = pd.to_datetime(\n"," df_s[\"CurrentFiscalYearEndDate\"], format=\"%Y-%m-%d\"\n",")\n","# 開示順に並べ替えます\n","df_s.sort_values([\"DisclosedDate\", \"DisclosedTime\"], inplace=True)\n","\n","# 配当性向を算出します\n","df_s[\"配当性向\"] = df_s[\"ResultDividendPerShareAnnual\"] / df_s[\"EarningsPerShare\"]"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"Zn61xoi4H5cB"},"outputs":[],"source":["# プロット用に配当額が存在するレコードのみに絞り込みます\n","df_plot = df_s.loc[df_s[\"ResultDividendPerShareAnnual\"].notna()].set_index(\"DisclosedDate\")\n","# インデックスの表記を変更します\n","df_plot.index = df_plot.index.strftime(\"%Y-%m-%d\")\n","\n","# 項目名を日本語にします\n","df_plot.index.name = \"開示日\"\n","df_plot.rename(columns={\n"," \"ResultDividendPerShareAnnual\": \"配当実績_合計\",\n"," \"EarningsPerShare\": \"1株当たり当期純利益\",\n","}, inplace=True)\n","\n","# 配当額と1株あたり利益をプロットします\n","ax = df_plot[[\"配当実績_合計\", \"1株当たり当期純利益\"]].plot(kind=\"bar\")\n","# 配当性向をプロットします\n","bx = df_plot[[\"配当性向\"]].plot(linestyle='-', marker='o', ax=ax, use_index=False, secondary_y=True, color=\"black\")\n","\n","# 棒グラフに数字を表記します\n","for p in ax.patches:\n"," ax.annotate(str(p.get_height()), (p.get_x() * 1.005, p.get_height() * 1.005))\n","\n","# 銘柄名を取得します\n","name = df_list.loc[df_list[\"Code\"] == TARGET_SYMBOL, \"CompanyName\"].iat[0]\n","\n","# タイトルを設定します\n","ax.set_title(f\"{name}({TARGET_SYMBOL}) の年間配当推移\")"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"0HlF2Zt1oOa5"},"outputs":[],"source":["# 株価の推移を月足で表示します\n","df_s[\"DisclosedDate\"] = pd.to_datetime(df_s[\"DisclosedDate\"])\n","df_plot = df_s.loc[df_s[\"ResultDividendPerShareAnnual\"].notna()].set_index(\"DisclosedDate\")\n","\n","mpf.plot(\n"," df_p_m_ohlc,\n"," type=\"candle\",\n"," volume=True,\n"," figsize=(20, 8),\n"," vlines={\"vlines\": df_plot.index[df_plot.index > df_p_m_ohlc.index[0]].tolist(), \"colors\": \"r\"}\n",")"]}],"metadata":{"colab":{"authorship_tag":"ABX9TyNWA57glz6LYpEP81RTb3Sf","collapsed_sections":[],"name":"20220825-004-annual-dividend-history.ipynb","provenance":[]},"kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python"}},"nbformat":4,"nbformat_minor":0} diff --git a/examples/20220927-005-jquants-api-starter.ipynb b/examples/20220927-005-jquants-api-starter.ipynb deleted file mode 100644 index 6e0c907..0000000 --- a/examples/20220927-005-jquants-api-starter.ipynb +++ /dev/null @@ -1,1444 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "source": [ - "# 本日の概要\n", - "- 本日話すこと\n", - " - J-Quants APIの利用の仕方\n", - " - J-Quants APIを利用した簡単なデータ分析\n", - "\n", - "- 本日話さないこと\n", - " - ゴリゴリのデータ分析\n", - " - データ分析を利用した投資・投資手法の紹介等\n", - "\n", - "\n", - "プログラミング初心者の方や、これからデータ分析を始める方向けに、 \n", - "コードも交えてJ-Quants APIの利用方法について紹介させていただきます!!" - ], - "metadata": { - "id": "KkNXT7iUBckP" - } - }, - { - "cell_type": "markdown", - "source": [ - "# J-QuantsAPIについて" - ], - "metadata": { - "id": "ZOgNFJtEY1g9" - } - }, - { - "cell_type": "markdown", - "source": [ - "## J-Quants APIの利用の仕方" - ], - "metadata": { - "id": "IAkAWwXhWLjM" - } - }, - { - "cell_type": "markdown", - "source": [ - "\n", - "\n", - "1. [APIサービス登録ページ](https://jpx-jquants.com/auth/signup)よりJ-Quants APIサービスへ登録\n", - "\n", - "2. 登録後、[ログインページ](https://jpx-jquants.com/auth/signin)から登録したメールアドレス及びパスワードでJ-Quants APIサービスへログインしリフレッシュトークンを取得(取得ボタンを押下すると、自動的にクリップボードへコピーされます)\n", - "3. CurlコマンドやPython等を用いて、リフレッシュトークンを利用し、ID tokenを取得\n", - "4. CurlコマンドやPython等を用いて、取得したID tokenを利用し、データを取得\n", - "\n", - "なお、J-Quants APIの各種APIの仕様は[こちら](https://jpx.gitbook.io/j-quants-ja/api-reference)をご参照ください。" - ], - "metadata": { - "id": "wWXM0pB9WQuu" - } - }, - { - "cell_type": "code", - "source": [ - "#@title 上記3. について、pythonによるID token取得サンプル\n", - "import requests\n", - "import json\n", - "\n", - "REFRESH_TOKEN = \"こちらにクリップボードにコピーしたリフレッシュトークンを貼り付け\"\n", - "idToken = requests.post(\n", - " f\"https://api.jquants.com/v1/token/auth_refresh?refreshtoken={REFRESH_TOKEN}\"\n", - ").json()[\"idToken\"]\n" - ], - "metadata": { - "id": "dZQEHU8rfatx" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "#@title 上記4.について、 pythonによるデータ取得サンプル(銘柄情報)\n", - "# 上記3.idTokenを取得していることが前提です\n", - "headers = {'Authorization': 'Bearer {}'.format(idToken)}\n", - "r = requests.get(\"https://api.jquants.com/v1/listed/info\", headers=headers)\n", - "\n", - "# APIからのresponseはjson形式\n", - "info_data = r.json()[\"info\"]\n", - "\n", - "# 取得したデータを5つ表示\n", - "info_data[:5]\n" - ], - "metadata": { - "id": "kv7PjrZRgcK2" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## J-Quants API各種クライアントライブラリ" - ], - "metadata": { - "id": "vf6qvLBOhbTJ" - } - }, - { - "cell_type": "markdown", - "source": [ - "J-Quants APIにはより使いやすくなるように、クライアントライブラリをalpacaさんや有志の方に作製いただいております! \n", - "作製いただいた方ありがとうございます!!\n", - "\n", - "\n", - "\n", - "* Python用クライアントライブラリ( [jquants-api-client-python](https://github.com/J-Quants/jquants-api-client-python) ) (有償版対応済)\n", - "\n", - "* R用クライアントライブラリ( [JQuantsR](https://github.com/J-Quants/JQuantsR) ) (有償版対応済)\n", - "\n", - "今回はPythonを用いるため、Python用クライアントライブラリを利用します。" - ], - "metadata": { - "id": "vkr4V7Mohtxg" - } - }, - { - "cell_type": "code", - "source": [ - "# Google Colabでjquants-api-client-pythonを使えるようにインストール\n", - "!pip install jquants-api-client\n" - ], - "metadata": { - "id": "h-WxFL-coL4K" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# Google Driveをマウント\n", - "from google.colab import drive\n", - "drive.mount('/content/drive')\n" - ], - "metadata": { - "id": "T8W0O5yFWT5f" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "Driveをマウント後、[こちら](https://github.com/J-Quants/jquants-api-client-python#%E8%A8%AD%E5%AE%9A)を参考にAPI利用のための設定ファイル(jquants-api.toml)を作成します。\n", - "\n", - "この設定を行うことで、jquantsapiパッケージを利用し、リフレッシュトークン及びtokenIDを自動で取得してくれます!!" - ], - "metadata": { - "id": "xO8LOJBHE1qn" - } - }, - { - "cell_type": "code", - "source": [ - "import requests\n", - "import json\n", - "import pandas as pd\n", - "import plotly.express as px\n", - "import plotly.graph_objects as go\n", - "from plotly.subplots import make_subplots\n", - "from datetime import datetime, timedelta\n", - "import warnings\n", - "\n", - "import jquantsapi\n", - "\n", - "# pandasデータフレームの描画設定\n", - "pd.set_option(\"display.max_columns\", None)\n", - "pd.set_option(\"display.max_rows\", 40)\n", - "pd.set_option(\"display.max_colwidth\", 80)\n", - "\n", - "warnings.simplefilter('ignore')\n", - "\n", - "# 今回はID及びPWは上記に記載の方法により別ファイルに保存しているため、引数特になしでOK。\n", - "cli = jquantsapi.Client()\n", - "\n", - "# 以下のように直接引数として渡してもOKですが、メールアドレスとパスワードが平文でnotebookに残るため、別で設定ファイルを作成したほうが安全です。\n", - "# cli = jquantsapi.Client(mail_address=\"ご登録いただいたメールアドレス\", password=\"ご登録いただいたパスワード\")\n" - ], - "metadata": { - "id": "HCJbxQLxoYWB" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 試しに銘柄情報を取得\n", - "cli.get_listed_info()" - ], - "metadata": { - "id": "aoraqfriWfws" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "その他、jquants-api-clientで利用できるものは[こちらの説明](https://github.com/J-Quants/jquants-api-client-python#%E5%AF%BE%E5%BF%9Capi)をご参照ください。\n" - ], - "metadata": { - "id": "dJvtf_UoXJWC" - } - }, - { - "cell_type": "markdown", - "source": [ - "# 銘柄一覧情報 API(毎営業日の21時頃データ更新)\n", - "\n", - "銘柄情報は、東京証券取引所へ上場している銘柄について提供しています。" - ], - "metadata": { - "id": "in1t1GGTXHx7" - } - }, - { - "cell_type": "code", - "source": [ - "df_info = cli.get_listed_info()\n", - "\n", - "# データフレームを確認\n", - "df_info.info()\n", - "\n", - "print(\"\\n\")\n", - "\n", - "# データフレームを描画\n", - "df_info\n" - ], - "metadata": { - "id": "UF2xMSqimuPw" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 欠損値の確認\n", - "df_info[df_info.isnull().any(axis=1)]\n" - ], - "metadata": { - "id": "ucCsQuUJlnTV" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### ひとくちメモ集" - ], - "metadata": { - "id": "q7WqyHNcjnp4" - } - }, - { - "cell_type": "markdown", - "source": [ - "- 株式銘柄コードは、(発行体ごとに付番される固有名コード4桁)及び(株券の種類ごとに付番される予備コード1桁)で構成されている。 \n", - "(ex.普通株は末尾が0、優先株は末尾が5)\n" - ], - "metadata": { - "id": "YIGjDmvrfkjM" - } - }, - { - "cell_type": "code", - "source": [ - "# 普通株と優先株\n", - "df_info[df_info[\"Code\"].isin([\"25930\", \"25935\"])]\n" - ], - "metadata": { - "id": "kFP4cl2Jg6Rw" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "なお、現在株式銘柄コードは数値のみですが、2024年1月1日以降に新たに設定するコード(新規上場等)から数字のほかに英文字が追加される予定とのことです。 \n", - "ご興味ある方は[こちら](https://www.jpx.co.jp/sicc/securities-code/index.html)に資料等があります。" - ], - "metadata": { - "id": "HFRYJ27xISbL" - } - }, - { - "cell_type": "markdown", - "source": [ - "- なお、Sector17Codeが99、またはSecter33Codeが9999のものは、ETFやREIT、インフラファンド等の銘柄になっています。" - ], - "metadata": { - "id": "hoQoPK0coOm1" - } - }, - { - "cell_type": "code", - "source": [ - "df_info[df_info[\"Sector33Code\"] == \"9999\"]\n" - ], - "metadata": { - "id": "Ku5ithg-oQid" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## 若干のデータ分析" - ], - "metadata": { - "id": "_M9ehA9ikCf1" - } - }, - { - "cell_type": "code", - "source": [ - "# 銘柄一覧情報を取得\n", - "df_info = cli.get_list()\n" - ], - "metadata": { - "id": "HSBgCcYlkGfp" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 17業種別の企業数" - ], - "metadata": { - "id": "2appWzbgFpJm" - } - }, - { - "cell_type": "code", - "source": [ - "# ETF, REIT, インフラファンド等の17業種以外のデータを除外\n", - "df = df_info[df_info[\"Sector17Code\"] != \"99\"]\n", - "\n", - "# 17業種名でグループ化\n", - "df_sector = df.groupby(\"Sector17CodeName\").size().to_frame(\n", - " \"Count\").reset_index().sort_values(by=\"Count\", ascending=False)\n", - "px.bar(df_sector, x=\"Sector17CodeName\", y=\"Count\", title=\"17業種別の企業数\")\n" - ], - "metadata": { - "id": "kG5wuV0zFsgO" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 33業種別の企業数" - ], - "metadata": { - "id": "wx97fcQy91wT" - } - }, - { - "cell_type": "code", - "source": [ - "# ETF, REIT, インフラファンド等の33業種以外のデータを除外\n", - "df = df_info[df_info[\"Sector33Code\"] != \"9999\"]\n", - "\n", - "# 33業種名でグループ化\n", - "df_sector = df.groupby(\"Sector33CodeName\").size().to_frame(\n", - " \"Count\").reset_index().sort_values(by=\"Count\", ascending=False)\n", - "px.bar(df_sector, x=\"Sector33CodeName\", y=\"Count\", title=\"33業種別の企業数\")\n" - ], - "metadata": { - "id": "Zr9o0Z0k5YEv" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 市場区分別の企業数" - ], - "metadata": { - "id": "_NC9DYSl-vWe" - } - }, - { - "cell_type": "code", - "source": [ - "# 市場区分名でグループ化\n", - "df_market = df_info.groupby(\"MarketCodeName\").size().to_frame(\n", - " \"Count\").reset_index().sort_values(by=\"Count\", ascending=False)\n", - "px.bar(df_market, x=\"MarketCodeName\", y=\"Count\", title=\"市場区分別の企業数\")\n" - ], - "metadata": { - "id": "kU25HFxB2zvk" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 上記分析の両方を加味" - ], - "metadata": { - "id": "qSpZOyQVst-6" - } - }, - { - "cell_type": "code", - "source": [ - "# ETF, REIT, インフラファンド等の33業種以外のデータを除外\n", - "df = df_info[df_info[\"Sector33Code\"] != \"9999\"]\n", - "\n", - "# さらにプライム、スタンダード、グロース及びTokyoProMarket銘柄にフィルタ\n", - "df = df[df[\"MarketCodeName\"].isin([\"プライム\", \"スタンダード\", \"グロース\", \"TOKYO PRO MARKET\"])]\n", - "\n", - "# 業種別及び市場名でグルーピング\n", - "df_sector_market = df.groupby([\n", - " \"Sector33CodeName\", \"MarketCodeName\"\n", - "]).size().to_frame(\"Count\").reset_index().sort_values(by=[\"MarketCodeName\", \"Count\"],\n", - " ascending=False)\n", - "\n", - "px.bar(df_sector_market,\n", - " x=\"Sector33CodeName\",\n", - " y=\"Count\",\n", - " color=\"MarketCodeName\",\n", - " barmode=\"relative\",\n", - " title=\"33業種及び市場区分別の企業数\")\n" - ], - "metadata": { - "id": "VRWWAS8G_hZc" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 過去時点(1年前)の銘柄一覧で上記同様のグラフ描画" - ], - "metadata": { - "id": "0DMfmDj-GLEj" - } - }, - { - "cell_type": "code", - "source": [ - "d = datetime.now() - timedelta(days=365)\n", - "df_info = cli.get_listed_info(date_yyyymmdd=d.strftime(format=\"%Y%m%d\"))\n", - "\n", - "# ETF, REIT, インフラファンド等の33業種以外のデータを除外\n", - "df = df_info[df_info[\"Sector33Code\"] != \"9999\"]\n", - "\n", - "# さらにプライム、スタンダード、グロース及びTokyoProMarket銘柄にフィルタ\n", - "df = df[df[\"MarketCodeName\"].isin([\"プライム\", \"スタンダード\", \"グロース\", \"TOKYO PRO MARKET\"])]\n", - "\n", - "# 業種別及び市場名でグルーピング\n", - "df_sector_market = df.groupby([\n", - " \"Sector33CodeName\", \"MarketCodeName\"\n", - "]).size().to_frame(\"Count\").reset_index().sort_values(by=[\"MarketCodeName\", \"Count\"],\n", - " ascending=False)\n", - "px.bar(df_sector_market,\n", - " x=\"Sector33CodeName\",\n", - " y=\"Count\",\n", - " color=\"MarketCodeName\",\n", - " barmode=\"relative\",\n", - " title=\"33業種及び市場区分別の企業数\")\n" - ], - "metadata": { - "id": "hx9apk4fPfEm" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "# 株価情報 API(毎営業日の17時00分頃データ更新)\n", - "\n", - "株価データを取得することができます。 \n", - "株価及び取引高は、株式分割・併合を考慮した調整済み株価(小数点第2位四捨五入)と調整前の株価の両方を取得することができます。 \n", - "\n", - "なお、データを取得する際には、株式銘柄コード(code)または日付(date)の指定が必須となっています。\n", - "\n", - "また、地取に単独上場している銘柄については、株価配信していません。" - ], - "metadata": { - "id": "IOurY_o-Y9Cl" - } - }, - { - "cell_type": "markdown", - "source": [ - "### 株式銘柄コード指定Ver" - ], - "metadata": { - "id": "Cpd0yiiwqC_f" - } - }, - { - "cell_type": "code", - "source": [ - "df_quotes_bycode = cli.get_prices_daily_quotes(code=8697)\n", - "\n", - "# データフレームの情報を取得\n", - "df_quotes_bycode.info()\n", - "\n", - "print(\"\\n\")\n", - "\n", - "# データフレームを描画\n", - "df_quotes_bycode\n" - ], - "metadata": { - "id": "AMMohwc-js08" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 欠損値の確認\n", - "df_quotes_bycode[df_quotes_bycode.isnull().any(axis=1)]\n" - ], - "metadata": { - "id": "SBsxOE2unqEV" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 取引日指定Ver" - ], - "metadata": { - "id": "Cq2iNeB9qHTE" - } - }, - { - "cell_type": "code", - "source": [ - "d = datetime.now() - timedelta(days=365)\n", - "df_quotes_bydate = cli.get_prices_daily_quotes(date_yyyymmdd=d.strftime(format=\"%Y%m%d\"))\n", - "\n", - "# データフレームの情報を取得\n", - "df_quotes_bydate.info()\n", - "\n", - "print(\"\\n\")\n", - "\n", - "# データフレームを描画\n", - "df_quotes_bydate\n" - ], - "metadata": { - "id": "zLbZCoQpnqm3" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 欠損値の確認\n", - "df_quotes_bydate[df_quotes_bydate.isnull().any(axis=1)]\n" - ], - "metadata": { - "id": "kE77mWfSq1dd" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "その日取引が成立しなかった銘柄については、NaNが入っている。" - ], - "metadata": { - "id": "efG0qAKfq7BE" - } - }, - { - "cell_type": "markdown", - "source": [ - "### ひとくちメモ集" - ], - "metadata": { - "id": "gQNAyN8mrxf2" - } - }, - { - "cell_type": "markdown", - "source": [ - "- jquants-api-clientでは、`get_price_range()`を使うことで、銘柄指定せずに`from`, `to`で株価データが取得できます!(ありがたい...!)" - ], - "metadata": { - "id": "6gV7aFgkxjNc" - } - }, - { - "cell_type": "code", - "source": [ - "d_from = datetime.now() - timedelta(days=365)\n", - "d_to = datetime.now() - timedelta(days=335)\n", - "df_quotes = cli.get_price_range(start_dt=d_from.strftime(format=\"%Y%m%d\"), end_dt=d_to.strftime(format=\"%Y%m%d\"))\n", - "df_quotes\n" - ], - "metadata": { - "id": "Mwz8uApUxm-E" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## 若干のデータ分析" - ], - "metadata": { - "id": "kaT1wWtSyhUV" - } - }, - { - "cell_type": "markdown", - "source": [ - "- 株価分析でよくある図を作成してみる" - ], - "metadata": { - "id": "lXXGMtizQEAD" - } - }, - { - "cell_type": "code", - "source": [ - "# JPXの株価を取得\n", - "df_jpx = cli.get_prices_daily_quotes(code=8697)\n", - "\n", - "# グラフに第2軸を設定\n", - "fig = make_subplots(specs=[[{\"secondary_y\": True}]])\n", - "\n", - "# ローソク足を描画\n", - "fig.add_trace(\n", - " go.Candlestick(x=df_jpx.Date,\n", - " open=df_jpx.AdjustmentOpen,\n", - " high=df_jpx.AdjustmentHigh,\n", - " low=df_jpx.AdjustmentLow,\n", - " close=df_jpx.AdjustmentClose,\n", - " name=\"OHLC\"))\n", - "\n", - "# 25日移動平均\n", - "fig.add_trace(\n", - " go.Scatter(x=df_jpx.Date,\n", - " y=df_jpx.AdjustmentClose.rolling(25).mean(),\n", - " name=\"25日移動平均線\"))\n", - "\n", - "# 75日移動平均\n", - "fig.add_trace(\n", - " go.Scatter(x=df_jpx.Date,\n", - " y=df_jpx.AdjustmentClose.rolling(75).mean(),\n", - " name=\"75日移動平均線\"))\n", - "\n", - "# 取引高を第2軸に設定\n", - "fig.add_trace(go.Bar(x=df_jpx.Date, y=df_jpx.AdjustmentVolume, name=\"調整済み取引高\"),\n", - " secondary_y=True)\n", - "fig.update_layout(title_text=\"JPX(8697)のローソク足及び出来高\")\n", - "fig.show()\n" - ], - "metadata": { - "id": "0qS4NGdYyeI0" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "# 財務情報 API(18時ごろ及び24時30分頃更新)\n", - "\n", - "財務情報は上場会社の四半期及び通期の決算短信に係る情報を取得できます。" - ], - "metadata": { - "id": "9Ox2YvyjY_p8" - } - }, - { - "cell_type": "code", - "source": [ - "df_fins = cli.get_fins_statements(code=8697)\n", - "\n", - "# データフレームを確認\n", - "df_fins.info()\n", - "\n", - "print(\"\\n\")\n", - "\n", - "# データフレームを描画\n", - "df_fins\n" - ], - "metadata": { - "id": "MCF7Vh166U7O" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 欠損値の確認\n", - "df_fins[df_fins.isnull().any(axis=1)]\n" - ], - "metadata": { - "id": "h_8PnfBU_Kxh" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "取得したデータフレームには空欄の箇所が多くみられるが、Null値は存在しない。 \n", - "本APIのデータは、各企業が適時開示したXBRLデータに基づき作成しており、当該XBRLデータにおいて、データの無い箇所には空文字が入っていることから、本APIにおいても空欄となっている箇所が多くある。" - ], - "metadata": { - "id": "V6JdDezubeHw" - } - }, - { - "cell_type": "markdown", - "source": [ - "## 若干のデータ分析" - ], - "metadata": { - "id": "6SBxtk9i6Rcc" - } - }, - { - "cell_type": "code", - "source": [ - "# 過去の一定期間の財務情報を取得\n", - "d_from = datetime.now() - timedelta(days=300)\n", - "d_to = datetime.now() - timedelta(days=270)\n", - "df_fins = cli.get_statements_range(start_dt=d_from.strftime(format=\"%Y%m%d\"), end_dt=d_to.strftime(format=\"%Y%m%d\"))\n" - ], - "metadata": { - "id": "EatgPstsnob-" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 書類種別の項目を表示\n", - "df_fins[\"TypeOfDocument\"].value_counts()\n" - ], - "metadata": { - "id": "CxONVOPLDM7l" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "書類種別には、連結(Consolidated)や非連結(NonConsolidated)決算、予想の修正(ForecastRevision)の開示等があることがわかる。" - ], - "metadata": { - "id": "Bi86Iwo5FNr0" - } - }, - { - "cell_type": "code", - "source": [ - "# 会計期間の種類を表示\n", - "df_fins[\"TypeOfCurrentPeriod\"].value_counts()\n" - ], - "metadata": { - "id": "AWBl4QmfNw-G" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 事業年度の終了日を表示\n", - "df_fins_onlyFY = df_fins[df_fins[\"TypeOfDocument\"].str.contains(\n", - " \"FYFinancialStatements\")]\n", - "df_fins_onlyFY[\"CurrentPeriodEndDate\"].value_counts()\n" - ], - "metadata": { - "id": "v9ZFCieEOweK" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 一番多い決算期末の日付でフィルタ\n", - "df_fins_onlyFY_onMar = df_fins_onlyFY[df_fins_onlyFY[\"CurrentPeriodEndDate\"] ==\n", - " df_fins_onlyFY[\"CurrentPeriodEndDate\"].max().strftime(format(\"%Y%m%d\"))]\n", - "\n", - "# 開示日でグループ化し、開示件数を描画\n", - "df_disclosed_date = df_fins_onlyFY_onMar.groupby(\n", - " \"DisclosedDate\").size().to_frame(\"Count\").reset_index()\n", - "px.bar(df_disclosed_date, x=\"DisclosedDate\", y=\"Count\", title=\"日ごとの開示件数\")\n" - ], - "metadata": { - "id": "lknuNNqgRVTD" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "ある日に開示が集中していることがわかる(決算期末を迎えてから45日以内に開示しなければならないため)" - ], - "metadata": { - "id": "e1034bJHV9Cc" - } - }, - { - "cell_type": "markdown", - "source": [ - "# マーケット情報 API(毎週第4営業日に週次で更新) **(Lightプラン以上のプランの方のみ利用可能)**\n", - "\n", - "2017年1月から足元までの投資部門別売買状況(金額)のデータを取得することができます。 \n", - "なお、配信データは[こちらのページ](https://www.jpx.co.jp/markets/statistics-equities/investor-type/index.html)で公表している内容と同一です。 " - ], - "metadata": { - "id": "tnIOKgSdX0GV" - } - }, - { - "cell_type": "code", - "source": [ - "df_trades_spec = cli.get_markets_trades_spec()\n", - "\n", - "# データフレームを確認\n", - "df_trades_spec.info()\n", - "\n", - "print(\"\\n\")\n", - "\n", - "# データフレームを描画\n", - "df_trades_spec\n" - ], - "metadata": { - "id": "Re_RHFAbX0GW" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 欠損値の確認\n", - "df_trades_spec[df_trades_spec.isnull().any(axis=1)]\n" - ], - "metadata": { - "id": "nSv896BR_oIt" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## 若干のデータ分析" - ], - "metadata": { - "id": "jheKeIcEX0GW" - } - }, - { - "cell_type": "code", - "source": [ - "# 2022年4月以降のプライム市場の投資部門別データを取得\n", - "df_trades_spec = cli.get_markets_trades_spec(section=jquantsapi.MARKET_API_SECTIONS.TSEPrime,\n", - " from_yyyymmdd=20220408)\n", - "\n", - "# 各属性のうち、Balance(売り買いの差し引き金額)の項目のみ取得\n", - "columns_balance = df_trades_spec.columns[df_trades_spec.columns.str.contains(\n", - " \"Balance\")]\n", - "df_trades_spec_only_balance = df_trades_spec[columns_balance].copy()\n", - "\n", - "# 投資部門別データの公表日を選択した項目のデータフレームへ転記\n", - "df_trades_spec_only_balance.loc[:, \"StartDate\"] = df_trades_spec[\n", - " \"StartDate\"].copy()\n", - "df_trades_spec_only_balance.set_index(\"StartDate\", inplace=True)\n", - "\n", - "# 海外投資家、個人、投資信託、信託銀行の4つの属性のみ描画\n", - "fig = px.bar(df_trades_spec_only_balance,\n", - " x=df_trades_spec_only_balance.index,\n", - " y=[\n", - " \"ForeignersBalance\", \"IndividualsBalance\",\n", - " \"InvestmentTrustsBalance\", \"TrustBanksBalance\"\n", - " ],\n", - " barmode=\"group\")\n", - "fig.update_xaxes(type=\"category\")\n", - "fig.show()\n" - ], - "metadata": { - "id": "jDzZ_UVzD5Ua" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 日ごとだと見にくいため、月単位で合計してみる\n", - "df_monthly = df_trades_spec_only_balance.resample(\"M\").sum()\n", - "fig = px.bar(df_monthly,\n", - " x=df_monthly.index,\n", - " y=[\n", - " \"ForeignersBalance\", \"IndividualsBalance\",\n", - " \"InvestmentTrustsBalance\", \"TrustBanksBalance\"\n", - " ],\n", - " barmode=\"group\")\n", - "fig.update_xaxes(\n", - " dtick=\"M1\",\n", - " tickformat=\"%b %Y\",\n", - " tick0=\"2022-04-30\")\n", - "fig.show()\n" - ], - "metadata": { - "id": "70w4GZ8YWmpb" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "2022年4月に海外投資家が大きく買い越しているが、5月以降はほぼ売り越しとなっていそう。(10月から買い戻しの動き?? 11/25追記)\n", - "- 2022年4月以前の状況はどうか?\n", - "- 今回はプライム市場でフィルタしているが、他の市場区分だとどうか?" - ], - "metadata": { - "id": "uzt9fKo0gHur" - } - }, - { - "cell_type": "markdown", - "source": [ - "# TOPIX指数API **(Lightプラン以上のプランの方のみ利用可能)**\n", - "\n", - "2021年1月から足元までのTOPIX指数のデータを取得することができます。 " - ], - "metadata": { - "id": "SDyo1lqF1RV0" - } - }, - { - "cell_type": "code", - "source": [ - "df_topix = cli.get_indices_topix()\n", - "\n", - "# データフレームを確認\n", - "df_topix.info()\n", - "\n", - "print(\"\\n\")\n", - "\n", - "# データフレームを描画\n", - "df_topix\n" - ], - "metadata": { - "id": "KjTkuMxs27X4" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 欠損値の確認\n", - "df_topix[df_topix.isnull().any(axis=1)]\n" - ], - "metadata": { - "id": "gYr-AIci27X6" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## 若干のデータ分析(JPXとTOPIX指数の比較)" - ], - "metadata": { - "id": "RB9Dg2IP3M7z" - } - }, - { - "cell_type": "code", - "source": [ - "# JPXの2021年からの株価を取得\n", - "d_now = datetime.now().strftime(\"%Y%m%d\")\n", - "df_jpx = cli.get_prices_daily_quotes(code=8697, from_yyyymmdd=20210101, to_yyyymmdd=d_now)\n", - "df_topix = cli.get_indices_topix(from_yyyymmdd=20210101, to_yyyymmdd=d_now)\n", - "\n", - "# グラフに第2軸を設定\n", - "fig = make_subplots(specs=[[{\"secondary_y\": True}]])\n", - "\n", - "# ローソク足を描画\n", - "fig.add_trace(\n", - " go.Candlestick(x=df_jpx.Date,\n", - " open=df_jpx.AdjustmentOpen,\n", - " high=df_jpx.AdjustmentHigh,\n", - " low=df_jpx.AdjustmentLow,\n", - " close=df_jpx.AdjustmentClose,\n", - " name=\"OHLC\"))\n", - "\n", - "# 取引高を第2軸に設定\n", - "fig.add_trace(go.Scatter(x=df_topix.Date, y=df_topix.Close, name=\"TOPIX指数終値\", line=dict(color=\"#51848E\")),\n", - " secondary_y=True)\n", - "fig.update_layout(title_text=\"JPX(8697)のローソク足及びTOPIX指数\")\n", - "fig.show()\n" - ], - "metadata": { - "id": "RxpZT1jA1RV1" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "# FinVizのTreeMapみたいなやつ" - ], - "metadata": { - "id": "nXzXQx-LQNP4" - } - }, - { - "cell_type": "markdown", - "source": [ - "- 各APIを統合して利用した分析として、FinVizのTreeMapのようなものを作ってみる" - ], - "metadata": { - "id": "4EpjbzS63LNo" - } - }, - { - "cell_type": "markdown", - "source": [ - "## 33業種で作成" - ], - "metadata": { - "id": "WMla6uaJMe_o" - } - }, - { - "cell_type": "markdown", - "source": [ - "### 時価総額を算出するため、各銘柄の期末発行済み株式数を取得" - ], - "metadata": { - "id": "YxoB18tdJoQi" - } - }, - { - "cell_type": "code", - "source": [ - "# 2023年初来の財務情報取得\n", - "df_fins = cli.get_statements_range(start_dt=\"20230101\")\n", - "\n", - "\n", - "# 財務情報データから取得したい項目(株式銘柄コード、期末発行済株式数)を定義\n", - "fins_columns = [\n", - " \"LocalCode\",\n", - " \"NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock\"\n", - "]\n", - "\n", - "# 財務情報テータから必要なデータのみ取得\n", - "df_treasury_stock = df_fins[df_fins[\n", - " \"NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock\"]\n", - " != \"\"][fins_columns]\n", - "\n", - "# 列名の変更(LocalCode -> Code)\n", - "df_treasury_stock = df_treasury_stock.rename(columns={\"LocalCode\": \"Code\"})\n", - "\n", - "\n", - "# 期末発行済株式数を文字列から整数に変換\n", - "df_treasury_stock[\n", - " \"NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock\"] = df_treasury_stock[\n", - " \"NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock\"].astype(\"int\")\n", - "\n", - "# 期末発行済株式数を銘柄毎にグループ化して平均\n", - "df_treasury_stock = df_treasury_stock.groupby(\n", - " by=\"Code\").mean().reset_index()\n" - ], - "metadata": { - "id": "zBIP-oKfu3ya" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 33業種のそれぞれについて、時価総額Top5の企業を取得" - ], - "metadata": { - "id": "McKUm9wIJ0tZ" - } - }, - { - "cell_type": "code", - "source": [ - "# 昨日の全銘柄株価を取得\n", - "d_yesterday = (datetime.now() - timedelta(days=1)).strftime(format=\"%Y%m%d\")\n", - "df_prices = cli.get_prices_daily_quotes(date_yyyymmdd=d_yesterday)\n", - "\n", - "# 銘柄一覧を取得\n", - "df_info = cli.get_list()\n", - "\n", - "# 銘柄一覧と全銘柄株価を株式銘柄コードで結合\n", - "df_merge = pd.merge(df_prices, df_info, how=\"inner\", on=\"Code\")\n", - "\n", - "# さらに先程取得した期末発行済み株式数と結合\n", - "df_merge = pd.merge(df_merge, df_treasury_stock, how=\"inner\", on=\"Code\")\n", - "\n", - "# 時価総額をデータフレームに追加\n", - "df_merge[\"Capitalization\"] = df_merge[\"AdjustmentClose\"] * df_merge[\n", - " \"NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock\"]\n", - "\n", - "# 時価総額及び業種コードでソート\n", - "df_merge = df_merge.sort_values(by=[\"Capitalization\"], ascending=False)\n", - "\n", - "# 業種名毎の上位5社を抽出\n", - "df_top5 = df_merge.groupby(\"Sector33CodeName\").head(5)\n", - "\n", - "# 業種その他(ETF等)を除外\n", - "df_top5 = df_top5[df_top5[\"Sector33Code\"] != \"9999\"]\n", - "\n", - "# 各業種の時価総額Top5の株式銘柄コードを取得\n", - "top5_codes = df_top5[\"Code\"]\n" - ], - "metadata": { - "id": "nY2Zs7UK3ZdO" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 33業種のそれぞれについて、時価総額Top5の企業の約1か月(20営業日)のリターンを取得" - ], - "metadata": { - "id": "klyKYN8dKKhy" - } - }, - { - "cell_type": "code", - "source": [ - "# 3月の約1か月分の全銘柄の株価情報を取得\n", - "\n", - "df_1month_prices = cli.get_price_range(start_dt=\"20230228\", end_dt=\"20230331\") \n", - "\n", - "# 各業種の時価総額Top5のみの調整済み終値を取得\n", - "df_top5_1month_prices = df_1month_prices[df_1month_prices[\"Code\"].isin(\n", - " top5_codes)][[\"Code\", \"Date\", \"AdjustmentClose\"]]\n", - "\n", - "# 約1か月のリターン計算する関数\n", - "def calc_return(df, code):\n", - " df = df[df[\"Code\"] == code]\n", - " df[\"Return\"] = df[\"AdjustmentClose\"].pct_change(20)\n", - " return df[[\"Code\", \"Return\"]].tail(1).to_dict(orient=\"records\")\n", - "\n", - "# 各銘柄の約1か月のリターンを作成\n", - "returns_list = []\n", - "\n", - "for code in top5_codes:\n", - " df = calc_return(df_top5_1month_prices, code)\n", - " returns_list.extend(df)\n", - "\n", - "# リターンのデータフレームを作成\n", - "df_returns = pd.DataFrame(returns_list)" - ], - "metadata": { - "id": "fQ-QSXr3R8pb" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 業種、企業名、時価総額、リターンからtreemapを描画" - ], - "metadata": { - "id": "IFCPIBN0KWTz" - } - }, - { - "cell_type": "code", - "source": [ - "# リターンのデータフレームを結合\n", - "df_top5_with_returns = pd.merge(df_top5, df_returns, how=\"inner\", on=\"Code\")\n", - "\n", - "# treemapを描画\n", - "fig = px.treemap(df_top5_with_returns,\n", - " path=[px.Constant(\"TSE\"), \"Sector33CodeName\", \"CompanyName\"],\n", - " values=\"Capitalization\",\n", - " color=\"Return\",\n", - " color_continuous_scale=[\"red\", \"white\", \"green\"],\n", - " color_continuous_midpoint=0)\n", - "fig.update_layout(margin=dict(t=50, l=25, r=25, b=25))\n", - "fig.show()\n" - ], - "metadata": { - "id": "RJt4Y7jtKFPg" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## 17業種でも作成" - ], - "metadata": { - "id": "MyvNuiZsMmG2" - } - }, - { - "cell_type": "markdown", - "source": [ - "### 時価総額を算出するため、各銘柄の期末発行済み株式数を取得" - ], - "metadata": { - "id": "drt5oLNHMTtH" - } - }, - { - "cell_type": "code", - "source": [ - "# 2023年初来の財務情報取得\n", - "df_fins = cli.get_statements_range(start_dt=\"20230101\")\n", - "\n", - "\n", - "# 財務情報データから取得したい項目(株式銘柄コード、期末発行済株式数)を定義\n", - "fins_columns = [\n", - " \"LocalCode\",\n", - " \"NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock\"\n", - "]\n", - "\n", - "# 財務情報テータから必要なデータのみ取得\n", - "df_treasury_stock = df_fins[df_fins[\n", - " \"NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock\"]\n", - " != \"\"][fins_columns]\n", - "\n", - "# 列名の変更(LocalCode -> Code)\n", - "df_treasury_stock = df_treasury_stock.rename(columns={\"LocalCode\": \"Code\"})\n", - "\n", - "\n", - "# 期末発行済株式数を文字列から整数に変換\n", - "df_treasury_stock[\n", - " \"NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock\"] = df_treasury_stock[\n", - " \"NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock\"].astype(\"int\")\n", - "\n", - "# 期末発行済株式数を銘柄毎にグループ化して平均\n", - "df_treasury_stock = df_treasury_stock.groupby(\n", - " by=\"Code\").mean().reset_index()\n" - ], - "metadata": { - "id": "8ErokySZMTtU" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 33業種のそれぞれについて、時価総額Top5の企業を取得" - ], - "metadata": { - "id": "Wj8GG8yaMTtU" - } - }, - { - "cell_type": "code", - "source": [ - "# 昨日の全銘柄株価を取得\n", - "d_yesterday = (datetime.now() - timedelta(days=1)).strftime(format=\"%Y%m%d\")\n", - "df_prices = cli.get_prices_daily_quotes(date_yyyymmdd=d_yesterday)\n", - "\n", - "\n", - "# 銘柄一覧を取得\n", - "df_info = cli.get_list()\n", - "\n", - "# 銘柄一覧と全銘柄株価を株式銘柄コードで結合\n", - "df_merge = pd.merge(df_prices, df_info, how=\"inner\", on=\"Code\")\n", - "\n", - "# さらに先程取得した期末発行済み株式数と結合\n", - "df_merge = pd.merge(df_merge, df_treasury_stock, how=\"inner\", on=\"Code\")\n", - "\n", - "# 時価総額をデータフレームに追加\n", - "df_merge[\"Capitalization\"] = df_merge[\"AdjustmentClose\"] * df_merge[\n", - " \"NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock\"]\n", - "\n", - "# 時価総額及び業種コードでソート\n", - "df_merge = df_merge.sort_values(by=[\"Capitalization\"], ascending=False)\n", - "\n", - "# 業種名毎の上位5社を抽出\n", - "df_top5 = df_merge.groupby(\"Sector17CodeName\").head(5)\n", - "\n", - "# 業種その他(ETF等)を除外\n", - "df_top5 = df_top5[df_top5[\"Sector17Code\"] != \"99\"]\n", - "\n", - "# 各業種の時価総額Top5の株式銘柄コードを取得\n", - "top5_codes = df_top5[\"Code\"]\n" - ], - "metadata": { - "id": "udsV1CxbMTtV" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 33業種のそれぞれについて、時価総額Top5の企業の約1か月(20営業日)のリターンを取得" - ], - "metadata": { - "id": "KjF3aMKwMTtV" - } - }, - { - "cell_type": "code", - "source": [ - "# 9月末から10月末までの約1か月分の全銘柄の株価情報を取得\n", - "df_1month_prices = cli.get_price_range(start_dt=\"20230228\", end_dt=\"20230331\") \n", - "\n", - "# 各業種の時価総額Top5のみの調整済み終値を取得\n", - "df_top5_1month_prices = df_1month_prices[df_1month_prices[\"Code\"].isin(\n", - " top5_codes)][[\"Code\", \"Date\", \"AdjustmentClose\"]]\n", - "\n", - "# 約1か月のリターン計算する関数\n", - "def calc_return(df, code):\n", - " df = df[df[\"Code\"] == code]\n", - " df[\"Return\"] = df[\"AdjustmentClose\"].pct_change(20)\n", - " return df[[\"Code\", \"Return\"]].tail(1).to_dict(orient=\"records\")\n", - "\n", - "# 各銘柄の約1か月のリターンを作成\n", - "returns_list = []\n", - "\n", - "for code in top5_codes:\n", - " df = calc_return(df_top5_1month_prices, code)\n", - " returns_list.extend(df)\n", - "\n", - "# リターンのデータフレームを作成\n", - "df_returns = pd.DataFrame(returns_list)" - ], - "metadata": { - "id": "GDfWncTWMTtV" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 業種、企業名、時価総額、リターンからtreemapを描画" - ], - "metadata": { - "id": "t3RZ1wQIMTtW" - } - }, - { - "cell_type": "code", - "source": [ - "# リターンのデータフレームを結合\n", - "df_top5_with_returns = pd.merge(df_top5, df_returns, how=\"inner\", on=\"Code\")\n", - "\n", - "# treemapを描画\n", - "fig = px.treemap(df_top5_with_returns,\n", - " path=[px.Constant(\"TSE\"), \"Sector17CodeName\", \"CompanyName\"],\n", - " values=\"Capitalization\",\n", - " color=\"Return\",\n", - " color_continuous_scale=[\"red\", \"white\", \"green\"],\n", - " color_continuous_midpoint=0)\n", - "fig.update_layout(margin=dict(t=50, l=25, r=25, b=25))\n", - "fig.show()\n" - ], - "metadata": { - "id": "FrLes332MTtW" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "# ご意見等\n", - "その他、こんなデータが欲しいというご要望や、こんなデータありますか?といった質問もどしどし受け付けております!!\n", - "\n", - "[マケデコdiscord](https://discord.gg/xg6P5RXwaa)の`#j-quants-api`チャンネルに送ってください!! \n", - "よろしくお願いいたします。" - ], - "metadata": { - "id": "ECuvXWrtcqiB" - } - }, - { - "cell_type": "code", - "source": [], - "metadata": { - "id": "rTg-yl_3NTeH" - }, - "execution_count": null, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/examples/20230126-006-mkdeco-jquants-kaggle-8th.ipynb b/examples/20230126-006-mkdeco-jquants-kaggle-8th.ipynb deleted file mode 100644 index 4887e0d..0000000 --- a/examples/20230126-006-mkdeco-jquants-kaggle-8th.ipynb +++ /dev/null @@ -1,521 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "source": [ - "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20230126-006-mkdeco-jquants-kaggle-8th.ipynb)\n\n", - "本ノートブックは J-Quants JPX Tokyo Stock Exchange Prediction の8位入賞モデルを J-Quants API を使用して動かしてみるサンプルノートブックとなります。\n", - "\n", - "\n", - "J-Quants API を使用するために元のコードから一部改変しています。本ノートブックはあくまでもサンプルとしての提供を目的としており、予測精度については十分な評価・検証を実施しておりません。\n", - "\n", - "\n", - "* 本ノートブックはGoogleドライブにデータを書き込みます。\n", - "* 本ノートブックはデータの取得に J-Quants API を使用します。\n", - "\n", - "\n", - "■注意事項\n", - "\n", - "本ノートブックは投資勧誘を目的としたものではありません。投資に関するご決定はご自身のご判断において行われるようお願いいたします。\n", - "掲載された情報に誤りがあった場合や、第三者によるデータの改ざん、データのダウンロード等によって生じた障害等に関し、本コミュニティは事由の如何を問わず一切責任を負うものではありませんので、あらかじめご了承ください。" - ], - "metadata": { - "id": "RyE7YZzx7G7l" - } - }, - { - "cell_type": "code", - "source": [ - "from google.colab import drive\n", - "drive.mount('/content/drive')" - ], - "metadata": { - "id": "ZBB4j4njA-UJ" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# データを保存するディレクトリを指定します。Google Driveに保存します。\n", - "DATA_DIR = \"/content/drive/MyDrive/drive_ws/mkdeco\"\n", - "# J-Quants JPX Tokyo Stock Exchange Prediction の入賞モデルのリポジトリを取得して8位モデルのコードを取得します\n", - "REPO_DIR = \"jquants-kaggle\"\n", - "MODEL_DIR = \"winner-models/8th\"\n", - "MODEL_PATH = f\"{REPO_DIR}/{MODEL_DIR}\"" - ], - "metadata": { - "id": "wsxN19WgCYNz" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "! git clone https://github.com/J-Quants/JPXTokyoStockExchangePrediction.git $REPO_DIR" - ], - "metadata": { - "id": "T4ihOGzBCQaM" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "import sys\n", - "sys.path.append(f\"{MODEL_PATH}\")" - ], - "metadata": { - "id": "cSwIqIBJDCDr" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "GtzyPqzhAo_6" - }, - "outputs": [], - "source": [ - "# データの取得に J-Quants API を使用します。\n", - "! python3 -m pip -q install jquants-api-client" - ] - }, - { - "cell_type": "code", - "source": [ - "# lightGBMのバージョンを調整します。\n", - "! python3 -m pip -q install -U lightgbm==3.3.5" - ], - "metadata": { - "id": "z7DhZcpCGX-p" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "import os\n", - "import sys\n", - "import pickle\n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "import lightgbm\n", - "from tqdm.auto import tqdm\n", - "\n", - "import jquantsapi as jqapi\n", - "\n", - "# 上記で取得した独自ライブラリ\n", - "import Features\n", - "from Preprocessing import StockDataPreprocessor\n", - "from Trackers import StockTracker, FeatureType" - ], - "metadata": { - "id": "l-xsPigTAvVP" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# J-Quants APIを使用してデータを取得します\n", - "# /content/drive/MyDrive/drive_ws/secret/jquants-api.toml にuser_idとパスワードを記載した設定ファイルを置いてあります\n", - "# ref. https://github.com/J-Quants/jquants-api-client-python#%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E4%BE%8B\n", - "cli = jqapi.Client()" - ], - "metadata": { - "id": "ZAltRA86A3Cw" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 予測対象銘柄を指定するために銘柄一覧を取得します\n", - "df_list = cli.get_list()" - ], - "metadata": { - "id": "5_2X5AgvDX1r" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "df_list.tail(2)" - ], - "metadata": { - "id": "ln7amrrODdA5" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 株価情報を取得します\n", - "LAST_N_BDAY = 100\n", - "START_DT = (pd.Timestamp.now() - pd.offsets.BDay(LAST_N_BDAY)).strftime(\"%Y-%m-%d\")\n", - "END_DT = pd.Timestamp.now().strftime(\"%Y-%m-%d\")\n", - "PRICE_FILE = f\"{DATA_DIR}/20230113-mkdeco-jquants-kaggle-8th-price-{START_DT}_{END_DT}.parquet\"\n", - "if not os.path.isfile(PRICE_FILE):\n", - " os.makedirs(DATA_DIR, exist_ok=True)\n", - " df_price = cli.get_price_range(start_dt=START_DT, end_dt=END_DT)\n", - " df_price.to_parquet(PRICE_FILE)\n", - "df_price = pd.read_parquet(PRICE_FILE)" - ], - "metadata": { - "id": "qEpXvndCA7C7" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "df_price.tail(2)" - ], - "metadata": { - "id": "OUhhNalrByKF" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "df_list[\"ScaleCategory\"].unique()" - ], - "metadata": { - "id": "8eBqFBG1a0iS" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 対象をTOPIX500銘柄に絞り込みます。\n", - "topix500_list = sorted(df_list.loc[df_list[\"ScaleCategory\"].isin([\"TOPIX Core30\", \"TOPIX Large70\", \"TOPIX Mid400\"]), \"Code\"].unique())\n", - "df_price = df_price.loc[df_price[\"Code\"].isin(topix500_list)]\n", - "df_price[\"Code\"].unique().shape" - ], - "metadata": { - "id": "rZ0sH_KPaxBn" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# データを調整します。\n", - "df_price_kaggle = df_price.sort_values([\"Code\", \"Date\"])\n", - "# 銘柄コードを4桁にします\n", - "df_price_kaggle[\"SecuritiesCode\"] = df_price_kaggle[\"Code\"].str[:4].astype(np.int16)\n", - "# Kaggleデータに存在したカラムを追加します\n", - "df_price_kaggle[\"ExpectedDividend\"] = 0.0\n", - "df_price_kaggle[\"SupervisionFlag\"] = False\n", - "df_price_kaggle[\"Target\"] = np.nan\n", - "df_price_kaggle[\"Target_open2close\"] = np.nan\n", - "\n", - "def adjust(df):\n", - " # 調整係数を1日分ずらします\n", - " df[\"AdjustmentFactor\"] = df[\"AdjustmentFactor\"].shift(-1)\n", - " # Target列を作成します\n", - " df[\"Target\"] = df[\"AdjustmentClose\"].pct_change().shift(-2)\n", - " # target_pen2close列を作成します\n", - " df[\"Target_open2close\"] = df[[\"AdjustmentOpen\", \"AdjustmentClose\"]].pct_change(axis=1)[\"AdjustmentClose\"].shift(-1)\n", - " return df\n", - "\n", - "df_price_kaggle = df_price_kaggle.groupby(\"Code\").apply(adjust).reset_index(drop=True)\n", - "# 予測対象の銘柄コード(4桁)を保存しておきます。\n", - "target_codes = sorted(df_price_kaggle[\"SecuritiesCode\"].unique())" - ], - "metadata": { - "id": "6Qefakkpbrvn" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "df_price_kaggle.tail(2)" - ], - "metadata": { - "id": "_dJXivBTeJAW" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 公開されている予測モデルを取得します\n", - "MODEL_FILE = \"lgbm.pickle\"\n", - "with open(f\"{MODEL_PATH}/{MODEL_FILE}\", mode=\"rb\") as f:\n", - " model = pickle.load(f)" - ], - "metadata": { - "id": "6JLZJkpwDUoO" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# モデルのパラメータを確認します\n", - "model.get_params()" - ], - "metadata": { - "id": "sVwotfREEsvm" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 特徴量などを設定します" - ], - "metadata": { - "id": "mzSRbaqldkQa" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "features = [Features.Amplitude(), Features.OpenCloseReturn(), Features.Return(), \n", - " Features.Volatility(10), Features.Volatility(30), Features.Volatility(50), \n", - " Features.SMA(\"Close\", 3), Features.SMA(\"Close\", 5), Features.SMA(\"Close\", 10),\n", - " Features.SMA(\"Close\", 30),\n", - " Features.SMA(\"Return\", 3), Features.SMA(\"Return\", 5), \n", - " Features.SMA(\"Return\", 10), Features.SMA(\"Return\", 30),\n", - " ]" - ], - "metadata": { - "id": "3ZHKzdqDdgzl" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "## Specify training columns and specify categorical columns\n", - "training_cols = ['SecuritiesCode', 'Open', 'High', 'Low', 'Close',\n", - " 'Volume', 'AdjustmentFactor', 'ExpectedDividend', \n", - " 'SupervisionFlag']\n", - "\n", - "for feature in features:\n", - " training_cols.append(feature.name)\n", - "\n", - "categorical_cols = [\"SecuritiesCode\", \"SupervisionFlag\"]\n", - "target_col = [\"Target\"]" - ], - "metadata": { - "id": "UFKHhAMbdsPE" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "class Algo:\n", - " \n", - " def __init__(self, model, state_tracker):\n", - " self.model = model\n", - " self.st = state_tracker\n", - " self.cols = ['SecuritiesCode', 'Open', 'High', 'Low', 'Close',\n", - " 'Volume', 'AdjustmentFactor', 'ExpectedDividend', \n", - " 'SupervisionFlag']\n", - "\n", - " # 元のコードではstock_idがハードコーディングされているため一部修正します。\n", - " for feature in self.st.local_features[list(self.st.local_features)[0]]:\n", - " self.cols.append(feature.name)\n", - "\n", - " def add_rank1(self, df):\n", - " # ランク付けをシンプルにしています。\n", - " df[\"Rank\"] = len(df) - df[\"Prediction\"].rank(method=\"first\")\n", - " return df\n", - " \n", - " def predict_online(self, prices):\n", - " prices = self.st.online_update_apply(prices)[self.cols]\n", - " if not prices[\"SecuritiesCode\"].is_monotonic_increasing:\n", - " prices = prices.sort_values(by=\"SecuritiesCode\")\n", - " prices[\"Prediction\"] = self.model.predict(prices)\n", - " return self.add_rank1(prices)" - ], - "metadata": { - "id": "TUE9DRkAjBLr" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "class StateTracker:\n", - "\n", - " def __init__(self, features, stock_ids):\n", - " # 元のコードではstock_idがハードコーディングされているため一部修正します。\n", - " self.stock_ids = stock_ids\n", - " self.stock_trackers = {}\n", - " for s_id in self.stock_ids:\n", - " self.stock_trackers[s_id] = StockTracker(s_id)\n", - " self.global_features = []\n", - "\n", - " self.local_features = {}\n", - "\n", - " for feature in features:\n", - "\n", - " if feature.feature_type == FeatureType.GLOBAL:\n", - " self.global_features.append(feature)\n", - " elif feature.feature_type == FeatureType.LOCAL:\n", - " for stock_id in self.stock_ids:\n", - " if stock_id not in self.local_features:\n", - " self.local_features[stock_id] = []\n", - " self.local_features[stock_id].append(feature.copy())\n", - "\n", - " def update_single_row(self, row):\n", - " stock_id = row[\"SecuritiesCode\"]\n", - " row, status_code = self.stock_trackers[stock_id].update(row)\n", - " row[\"StatusCode\"] = status_code\n", - " for feature in self.local_features[stock_id]:\n", - " row = feature.update_row(row)\n", - " return row\n", - "\n", - " def online_update_apply(self, prices):\n", - " return prices.apply(lambda row: self.update_single_row(row), axis=1)\n" - ], - "metadata": { - "id": "_H_jWbVPpM1x" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 推論します (初期設定のデータ期間 (100日) の場合、10分程度かかります)\n", - "st = StateTracker(features, target_codes)\n", - "algo = Algo(model, st)\n", - "# 取得するランキングの上下N銘柄数を指定します\n", - "# EVAL_N = 10\n", - "\n", - "buff = []\n", - "for grouped_prices in tqdm(df_price_kaggle.groupby(\"Date\")):\n", - " prices = grouped_prices[1].copy()\n", - " if not prices[\"SecuritiesCode\"].is_monotonic_increasing:\n", - " prices = prices.sort_values(\"SecuritiesCode\")\n", - " \n", - " prices[\"Rank\"] = algo.predict_online(prices)[\"Rank\"] # make your predictions here\n", - " prices = prices.sort_values(\"Rank\")\n", - " # ランキングの上下N銘柄のみ取得します\n", - " # prices = pd.concat([prices.iloc[:EVAL_N], prices.iloc[-EVAL_N:]])\n", - "\n", - " buff.append(prices) # register your predictions" - ], - "metadata": { - "id": "YQ2P57IDGq76" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "df_ret = pd.concat(buff)" - ], - "metadata": { - "id": "sRX7ZSyLiiqp" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "df_ret.head(2)" - ], - "metadata": { - "id": "PUa-BEwv3sdg" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "df_ret.tail(2)" - ], - "metadata": { - "id": "nLDzay8vj-ZN" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 日次の順位相関を確認します\n", - "df_ret.groupby(\"Date\")[[\"Target\", \"Rank\"]].corr(method=\"spearman\").xs(\"Target\", level=1)[\"Rank\"].describe()" - ], - "metadata": { - "id": "r6fwYqtDnvMN" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "# 日次の順位相関の累積をプロットします\n", - "df_ret.groupby(\"Date\")[[\"Target\", \"Rank\"]].corr(method=\"spearman\").xs(\"Target\", level=1)[\"Rank\"].cumsum().plot(figsize=(20, 8))" - ], - "metadata": { - "id": "aF99A37208x7" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": [], - "metadata": { - "id": "4fv_Yi22Sjgr" - }, - "execution_count": null, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index 319b61a..5fb9fa6 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,26 +6,10 @@ jquants-api-client-python の使用例集です。データの取得方法や分 Google Colab での使用例です。実際に実行することも可能となっていますのでご活用ください。 -### V2 API (ClientV2) - | ファイル | 内容 | Colab で開く | | :--------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------- | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | [20260119-007-jquants-api-v2-starter.ipynb](20260119-007-jquants-api-v2-starter.ipynb) | J-Quants API V2 の使い方や ClientV2 を使った基本的なデータ取得方法を解説します。 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20260119-007-jquants-api-v2-starter.ipynb) | -### V1 API (Client) - Deprecated - -> **⚠️ 非推奨**: 以下のノートブックは `Client` クラス (V1) を使用しています。V1 API は非推奨となりました。新規の開発には上記の V2 API (ClientV2) をご利用ください。 - -| ファイル | 内容 | Colab で開く | -| :--------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------- | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -| [20220825-000-write-refresh_token.ipynb](20220825-000-write-refresh_token.ipynb) | リフレッシュトークンを Google Drive のファイルに書き込みます。 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20220825-000-write-refresh_token.ipynb) | -| [20220825-001-price-movement.ipynb](20220825-001-price-movement.ipynb) | 株価の推移をプロットします。 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20220825-001-price-movement.ipynb) | -| [20220825-002-sector.ipynb](20220825-002-sector.ipynb) | セクターのリターンをプロットします。 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20220825-002-sector.ipynb) | -| [20220825-003-dividend.ipynb](20220825-003-dividend.ipynb) | 配当利回りを一覧表示します。 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20220825-003-dividend.ipynb) | -| [20220825-004-annual-dividend-history.ipynb](20220825-004-annual-dividend-history.ipynb) | 特定銘柄について年間配当実績の推移をプロットします。 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20220825-004-annual-dividend-history.ipynb) | -| [20220927-005-jquants-api-starter.ipynb](20220927-005-jquants-api-starter.ipynb) | J-Quants API の使い方や J-Quants API を使った簡単なデータ分析への導入を行います。 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20220927-005-jquants-api-starter.ipynb) | -| [20230126-006-mkdeco-jquants-kaggle-8th.ipynb](20230126-006-mkdeco-jquants-kaggle-8th.ipynb) | J-Quants JPX Tokyo Stock Exchange Prediction の8位入賞モデルを J-Quants API を使用して動かしてみるサンプルノートブックとなります。 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/J-Quants/jquants-api-client-python/blob/master/examples/20230126-006-mkdeco-jquants-kaggle-8th.ipynb) | - ## その他の使用例 - [AlpacaDB/jquants-api-sample](https://github.com/AlpacaDB/jquants-api-sample) diff --git a/jquantsapi/__init__.py b/jquantsapi/__init__.py index 7b23914..aed6f67 100644 --- a/jquantsapi/__init__.py +++ b/jquantsapi/__init__.py @@ -1,6 +1,5 @@ # this version will be overwritten by poetry-dynamic-versioning __version__ = "0.0.0" -from .client import Client from .client_v2 import ClientV2 from .enums import MARKET_API_SECTIONS, BulkEndpoint diff --git a/jquantsapi/apis/__init__.py b/jquantsapi/apis/__init__.py index 5b9124f..4fdff2d 100644 --- a/jquantsapi/apis/__init__.py +++ b/jquantsapi/apis/__init__.py @@ -2,7 +2,6 @@ API ごとの実装クラス群をまとめるパッケージ。 - 共通の抽象クラスは `BaseApi` -- v1 向けの実装は `jquantsapi.apis.v1` - v2 向けの実装は `jquantsapi.apis.v2` """ diff --git a/jquantsapi/apis/base.py b/jquantsapi/apis/base.py index 10ac69b..6257b15 100644 --- a/jquantsapi/apis/base.py +++ b/jquantsapi/apis/base.py @@ -8,9 +8,7 @@ class SupportsRequest(Protocol): """ Api クラスが利用するクライアント側の最小インタフェース。 - - v1 の `Client` - - v2 の `ClientV2` - などがこの Protocol を満たす想定。 + `ClientV2` がこの Protocol を満たす想定。 """ JQUANTS_API_BASE: str @@ -26,12 +24,12 @@ class BaseApi(ABC): """ 各エンドポイント単位の API 実装のための抽象クラス。 - v1 / v2 の実装で共通の execute インタフェースを提供する。 + `ClientV2` から呼び出される共通の execute インタフェースを提供する。 """ #: 論理名 (例: "listed_info") name: str - #: バージョン識別子 (例: "v1", "v2") + #: バージョン識別子 (例: "v2") version: str @abstractmethod diff --git a/jquantsapi/apis/v1/__init__.py b/jquantsapi/apis/v1/__init__.py deleted file mode 100644 index 447e585..0000000 --- a/jquantsapi/apis/v1/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -J-Quants API v1 向けの各種 Api 実装。 -""" diff --git a/jquantsapi/apis/v1/derivatives.py b/jquantsapi/apis/v1/derivatives.py deleted file mode 100644 index 693513e..0000000 --- a/jquantsapi/apis/v1/derivatives.py +++ /dev/null @@ -1,146 +0,0 @@ -from __future__ import annotations - -import json -from typing import Any - -import pandas as pd # type: ignore - -from jquantsapi import constants -from jquantsapi.apis.base import BaseApi, SupportsRequest - - -class DerivativesFuturesApiV1(BaseApi): - """ - v1 の先物四本値 API (`/derivatives/futures`) のラッパークラス。 - """ - - name = "derivatives_futures" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - date_yyyymmdd: str = "", - category: str = "", - contract_flag: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - # 元の _get_derivatives_futures_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/derivatives/futures" # type: ignore[attr-defined] - params = { - "category": category, - "date": date_yyyymmdd, - "contract_flag": contract_flag, - } - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - data = d["futures"] - while "pagination_key" in d: - params["pagination_key"] = d["pagination_key"] - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d = json.loads(j) - data += d["futures"] - - df = pd.DataFrame.from_dict(data) - cols = constants.DERIVATIVES_FUTURES_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Code"], inplace=True) - return df[cols] - - -class DerivativesOptionsApiV1(BaseApi): - """ - v1 のオプション四本値 API (`/derivatives/options`) のラッパークラス。 - """ - - name = "derivatives_options" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - date_yyyymmdd: str = "", - category: str = "", - contract_flag: str = "", - code: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - # 元の _get_derivatives_options_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/derivatives/options" # type: ignore[attr-defined] - params = { - "category": category, - "date": date_yyyymmdd, - "contract_flag": contract_flag, - "code": code, - } - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - data = d["options"] - while "pagination_key" in d: - params["pagination_key"] = d["pagination_key"] - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d = json.loads(j) - data += d["options"] - - df = pd.DataFrame.from_dict(data) - cols = constants.DERIVATIVES_OPTIONS_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Code"], inplace=True) - return df[cols] - - -class OptionIndexOptionApiV1(BaseApi): - """ - v1 のオプション指数四本値 API (`/option/index_option`) のラッパークラス。 - """ - - name = "option_index_option" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - date_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - # 元の _get_option_index_option_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/option/index_option" # type: ignore[attr-defined] - params = {"date": date_yyyymmdd} - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - data = d["index_option"] - while "pagination_key" in d: - params["pagination_key"] = d["pagination_key"] - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d = json.loads(j) - data += d["index_option"] - - df = pd.DataFrame.from_dict(data) - cols = constants.OPTION_INDEX_OPTION_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Code"], inplace=True) - return df[cols] diff --git a/jquantsapi/apis/v1/fins.py b/jquantsapi/apis/v1/fins.py deleted file mode 100644 index 4e43e7f..0000000 --- a/jquantsapi/apis/v1/fins.py +++ /dev/null @@ -1,227 +0,0 @@ -from __future__ import annotations - -import json -from typing import Any - -import pandas as pd # type: ignore - -from jquantsapi import constants -from jquantsapi.apis.base import BaseApi, SupportsRequest - - -class FinsStatementsApiV1(BaseApi): - """ - v1 の財務情報 API (`/fins/statements`) のラッパークラス。 - """ - - name = "fins_statements" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - code: str = "", - date_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/fins/statements` を実行し、財務情報を DataFrame で返す。 - """ - url = f"{client.JQUANTS_API_BASE}/fins/statements" # type: ignore[attr-defined] - params: dict[str, Any] = {"code": code, "date": date_yyyymmdd} - - data: list[dict[str, Any]] = [] - pagination_key: str = "" - while True: - req_params = dict(params) - if pagination_key != "": - req_params["pagination_key"] = pagination_key - - resp = client._get(url, req_params) # type: ignore[arg-type] - resp.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - d: dict[str, Any] = json.loads(resp.text) - page = d.get("statements", []) - if isinstance(page, list): - data.extend(page) - - pagination_key = d.get("pagination_key", "") - if not pagination_key: - break - df = pd.DataFrame.from_dict(data) - cols = constants.FINS_STATEMENTS_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["DisclosedDate"] = pd.to_datetime(df["DisclosedDate"], format="%Y-%m-%d") - df["CurrentPeriodStartDate"] = pd.to_datetime( - df["CurrentPeriodStartDate"], format="%Y-%m-%d" - ) - df["CurrentPeriodEndDate"] = pd.to_datetime( - df["CurrentPeriodEndDate"], format="%Y-%m-%d" - ) - df["CurrentFiscalYearStartDate"] = pd.to_datetime( - df["CurrentFiscalYearStartDate"], format="%Y-%m-%d" - ) - df["CurrentFiscalYearEndDate"] = pd.to_datetime( - df["CurrentFiscalYearEndDate"], format="%Y-%m-%d" - ) - df["NextFiscalYearStartDate"] = pd.to_datetime( - df["NextFiscalYearStartDate"], format="%Y-%m-%d" - ) - df["NextFiscalYearEndDate"] = pd.to_datetime( - df["NextFiscalYearEndDate"], format="%Y-%m-%d" - ) - df.sort_values(["DisclosedDate", "DisclosedTime", "LocalCode"], inplace=True) - return df[cols] - - -class FinsFsDetailsApiV1(BaseApi): - """ - v1 の財務諸表(BS/PL) API (`/fins/fs_details`) のラッパークラス。 - """ - - name = "fins_fs_details" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - code: str = "", - date_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/fins/fs_details` を実行し、財務諸表(BS/PL)を DataFrame で返す。 - """ - url = f"{client.JQUANTS_API_BASE}/fins/fs_details" # type: ignore[attr-defined] - params: dict[str, Any] = {"code": code, "date": date_yyyymmdd} - - data: list[dict[str, Any]] = [] - pagination_key: str = "" - while True: - req_params = dict(params) - if pagination_key != "": - req_params["pagination_key"] = pagination_key - - resp = client._get(url, req_params) # type: ignore[arg-type] - resp.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - d: dict[str, Any] = json.loads(resp.text) - page = d.get("fs_details", []) - if isinstance(page, list): - data.extend(page) - - pagination_key = d.get("pagination_key", "") - if not pagination_key: - break - df = pd.json_normalize(data=data) - cols = constants.FINS_FS_DETAILS_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["DisclosedDate"] = pd.to_datetime(df["DisclosedDate"], format="%Y-%m-%d") - df.sort_values(["DisclosedDate", "DisclosedTime", "LocalCode"], inplace=True) - return df - - -class FinsDividendApiV1(BaseApi): - """ - v1 の配当金情報 API (`/fins/dividend`) のラッパークラス。 - """ - - name = "fins_dividend" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/fins/dividend` を実行し、配当金情報を DataFrame で返す。 - """ - url = f"{client.JQUANTS_API_BASE}/fins/dividend" # type: ignore[attr-defined] - params: dict[str, Any] = {"code": code} - if date_yyyymmdd != "": - params["date"] = date_yyyymmdd - else: - if from_yyyymmdd != "": - params["from"] = from_yyyymmdd - if to_yyyymmdd != "": - params["to"] = to_yyyymmdd - - data: list[dict[str, Any]] = [] - pagination_key: str = "" - while True: - req_params = dict(params) - if pagination_key != "": - req_params["pagination_key"] = pagination_key - - resp = client._get(url, req_params) # type: ignore[arg-type] - resp.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - d: dict[str, Any] = json.loads(resp.text) - page = d.get("dividend", []) - if isinstance(page, list): - data.extend(page) - - pagination_key = d.get("pagination_key", "") - if not pagination_key: - break - df = pd.DataFrame.from_dict(data) - cols = constants.FINS_DIVIDEND_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["AnnouncementDate"] = pd.to_datetime( - df["AnnouncementDate"], format="%Y-%m-%d" - ) - df.sort_values(["Code"], inplace=True) - return df[cols] - - -class FinsAnnouncementApiV1(BaseApi): - """ - v1 の決算発表予定 API (`/fins/announcement`) のラッパークラス。 - """ - - name = "fins_announcement" - version = "v1" - - def execute( - self, - client: SupportsRequest, - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/fins/announcement` を実行し、決算発表予定データを DataFrame で返す。 - """ - url = f"{client.JQUANTS_API_BASE}/fins/announcement" # type: ignore[attr-defined] - params: dict[str, Any] = {} - - data: list[dict[str, Any]] = [] - pagination_key: str = "" - while True: - req_params = dict(params) - if pagination_key != "": - req_params["pagination_key"] = pagination_key - - resp = client._get(url, req_params) # type: ignore[arg-type] - resp.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - d: dict[str, Any] = json.loads(resp.text) - page = d.get("announcement", []) - if isinstance(page, list): - data.extend(page) - - pagination_key = d.get("pagination_key", "") - if not pagination_key: - break - df = pd.DataFrame.from_dict(data) - cols = constants.FINS_ANNOUNCEMENT_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Date", "Code"], inplace=True) - return df[cols] diff --git a/jquantsapi/apis/v1/indices.py b/jquantsapi/apis/v1/indices.py deleted file mode 100644 index 66fe01e..0000000 --- a/jquantsapi/apis/v1/indices.py +++ /dev/null @@ -1,106 +0,0 @@ -from __future__ import annotations - -import json -from typing import Any - -import pandas as pd # type: ignore - -from jquantsapi import constants -from jquantsapi.apis.base import BaseApi, SupportsRequest - - -class IndicesApiV1(BaseApi): - """ - v1 の指数四本値 API (`/indices`) のラッパークラス。 - """ - - name = "indices" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - # 元の _get_indices_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/indices" # type: ignore[attr-defined] - params = {"code": code} - if date_yyyymmdd != "": - params["date"] = date_yyyymmdd - else: - if from_yyyymmdd != "": - params["from"] = from_yyyymmdd - if to_yyyymmdd != "": - params["to"] = to_yyyymmdd - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - data = d["indices"] - while "pagination_key" in d: - params["pagination_key"] = d["pagination_key"] - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d = json.loads(j) - data += d["indices"] - - df = pd.DataFrame.from_dict(data) - cols = constants.INDICES_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Code", "Date"], inplace=True) - return df[cols] - - -class IndicesTopixApiV1(BaseApi): - """ - v1 の TOPIX 指数四本値 API (`/indices/topix`) のラッパークラス。 - """ - - name = "indices_topix" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - # 元の _get_indices_topix_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/indices/topix" # type: ignore[attr-defined] - params = {} - if from_yyyymmdd != "": - params["from"] = from_yyyymmdd - if to_yyyymmdd != "": - params["to"] = to_yyyymmdd - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - data = d["topix"] - while "pagination_key" in d: - params["pagination_key"] = d["pagination_key"] - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d = json.loads(j) - data += d["topix"] - - df = pd.DataFrame.from_dict(data) - cols = constants.INDICES_TOPIX_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Date"], inplace=True) - return df[cols] diff --git a/jquantsapi/apis/v1/listed.py b/jquantsapi/apis/v1/listed.py deleted file mode 100644 index 513e839..0000000 --- a/jquantsapi/apis/v1/listed.py +++ /dev/null @@ -1,75 +0,0 @@ -from __future__ import annotations - -import json -from typing import Any - -import pandas as pd # type: ignore - -from jquantsapi import constants -from jquantsapi.apis.base import BaseApi, SupportsRequest - - -class ListedInfoApiV1(BaseApi): - """ - v1 の上場銘柄一覧 API (`/listed/info`) のラッパークラス。 - """ - - name = "listed_info" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - code: str = "", - date_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - v1 `/listed/info` を実行し、上場銘柄情報を DataFrame で返す。 - - Args: - client: v1 `Client` インスタンスを想定 - code: 銘柄コード (任意) - date_yyyymmdd: 基準日 (YYYYMMDD or YYYY-MM-DD, 任意) - """ - url = f"{client.JQUANTS_API_BASE}/listed/info" - - # ページングしながら全件取得 - all_info: list[dict[str, Any]] = [] - base_params: dict[str, Any] = {} - if code != "": - base_params["code"] = code - if date_yyyymmdd != "": - base_params["date"] = date_yyyymmdd - - pagination_key = "" - while True: - params = dict(base_params) - if pagination_key != "": - params["pagination_key"] = pagination_key - - resp = client._get(url, params) # type: ignore[arg-type] - resp.encoding = client.RAW_ENCODING - payload = json.loads(resp.text) - - data = payload.get("info", []) - if isinstance(data, list): - all_info.extend(data) - - pagination_key = payload.get("pagination_key", "") - if not pagination_key: - break - - df = pd.DataFrame.from_dict(all_info) - - standard_premium_flag = "MarginCode" in df.columns - if standard_premium_flag: - cols = constants.LISTED_INFO_STANDARD_PREMIUM_COLUMNS - else: - cols = constants.LISTED_INFO_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values("Code", inplace=True) - return df[cols].reset_index(drop=True) diff --git a/jquantsapi/apis/v1/markets.py b/jquantsapi/apis/v1/markets.py deleted file mode 100644 index c9093e2..0000000 --- a/jquantsapi/apis/v1/markets.py +++ /dev/null @@ -1,391 +0,0 @@ -from __future__ import annotations - -import json -from typing import Any, Union - -import pandas as pd # type: ignore - -from jquantsapi import constants, enums -from jquantsapi.apis.base import BaseApi, SupportsRequest - - -class MarketsTradesSpecApiV1(BaseApi): - """ - v1 の投資部門別売買状況 API (`/markets/trades_spec`) のラッパークラス。 - """ - - name = "markets_trades_spec" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - section: Union[str, enums.MARKET_API_SECTIONS] = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/markets/trades_spec` を実行し、投資部門別売買状況を DataFrame で返す。 - - Args: - client: v1 `Client` インスタンスを想定 - section: section name (e.g. "TSEPrime" or MARKET_API_SECTIONS.TSEPrime) - from_yyyymmdd: starting point of data period (e.g. 20210901 or 2021-09-01) - to_yyyymmdd: end point of data period (e.g. 20210907 or 2021-09-07) - """ - # 元の _get_markets_trades_spec_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/markets/trades_spec" # type: ignore[attr-defined] - params = {} - if section != "": - params["section"] = section - if from_yyyymmdd != "": - params["from"] = from_yyyymmdd - if to_yyyymmdd != "": - params["to"] = to_yyyymmdd - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - data: list[dict[str, Any]] = d["trades_spec"] - while "pagination_key" in d: - params["pagination_key"] = d["pagination_key"] - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d = json.loads(j) - data += d["trades_spec"] - df = pd.DataFrame.from_dict(data) - cols = constants.MARKETS_TRADES_SPEC - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["PublishedDate"] = pd.to_datetime(df["PublishedDate"], format="%Y-%m-%d") - df["StartDate"] = pd.to_datetime(df["StartDate"], format="%Y-%m-%d") - df["EndDate"] = pd.to_datetime(df["EndDate"], format="%Y-%m-%d") - df.sort_values(["PublishedDate", "Section"], inplace=True) - return df[cols] - - -class MarketsWeeklyMarginInterestApiV1(BaseApi): - """ - v1 の信用取引週末残高 API (`/markets/weekly_margin_interest`) のラッパークラス。 - """ - - name = "markets_weekly_margin_interest" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/markets/weekly_margin_interest` を実行し、信用取引週末残高を DataFrame で返す。 - """ - # 元の _get_markets_weekly_margin_interest_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/markets/weekly_margin_interest" # type: ignore[attr-defined] - params = {"code": code} - if date_yyyymmdd != "": - params["date"] = date_yyyymmdd - else: - if from_yyyymmdd != "": - params["from"] = from_yyyymmdd - if to_yyyymmdd != "": - params["to"] = to_yyyymmdd - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - data: list[dict[str, Any]] = d["weekly_margin_interest"] - while "pagination_key" in d: - params["pagination_key"] = d["pagination_key"] - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d = json.loads(j) - data += d["weekly_margin_interest"] - df = pd.DataFrame.from_dict(data) - cols = constants.MARKETS_WEEKLY_MARGIN_INTEREST - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Date", "Code"], inplace=True) - return df[cols] - - -class MarketsTradingCalendarApiV1(BaseApi): - """ - v1 の取引カレンダー API (`/markets/trading_calendar`) のラッパークラス。 - """ - - name = "markets_trading_calendar" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - holiday_division: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/markets/trading_calendar` を実行し、取引カレンダーデータを DataFrame で返す。 - """ - # 元の _get_markets_trading_calendar_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/markets/trading_calendar" # type: ignore[attr-defined] - params = {} - if holiday_division != "": - params["holidaydivision"] = holiday_division - if from_yyyymmdd != "": - params["from"] = from_yyyymmdd - if to_yyyymmdd != "": - params["to"] = to_yyyymmdd - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - df = pd.DataFrame.from_dict(d["trading_calendar"]) - cols = constants.MARKETS_TRADING_CALENDAR - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Date"], inplace=True) - return df[cols] - - -class MarketsShortSellingApiV1(BaseApi): - """ - v1 の業種別空売り比率 API (`/markets/short_selling`) のラッパークラス。 - """ - - name = "markets_short_selling" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - sector_33_code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/markets/short_selling` を実行し、業種別空売り比率データを DataFrame で返す。 - """ - # 元の _get_markets_short_selling_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/markets/short_selling" # type: ignore[attr-defined] - params = {"sector33code": sector_33_code} - if date_yyyymmdd != "": - params["date"] = date_yyyymmdd - else: - if from_yyyymmdd != "": - params["from"] = from_yyyymmdd - if to_yyyymmdd != "": - params["to"] = to_yyyymmdd - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - data: list[dict[str, Any]] = d["short_selling"] - while "pagination_key" in d: - params["pagination_key"] = d["pagination_key"] - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d = json.loads(j) - data += d["short_selling"] - df = pd.DataFrame.from_dict(data) - cols = constants.MARKET_SHORT_SELLING_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Date", "Sector33Code"], inplace=True) - return df[cols] - - -class MarketsBreakdownApiV1(BaseApi): - """ - v1 の売買内訳 API (`/markets/breakdown`) のラッパークラス。 - """ - - name = "markets_breakdown" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/markets/breakdown` を実行し、売買内訳データを DataFrame で返す。 - """ - # 元の _get_markets_breakdown_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/markets/breakdown" # type: ignore[attr-defined] - params = {"code": code} - if date_yyyymmdd != "": - params["date"] = date_yyyymmdd - else: - if from_yyyymmdd != "": - params["from"] = from_yyyymmdd - if to_yyyymmdd != "": - params["to"] = to_yyyymmdd - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - data: list[dict[str, Any]] = d["breakdown"] - while "pagination_key" in d: - params["pagination_key"] = d["pagination_key"] - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d = json.loads(j) - data += d["breakdown"] - df = pd.DataFrame.from_dict(data) - cols = constants.MARKETS_BREAKDOWN_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Code"], inplace=True) - return df[cols] - - -class MarketsShortSellingPositionsApiV1(BaseApi): - """ - v1 の空売り残高報告 API (`/markets/short_selling_positions`) のラッパークラス。 - """ - - name = "markets_short_selling_positions" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - code: str = "", - disclosed_date: str = "", - disclosed_date_from: str = "", - disclosed_date_to: str = "", - calculated_date: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/markets/short_selling_positions` を実行し、空売り残高報告データを DataFrame で返す。 - """ - # 元の _get_markets_short_selling_positions_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/markets/short_selling_positions" # type: ignore[attr-defined] - params = {} - if code != "": - params["code"] = code - if disclosed_date != "": - params["disclosed_date"] = disclosed_date - if disclosed_date_from != "": - params["disclosed_date_from"] = disclosed_date_from - if disclosed_date_to != "": - params["disclosed_date_to"] = disclosed_date_to - if calculated_date != "": - params["calculated_date"] = calculated_date - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - data: list[dict[str, Any]] = d["short_selling_positions"] - while "pagination_key" in d: - params["pagination_key"] = d["pagination_key"] - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d = json.loads(j) - data += d["short_selling_positions"] - df = pd.DataFrame.from_dict(data) - cols = constants.SHORT_SELLING_POSITIONS_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["DisclosedDate"] = pd.to_datetime( - df["DisclosedDate"], format="%Y-%m-%d", errors="coerce" - ) - df["CalculatedDate"] = pd.to_datetime( - df["CalculatedDate"], format="%Y-%m-%d", errors="coerce" - ) - df["CalculationInPreviousReportingDate"] = pd.to_datetime( - df["CalculationInPreviousReportingDate"], format="%Y-%m-%d", errors="coerce" - ) - df.sort_values(["DisclosedDate", "CalculatedDate", "Code"], inplace=True) - return df[cols] - - -class MarketsDailyMarginInterestApiV1(BaseApi): - """ - v1 の日々公表信用取引残高 API (`/markets/daily_margin_interest`) のラッパークラス。 - """ - - name = "markets_daily_margin_interest" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/markets/daily_margin_interest` を実行し、日々公表信用取引残高を DataFrame で返す。 - """ - # 元の _get_markets_daily_margin_interest_raw の実装を統合 - url = f"{client.JQUANTS_API_BASE}/markets/daily_margin_interest" # type: ignore[attr-defined] - params = {} - if code != "": - params["code"] = code - if date_yyyymmdd != "": - params["date"] = date_yyyymmdd - else: - if from_yyyymmdd != "": - params["from"] = from_yyyymmdd - if to_yyyymmdd != "": - params["to"] = to_yyyymmdd - - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d: dict[str, Any] = json.loads(j) - data: list[dict[str, Any]] = d["daily_margin_interest"] - while "pagination_key" in d: - params["pagination_key"] = d["pagination_key"] - ret = client._get(url, params) # type: ignore[attr-defined] - ret.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - j = ret.text - d = json.loads(j) - data += d["daily_margin_interest"] - df = pd.json_normalize(data=data) - cols = constants.DAILY_MARGIN_INTEREST_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["PublishedDate"] = pd.to_datetime(df["PublishedDate"], format="%Y-%m-%d") - df["ApplicationDate"] = pd.to_datetime(df["ApplicationDate"], format="%Y-%m-%d") - df.sort_values(["Code", "PublishedDate"], inplace=True) - return df[cols] diff --git a/jquantsapi/apis/v1/prices.py b/jquantsapi/apis/v1/prices.py deleted file mode 100644 index 3bfe4b5..0000000 --- a/jquantsapi/apis/v1/prices.py +++ /dev/null @@ -1,127 +0,0 @@ -from __future__ import annotations - -import json -from typing import Any - -import pandas as pd # type: ignore - -from jquantsapi import constants -from jquantsapi.apis.base import BaseApi, SupportsRequest - - -class PricesDailyQuotesApiV1(BaseApi): - """ - v1 の株価四本値 API (`/prices/daily_quotes`) のラッパークラス。 - """ - - name = "prices_daily_quotes" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/prices/daily_quotes` を実行し、株価情報を DataFrame で返す。 - - Args: - client: v1 `Client` インスタンスを想定 - code: 銘柄コード - from_yyyymmdd: 取得開始日 - to_yyyymmdd: 取得終了日 - date_yyyymmdd: 取得日 - """ - url = f"{client.JQUANTS_API_BASE}/prices/daily_quotes" # type: ignore[attr-defined] - params: dict[str, Any] = {"code": code} - if date_yyyymmdd != "": - params["date"] = date_yyyymmdd - else: - if from_yyyymmdd != "": - params["from"] = from_yyyymmdd - if to_yyyymmdd != "": - params["to"] = to_yyyymmdd - - data: list[dict[str, Any]] = [] - pagination_key: str = "" - while True: - req_params = dict(params) - if pagination_key != "": - req_params["pagination_key"] = pagination_key - - resp = client._get(url, req_params) # type: ignore[arg-type] - resp.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - d: dict[str, Any] = json.loads(resp.text) - page = d.get("daily_quotes", []) - if isinstance(page, list): - data.extend(page) - - pagination_key = d.get("pagination_key", "") - if not pagination_key: - break - - df = pd.DataFrame.from_dict(data) - - premium_flag = "MorningClose" in df.columns - if premium_flag: - cols = constants.PRICES_DAILY_QUOTES_PREMIUM_COLUMNS - else: - cols = constants.PRICES_DAILY_QUOTES_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Code", "Date"], inplace=True) - return df[cols] - - -class PricesPricesAmApiV1(BaseApi): - """ - v1 の前場四本値 API (`/prices/prices_am`) のラッパークラス。 - """ - - name = "prices_prices_am" - version = "v1" - - def execute( - self, - client: SupportsRequest, - *, - code: str = "", - **kwargs: Any, - ) -> pd.DataFrame: - """ - `/prices/prices_am` を実行し、前場四本値を DataFrame で返す。 - - Args: - client: v1 `Client` インスタンスを想定 - code: issue code (e.g. 27800 or 2780) - """ - url = f"{client.JQUANTS_API_BASE}/prices/prices_am" # type: ignore[attr-defined] - params: dict[str, Any] = {"code": code} - - resp = client._get(url, params) # type: ignore[arg-type] - resp.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - d: dict[str, Any] = json.loads(resp.text) - if d.get("message"): - return d["message"] # type: ignore[return-value] - data: list[dict[str, Any]] = d.get("prices_am", []) - while "pagination_key" in d: - req_params = dict(params) - req_params["pagination_key"] = d["pagination_key"] - resp = client._get(url, req_params) # type: ignore[arg-type] - resp.encoding = client.RAW_ENCODING # type: ignore[attr-defined] - d = json.loads(resp.text) - data += d.get("prices_am", []) - df = pd.DataFrame.from_dict(data) - cols = constants.PRICES_PRICES_AM_COLUMNS - if len(df) == 0: - return pd.DataFrame([], columns=cols) - df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d") - df.sort_values(["Code"], inplace=True) - return df[cols] diff --git a/jquantsapi/client.py b/jquantsapi/client.py deleted file mode 100644 index 7b5ddce..0000000 --- a/jquantsapi/client.py +++ /dev/null @@ -1,1391 +0,0 @@ -import os -import platform -import sys -from concurrent.futures import ThreadPoolExecutor, as_completed -from datetime import datetime -from pathlib import Path -from typing import Any, Mapping, Optional, Union - -import pandas as pd # type: ignore -import requests -from requests.adapters import HTTPAdapter -from requests.exceptions import HTTPError -from tenacity import ( - retry, - retry_if_exception_type, - stop_after_attempt, - wait_exponential, -) -from urllib3.util import Retry - -from jquantsapi import __version__, constants, enums -from jquantsapi.apis.v1.derivatives import ( - DerivativesFuturesApiV1, - DerivativesOptionsApiV1, - OptionIndexOptionApiV1, -) -from jquantsapi.apis.v1.fins import ( - FinsAnnouncementApiV1, - FinsDividendApiV1, - FinsFsDetailsApiV1, - FinsStatementsApiV1, -) -from jquantsapi.apis.v1.indices import IndicesApiV1, IndicesTopixApiV1 -from jquantsapi.apis.v1.listed import ListedInfoApiV1 -from jquantsapi.apis.v1.markets import ( - MarketsBreakdownApiV1, - MarketsDailyMarginInterestApiV1, - MarketsShortSellingApiV1, - MarketsShortSellingPositionsApiV1, - MarketsTradesSpecApiV1, - MarketsTradingCalendarApiV1, - MarketsWeeklyMarginInterestApiV1, -) -from jquantsapi.apis.v1.prices import PricesDailyQuotesApiV1, PricesPricesAmApiV1 - -if sys.version_info >= (3, 11): - import tomllib -else: - import tomli as tomllib - -if sys.version_info >= (3, 13): - from warnings import deprecated # type: ignore[attr-defined] -else: - from typing_extensions import deprecated - - -DatetimeLike = Union[datetime, pd.Timestamp, str] -_Data = Union[str, Mapping[str, Any]] - - -class TokenAuthRefreshBadRequestException(Exception): - pass - - -@deprecated( - "Client (V1) is deprecated and will be removed in a future version. Please use ClientV2 instead." -) -class Client: - """ - J-Quants API からデータを取得する - ref. https://jpx.gitbook.io/j-quants-ja/ - - .. deprecated:: - This class is deprecated. Use :class:`ClientV2` instead. - """ - - JQUANTS_API_BASE = "https://api.jquants.com/v1" - MAX_WORKERS = 5 - USER_AGENT = "jqapi-python" - USER_AGENT_VERSION = __version__ - RAW_ENCODING = "utf-8" - - def __init__( - self, - refresh_token: Optional[str] = None, - *, - mail_address: Optional[str] = None, - password: Optional[str] = None, - ) -> None: - """ - Args: - refresh_token: J-Quants API refresh token - mail_address: J-Quants API login email address - password: J-Quants API login password - """ - config = self._load_config() - - self._mail_address = config["mail_address"] - if mail_address is not None: - self._mail_address = mail_address - - self._password = config["password"] - if password is not None: - self._password = password - - self._refresh_token = config["refresh_token"] - if refresh_token is not None: - self._refresh_token = refresh_token - - if self._refresh_token != "": - self._refresh_token_expire = pd.Timestamp.utcnow() + pd.Timedelta( - 6, unit="D" - ) - else: - self._refresh_token_expire = pd.Timestamp.utcnow() - - self._id_token = "" - self._id_token_expire = pd.Timestamp.utcnow() - self._session: Optional[requests.Session] = None - - # API 実装 (v1) - self._listed_info_api = ListedInfoApiV1() - self._prices_daily_quotes_api = PricesDailyQuotesApiV1() - self._prices_prices_am_api = PricesPricesAmApiV1() - self._markets_trades_spec_api = MarketsTradesSpecApiV1() - self._markets_weekly_margin_interest_api = MarketsWeeklyMarginInterestApiV1() - self._indices_api = IndicesApiV1() - self._indices_topix_api = IndicesTopixApiV1() - self._derivatives_futures_api = DerivativesFuturesApiV1() - self._derivatives_options_api = DerivativesOptionsApiV1() - self._option_index_option_api = OptionIndexOptionApiV1() - self._markets_weekly_margin_interest_api = MarketsWeeklyMarginInterestApiV1() - self._markets_short_selling_api = MarketsShortSellingApiV1() - self._markets_breakdown_api = MarketsBreakdownApiV1() - self._markets_short_selling_positions_api = MarketsShortSellingPositionsApiV1() - self._markets_daily_margin_interest_api = MarketsDailyMarginInterestApiV1() - self._markets_trading_calendar_api = MarketsTradingCalendarApiV1() - self._fins_statements_api = FinsStatementsApiV1() - self._fins_fs_details_api = FinsFsDetailsApiV1() - self._fins_dividend_api = FinsDividendApiV1() - self._fins_announcement_api = FinsAnnouncementApiV1() - - if ((self._mail_address == "") or (self._password == "")) and ( - self._refresh_token == "" - ): - raise ValueError( - "Either mail_address/password or refresh_token is required." - ) - if (self._mail_address != "") and ("@" not in self._mail_address): - raise ValueError("mail_address must contain '@' character.") - - def _is_colab(self) -> bool: - """ - Return True if running in colab - """ - return "google.colab" in sys.modules - - def _load_config(self) -> dict: - """ - load config from files and environment variables - - Args: - N/A - Returns: - dict: configurations - """ - config: dict = {} - - # colab config - if self._is_colab(): - colab_config_path = ( - "/content/drive/MyDrive/drive_ws/secret/jquants-api.toml" - ) - config = {**config, **self._read_config(colab_config_path)} - - # user default config - user_config_path = f"{Path.home()}/.jquants-api/jquants-api.toml" - config = {**config, **self._read_config(user_config_path)} - - # current dir config - current_config_path = "jquants-api.toml" - config = {**config, **self._read_config(current_config_path)} - - # env specified config - if "JQUANTS_API_CLIENT_CONFIG_FILE" in os.environ: - env_config_path = os.environ["JQUANTS_API_CLIENT_CONFIG_FILE"] - config = {**config, **self._read_config(env_config_path)} - - # env vars - config["mail_address"] = os.environ.get( - "JQUANTS_API_MAIL_ADDRESS", config.get("mail_address", "") - ) - config["password"] = os.environ.get( - "JQUANTS_API_PASSWORD", config.get("password", "") - ) - config["refresh_token"] = os.environ.get( - "JQUANTS_API_REFRESH_TOKEN", config.get("refresh_token", "") - ) - - return config - - def _read_config(self, config_path: str) -> dict: - """ - read config from a toml file - - Params: - config_path: a path to a toml file - """ - if not os.path.isfile(config_path): - return {} - - with open(config_path, mode="rb") as f: - ret = tomllib.load(f) - - if "jquants-api-client" not in ret: - return {} - - return ret["jquants-api-client"] - - def _base_headers(self) -> dict: - """ - J-Quants API にアクセスする際にヘッダーにIDトークンを設定 - """ - id_token = self.get_id_token() - headers = { - "Authorization": f"Bearer {id_token}", - "User-Agent": f"{self.USER_AGENT}/{self.USER_AGENT_VERSION} p/{platform.python_version()}", - } - return headers - - def _request_session( - self, - status_forcelist: Optional[list[int]] = None, - allowed_methods: Optional[list[str]] = None, - ) -> requests.Session: - """ - requests の session 取得 - - リトライを設定 - - Args: - status_forcelist: リトライ対象のステータスコード - allowed_methods: リトライ対象のメソッド - Returns: - requests.session - """ - if status_forcelist is None: - status_forcelist = [429, 500, 502, 503, 504] - if allowed_methods is None: - allowed_methods = ["HEAD", "GET", "OPTIONS", "POST"] - - if self._session is None: - retry_strategy = Retry( - total=3, - status_forcelist=status_forcelist, - allowed_methods=allowed_methods, - ) - adapter = HTTPAdapter( - # 安全のため並列スレッド数に更に10追加しておく - pool_connections=self.MAX_WORKERS + 10, - pool_maxsize=self.MAX_WORKERS + 10, - max_retries=retry_strategy, - ) - self._session = requests.Session() - self._session.mount("https://", adapter) - - return self._session - - def _get(self, url: str, params: Optional[dict] = None) -> requests.Response: - """ - requests の get 用ラッパー - - ヘッダーにアクセストークンを設定 - タイムアウトを設定 - - Args: - url: アクセスするURL - params: パラメーター - - Returns: - requests.Response: レスポンス - """ - s = self._request_session() - - headers = self._base_headers() - ret = s.get(url, params=params, headers=headers, timeout=30) - if ret.status_code == 400: - msg = f"{ret.status_code} for url: {ret.url} body: {ret.text}" - raise HTTPError(msg, response=ret) - ret.raise_for_status() - return ret - - def _post( - self, - url: str, - data: Optional[_Data] = None, - json: Optional[Any] = None, - headers: Optional[dict] = None, - ) -> requests.Response: - """ - requests の post 用ラッパー - - タイムアウトを設定 - - Args: - url: アクセスするURL - payload: 送信するデータ - headers: HTTPヘッダ - - Returns: - requests.Response: レスポンス - """ - s = self._request_session() - - base_headers = { - "User-Agent": f"{self.USER_AGENT}/{self.USER_AGENT_VERSION} p/{platform.python_version()}", - } - if headers is not None: - base_headers.update(headers) - - ret = s.post(url, data=data, json=json, headers=base_headers, timeout=30) - ret.raise_for_status() - return ret - - # /token - def get_refresh_token( - self, mail_address: Optional[str] = None, password: Optional[str] = None - ) -> str: - """ - get J-Quants API refresh token - - Params: - mail_address: J-Quants API login email address - password: J-Quants API login password - Returns: - refresh_token: J-Quants API refresh token - """ - if self._refresh_token_expire > pd.Timestamp.utcnow(): - return self._refresh_token - - if mail_address is None: - mail_address = self._mail_address - if password is None: - password = self._password - - if mail_address == "" or password == "": - raise ValueError("mail_address/password are required") - if (mail_address is not None) and ("@" not in mail_address): - raise ValueError("mail_address must contain '@' character.") - - url = f"{self.JQUANTS_API_BASE}/token/auth_user" - data = { - "mailaddress": mail_address, - "password": password, - } - ret = self._post(url, json=data) - refresh_token = ret.json()["refreshToken"] - self._refresh_token = refresh_token - self._refresh_token_expire = pd.Timestamp.utcnow() + pd.Timedelta(6, unit="D") - return self._refresh_token - - @retry( - retry=retry_if_exception_type(TokenAuthRefreshBadRequestException), - stop=stop_after_attempt(3), - wait=wait_exponential(multiplier=1, min=5, max=300), - ) - def get_id_token(self, refresh_token: Optional[str] = None) -> str: - """ - get J-Quants API id_token - - Params: - refresh_token: J-Quants API refresh token - Returns: - id_token: J-Quants API id token - """ - if self._id_token_expire > pd.Timestamp.utcnow(): - return self._id_token - - if refresh_token is not None: - _refresh_token = refresh_token - else: - _refresh_token = self.get_refresh_token() - - url = ( - f"{self.JQUANTS_API_BASE}/token/auth_refresh?refreshtoken={_refresh_token}" - ) - try: - ret = self._post(url) - except HTTPError as e: - # retry if: - # - refresh_token is not provided as a parameter - # - error is 400 bad request (refresh_token expire) - # - mail_address and password are provided - if ( - refresh_token is None - and e.response.status_code == 400 - and self._mail_address != "" - and self._password != "" - ): - # clear tokens for the next try - self._refresh_token = "" - self._refresh_token_expire = pd.Timestamp.utcnow() - self._id_token = "" - self._id_token_expire = pd.Timestamp.utcnow() - # raise for retrying - raise TokenAuthRefreshBadRequestException(e) - raise e - id_token = ret.json()["idToken"] - self._id_token = id_token - self._id_token_expire = pd.Timestamp.utcnow() + pd.Timedelta(23, unit="hour") - return self._id_token - - def get_listed_info(self, code: str = "", date_yyyymmdd: str = "") -> pd.DataFrame: - """ - Get listed companies - - Args: - code: Issue code (Optional) - date: YYYYMMDD or YYYY-MM-DD (Optional) - - Returns: - pd.DataFrame: listed companies (sorted by Code) - """ - return self._listed_info_api.execute( - self, - code=code, - date_yyyymmdd=date_yyyymmdd, - ) - - @staticmethod - def get_market_segments() -> pd.DataFrame: - """ - Get market segment code and name - - Args: - N/A - - Returns: - pd.DataFrame: market segment code and name - - """ - - df = pd.DataFrame( - constants.MARKET_SEGMENT_DATA, columns=constants.MARKET_SEGMENT_COLUMNS - ) - df.sort_values(constants.MARKET_SEGMENT_COLUMNS[0], inplace=True) - return df - - def get_17_sectors(self) -> pd.DataFrame: - """ - Get 17-sector code and name - ref. https://jpx.gitbook.io/j-quants-api-en/api-reference/listed-api/17-sector - - Args: - N/A - - Returns: - pd.DataFrame: 17-sector code and name - """ - df = pd.DataFrame(constants.SECTOR_17_DATA, columns=constants.SECTOR_17_COLUMNS) - df.sort_values(constants.SECTOR_17_COLUMNS[0], inplace=True) - return df - - def get_33_sectors(self) -> pd.DataFrame: - """ - Get 33-sector code and name - ref. https://jpx.gitbook.io/j-quants-api-en/api-reference/listed-api/33-sector - - Args: - N/A - - Returns: - pd.DataFrame: 33-sector code and name - """ - df = pd.DataFrame(constants.SECTOR_33_DATA, columns=constants.SECTOR_33_COLUMNS) - df.sort_values(constants.SECTOR_33_COLUMNS[0], inplace=True) - return df - - def get_list(self, code: str = "", date_yyyymmdd: str = "") -> pd.DataFrame: - """ - Get listed companies (incl English name for sectors/segments) - - Args: - code: Issue code (Optional) - date: YYYYMMDD or YYYY-MM-DD (Optional) - - Returns: - pd.DataFrame: listed companies - """ - df_list = self.get_listed_info(code=code, date_yyyymmdd=date_yyyymmdd) - df_17_sectors = self.get_17_sectors()[ - ["Sector17Code", "Sector17CodeNameEnglish"] - ] - df_33_sectors = self.get_33_sectors()[ - ["Sector33Code", "Sector33CodeNameEnglish"] - ] - df_segments = self.get_market_segments()[ - ["MarketCode", "MarketCodeNameEnglish"] - ] - df_list = pd.merge(df_list, df_17_sectors, how="left", on=["Sector17Code"]) - df_list = pd.merge(df_list, df_33_sectors, how="left", on=["Sector33Code"]) - df_list = pd.merge(df_list, df_segments, how="left", on=["MarketCode"]) - df_list.sort_values("Code", inplace=True) - return df_list - - def get_prices_daily_quotes( - self, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - ) -> pd.DataFrame: - """ - 株価情報を取得 - - Args: - code: 銘柄コード - from_yyyymmdd: 取得開始日 - to_yyyymmdd: 取得終了日 - date_yyyymmdd: 取得日 - - Returns: - pd.DataFrame: 株価情報 (Code, Date列でソートされています) - """ - return self._prices_daily_quotes_api.execute( - self, - code=code, - from_yyyymmdd=from_yyyymmdd, - to_yyyymmdd=to_yyyymmdd, - date_yyyymmdd=date_yyyymmdd, - ) - - def get_price_range( - self, - start_dt: DatetimeLike = "20170101", - end_dt: DatetimeLike = datetime.now(), - ) -> pd.DataFrame: - """ - 全銘柄の株価情報を日付範囲指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - - Returns: - pd.DataFrame: 株価情報 (Code, Date列でソートされています) - """ - # pre-load id_token - self.get_id_token() - buff = [] - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - futures = [ - executor.submit( - self.get_prices_daily_quotes, date_yyyymmdd=s.strftime("%Y-%m-%d") - ) - for s in dates - ] - for future in as_completed(futures): - df = future.result() - buff.append(df) - return pd.concat(buff).sort_values(["Code", "Date"]) - - def get_prices_prices_am( - self, - code: str = "", - ) -> pd.DataFrame: - """ - get the morning session's high, low, opening, and closing prices for individual stocks API returns - - Args: - code: issue code (e.g. 27800 or 2780) - If a 4-character issue code is specified, only the data of common stock will be obtained - for the issue on which both common and preferred stocks are listed. - Returns: pd.DataFrame: the morning session's OHLC data - """ - return self._prices_prices_am_api.execute(self, code=code) - - # /markets - def get_markets_trades_spec( - self, - section: Union[str, enums.MARKET_API_SECTIONS] = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - ) -> pd.DataFrame: - """ - Weekly Trading by Type of Investors - - Args: - section: section name (e.g. "TSEPrime" or MARKET_API_SECTIONS.TSEPrime) - from_yyyymmdd: starting point of data period (e.g. 20210901 or 2021-09-01) - to_yyyymmdd: end point of data period (e.g. 20210907 or 2021-09-07) - Returns: - pd.DataFrame: Weekly Trading by Type of Investors (Sorted by "PublishedDate" and "Section" columns) - """ - return self._markets_trades_spec_api.execute( - self, - section=section, - from_yyyymmdd=from_yyyymmdd, - to_yyyymmdd=to_yyyymmdd, - ) - - def get_markets_weekly_margin_interest( - self, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - ) -> pd.DataFrame: - """ - get weekly margin interest API returns - - Args: - code: issue code (e.g. 27800 or 2780) - If a 4-character issue code is specified, only the data of common stock will be obtained - for the issue on which both common and preferred stocks are listed. - from_yyyymmdd: starting point of data period (e.g. 20210901 or 2021-09-01) - to_yyyymmdd: end point of data period (e.g. 20210907 or 2021-09-07) - date_yyyymmdd: date of data (e.g. 20210907 or 2021-09-07) - Returns: - pd.DataFrame: weekly margin interest (Sorted by "Date" and "Code" columns) - """ - return self._markets_weekly_margin_interest_api.execute( - self, - code=code, - from_yyyymmdd=from_yyyymmdd, - to_yyyymmdd=to_yyyymmdd, - date_yyyymmdd=date_yyyymmdd, - ) - - def get_weekly_margin_range( - self, - start_dt: DatetimeLike = "20170101", - end_dt: DatetimeLike = datetime.now(), - ) -> pd.DataFrame: - """ - 信用取引週末残高を日付範囲を指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - - Returns: - pd.DataFrame: 信用取引週末残高(Code, Date列でソートされています) - """ - # pre-load id_token - self.get_id_token() - buff = [] - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - futures = [ - executor.submit( - self.get_markets_weekly_margin_interest, - date_yyyymmdd=s.strftime("%Y-%m-%d"), - ) - for s in dates - ] - for future in as_completed(futures): - df = future.result() - buff.append(df) - return pd.concat(buff).sort_values(["Code", "Date"]) - - def get_markets_short_selling( - self, - sector_33_code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - ) -> pd.DataFrame: - """ - get daily short sale ratios and trading value by industry (sector) API returns - - Args: - sector_33_code: 33-sector code (e.g. 0050 or 8050) - from_yyyymmdd: starting point of data period (e.g. 20210901 or 2021-09-01) - to_yyyymmdd: end point of data period (e.g. 20210907 or 2021-09-07) - date_yyyymmdd: date of data (e.g. 20210907 or 2021-09-07) - Returns: - pd.DataFrame: - daily short sale ratios and trading value by industry (Sorted by "Date" and "Sector33Code" columns) - """ - return self._markets_short_selling_api.execute( - self, - sector_33_code=sector_33_code, - from_yyyymmdd=from_yyyymmdd, - to_yyyymmdd=to_yyyymmdd, - date_yyyymmdd=date_yyyymmdd, - ) - - def get_short_selling_range( - self, - start_dt: DatetimeLike = "20170101", - end_dt: DatetimeLike = datetime.now(), - ) -> pd.DataFrame: - """ - 全33業種の空売り比率に関する売買代金を日付範囲指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - - Returns: - pd.DataFrame: 空売り比率に関する売買代金 (Sector33Code, Date列でソートされています) - """ - # pre-load id_token - self.get_id_token() - buff = [] - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - futures = [ - executor.submit( - self.get_markets_short_selling, date_yyyymmdd=s.strftime("%Y-%m-%d") - ) - for s in dates - ] - for future in as_completed(futures): - df = future.result() - buff.append(df) - return pd.concat(buff).sort_values(["Sector33Code", "Date"]) - - def get_markets_breakdown( - self, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - ) -> pd.DataFrame: - """ - get detail breakdown trading data API returns - - Args: - code: issue code (e.g. 27800 or 2780) - If a 4-character issue code is specified, only the data of common stock will be obtained - for the issue on which both common and preferred stocks are listed. - from_yyyymmdd: starting point of data period (e.g. 20210901 or 2021-09-01) - to_yyyymmdd: end point of data period (e.g. 20210907 or 2021-09-07) - date_yyyymmdd: date of data (e.g. 20210907 or 2021-09-07) - Returns: - pd.DataFrame: detail breakdown trading data (Sorted by "Code") - """ - return self._markets_breakdown_api.execute( - self, - code=code, - from_yyyymmdd=from_yyyymmdd, - to_yyyymmdd=to_yyyymmdd, - date_yyyymmdd=date_yyyymmdd, - ) - - def get_breakdown_range( - self, - start_dt: DatetimeLike = "20170101", - end_dt: DatetimeLike = datetime.now(), - ) -> pd.DataFrame: - """ - 売買内訳データを日付範囲指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - - Returns: - pd.DataFrame: 売買内訳データ(Code, Date列でソートされています) - """ - # pre-load id_token - self.get_id_token() - buff = [] - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - futures = [ - executor.submit( - self.get_markets_breakdown, date_yyyymmdd=s.strftime("%Y-%m-%d") - ) - for s in dates - ] - for future in as_completed(futures): - df = future.result() - buff.append(df) - return pd.concat(buff).sort_values(["Code", "Date"]) - - # /indices - - def get_indices( - self, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - ) -> pd.DataFrame: - """ - Indices Daily OHLC - - Args: - code: 指数コード - from_yyyymmdd: 取得開始日 - to_yyyymmdd: 取得終了日 - date_yyyymmdd: 取得日 - Returns: - pd.DataFrame: Indices Daily OHLC (Sorted by "Code", "Date" column) - """ - return self._indices_api.execute( - self, - code=code, - from_yyyymmdd=from_yyyymmdd, - to_yyyymmdd=to_yyyymmdd, - date_yyyymmdd=date_yyyymmdd, - ) - - def get_indices_topix( - self, - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - ) -> pd.DataFrame: - """ - TOPIX Daily OHLC - - Args: - from_yyyymmdd: starting point of data period (e.g. 20210901 or 2021-09-01) - to_yyyymmdd: end point of data period (e.g. 20210907 or 2021-09-07) - Returns: - pd.DataFrame: TOPIX Daily OHLC (Sorted by "Date" column) - """ - return self._indices_topix_api.execute( - self, - from_yyyymmdd=from_yyyymmdd, - to_yyyymmdd=to_yyyymmdd, - ) - - def get_fins_statements( - self, code: str = "", date_yyyymmdd: str = "" - ) -> pd.DataFrame: - """ - 財務情報取得 - - Args: - code: 銘柄コード - date_yyyymmdd: 日付(YYYYMMDD or YYYY-MM-DD) - - Returns: - pd.DataFrame: 財務情報 (DisclosedDate, DisclosedTime, 及びLocalCode列でソートされています) - """ - return self._fins_statements_api.execute( - self, - code=code, - date_yyyymmdd=date_yyyymmdd, - ) - - def get_statements_range( - self, - start_dt: DatetimeLike = "20080707", - end_dt: DatetimeLike = datetime.now(), - cache_dir: str = "", - ) -> pd.DataFrame: - """ - 財務情報を日付範囲指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - cache_dir: CSV形式のキャッシュファイルが存在するディレクトリ - - Returns: - pd.DataFrame: 財務情報 (DisclosedDate, DisclosedTime, 及びLocalCode列でソートされています) - """ - # pre-load id_token - self.get_id_token() - - buff = [] - futures = {} - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - for s in dates: - # fetch data via API or cache file - yyyymmdd = s.strftime("%Y%m%d") - yyyy = yyyymmdd[:4] - cache_file = f"fins_statements_{yyyymmdd}.csv.gz" - if (cache_dir != "") and os.path.isfile( - f"{cache_dir}/{yyyy}/{cache_file}" - ): - df = pd.read_csv(f"{cache_dir}/{yyyy}/{cache_file}", dtype=str) - df["DisclosedDate"] = pd.to_datetime( - df["DisclosedDate"], format="%Y-%m-%d" - ) - df["CurrentPeriodStartDate"] = pd.to_datetime( - df["CurrentPeriodStartDate"], format="%Y-%m-%d" - ) - df["CurrentPeriodEndDate"] = pd.to_datetime( - df["CurrentPeriodEndDate"], format="%Y-%m-%d" - ) - df["CurrentFiscalYearStartDate"] = pd.to_datetime( - df["CurrentFiscalYearStartDate"], format="%Y-%m-%d" - ) - df["CurrentFiscalYearEndDate"] = pd.to_datetime( - df["CurrentFiscalYearEndDate"], format="%Y-%m-%d" - ) - df["NextFiscalYearStartDate"] = pd.to_datetime( - df["NextFiscalYearStartDate"], format="%Y-%m-%d" - ) - df["NextFiscalYearEndDate"] = pd.to_datetime( - df["NextFiscalYearEndDate"], format="%Y-%m-%d" - ) - buff.append(df) - else: - future = executor.submit( - self.get_fins_statements, date_yyyymmdd=yyyymmdd - ) - futures[future] = yyyymmdd - for future in as_completed(futures): - df = future.result() - buff.append(df) - yyyymmdd = futures[future] - yyyy = yyyymmdd[:4] - cache_file = f"fins_statements_{yyyymmdd}.csv.gz" - if cache_dir != "": - # create year directory - os.makedirs(f"{cache_dir}/{yyyy}", exist_ok=True) - # write cache file - df.to_csv(f"{cache_dir}/{yyyy}/{cache_file}", index=False) - - return pd.concat(buff).sort_values( - ["DisclosedDate", "DisclosedTime", "LocalCode"] - ) - - def get_fins_fs_details( - self, code: str = "", date_yyyymmdd: str = "" - ) -> pd.DataFrame: - """ - 財務諸表(BS/PL)取得 - - Args: - code: 銘柄コード - date_yyyymmdd: 開示日(YYYYMMDD or YYYY-MM-DD) - - Returns: - pd.DataFrame: 財務諸表(BS/PL) (DisclosedDate, DisclosedTime, 及びLocalCode列でソートされています) - """ - return self._fins_fs_details_api.execute( - self, - code=code, - date_yyyymmdd=date_yyyymmdd, - ) - - def get_fs_details_range( - self, - start_dt: DatetimeLike = "20080707", - end_dt: DatetimeLike = datetime.now(), - cache_dir: str = "", - ) -> pd.DataFrame: - """ - 財務諸表(BS/PL)を日付範囲指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - cache_dir: CSV形式のキャッシュファイルが存在するディレクトリ - - Returns: - pd.DataFrame: 財務諸表(BS/PL) (DisclosedDate, DisclosedTime, 及びLocalCode列でソートされています) - """ - # pre-load id_token - self.get_id_token() - - buff = [] - futures = {} - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - for s in dates: - # fetch data via API or cache file - yyyymmdd = s.strftime("%Y%m%d") - yyyy = yyyymmdd[:4] - cache_file = f"fins_fs_details_{yyyymmdd}.csv.gz" - if (cache_dir != "") and os.path.isfile( - f"{cache_dir}/{yyyy}/{cache_file}" - ): - df = pd.read_csv(f"{cache_dir}/{yyyy}/{cache_file}", dtype=str) - df["DisclosedDate"] = pd.to_datetime( - df["DisclosedDate"], format="%Y-%m-%d" - ) - buff.append(df) - else: - future = executor.submit( - self.get_fins_fs_details, date_yyyymmdd=yyyymmdd - ) - futures[future] = yyyymmdd - for future in as_completed(futures): - df = future.result() - buff.append(df) - yyyymmdd = futures[future] - yyyy = yyyymmdd[:4] - cache_file = f"fins_fs_details_{yyyymmdd}.csv.gz" - if cache_dir != "": - # create year directory - os.makedirs(f"{cache_dir}/{yyyy}", exist_ok=True) - # write cache file - df.to_csv(f"{cache_dir}/{yyyy}/{cache_file}", index=False) - - return pd.concat(buff).sort_values( - ["DisclosedDate", "DisclosedTime", "LocalCode"] - ) - - def get_fins_dividend( - self, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - ) -> pd.DataFrame: - """ - get information on dividends (determined and forecast) per share of listed companies etc.. API returns - - Args: - code: issue code (e.g. 27800 or 2780) - If a 4-character issue code is specified, only the data of common stock will be obtained - for the issue on which both common and preferred stocks are listed. - from_yyyymmdd: starting point of data period (e.g. 20210901 or 2021-09-01) - to_yyyymmdd: end point of data period (e.g. 20210907 or 2021-09-07) - date_yyyymmdd: date of data (e.g. 20210907 or 2021-09-07) - Returns: - pd.DataFrame: information on dividends data (Sorted by "Code") - """ - return self._fins_dividend_api.execute( - self, - code=code, - from_yyyymmdd=from_yyyymmdd, - to_yyyymmdd=to_yyyymmdd, - date_yyyymmdd=date_yyyymmdd, - ) - - def get_dividend_range( - self, - start_dt: DatetimeLike = "20170101", - end_dt: DatetimeLike = datetime.now(), - ) -> pd.DataFrame: - """ - 配当金データを日付範囲指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - - Returns: - pd.DataFrame: 配当金データ(Code, AnnouncementDate, AnnouncementTime列でソートされています) - """ - # pre-load id_token - self.get_id_token() - buff = [] - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - futures = [ - executor.submit( - self.get_fins_dividend, date_yyyymmdd=s.strftime("%Y-%m-%d") - ) - for s in dates - ] - for future in as_completed(futures): - df = future.result() - buff.append(df) - return pd.concat(buff).sort_values( - ["AnnouncementDate", "AnnouncementTime", "Code"] - ) - - def get_fins_announcement(self) -> pd.DataFrame: - """ - get fin announcement - - Args: - N/A - - Returns: - pd.DataFrame: Schedule of financial announcement - """ - return self._fins_announcement_api.execute(self) - - def get_option_index_option( - self, - date_yyyymmdd, - ) -> pd.DataFrame: - """ - get information on the OHLC etc. of Nikkei 225 API returns - - Args: - date_yyyymmdd: date of data (e.g. 20210907 or 2021-09-07) - Returns: - pd.DataFrame: - Nikkei 225 Options' OHLC etc. (Sorted by "Code") - """ - return self._option_index_option_api.execute( - self, - date_yyyymmdd=date_yyyymmdd, - ) - - def get_index_option_range( - self, - start_dt: DatetimeLike = "20170101", - end_dt: DatetimeLike = datetime.now(), - ) -> pd.DataFrame: - """ - 指数オプション(Nikkei225)に関するOHLC等の情報を日付範囲指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - - Returns: - pd.DataFrame: 指数オプション(Nikkei225)に関するOHLC等 (Code, Date列でソートされています) - """ - # pre-load id_token - self.get_id_token() - buff = [] - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - futures = [ - executor.submit( - self.get_option_index_option, date_yyyymmdd=s.strftime("%Y-%m-%d") - ) - for s in dates - ] - for future in as_completed(futures): - df = future.result() - buff.append(df) - return pd.concat(buff).sort_values(["Code", "Date"]) - - def get_markets_trading_calendar( - self, - holiday_division: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - ) -> pd.DataFrame: - """ - 取引カレンダーを取得 - - Args: - holiday_division: 休日区分 - from_yyyymmdd: 取得開始日 - to_yyyymmdd: 取得終了日 - - Returns: - pd.DataFrame: 取り引きカレンダー (Date列でソートされています) - """ - return self._markets_trading_calendar_api.execute( - self, - holiday_division=holiday_division, - from_yyyymmdd=from_yyyymmdd, - to_yyyymmdd=to_yyyymmdd, - ) - - def get_derivatives_futures( - self, - date_yyyymmdd: str, - category: str = "", - contract_flag: str = "", - ) -> pd.DataFrame: - """ - get information on the OHLC etc. of Futures API returns - - Args: - date_yyyymmdd: date of data (e.g. 20210907 or 2021-09-07) - Returns: - pd.DataFrame: - Futures' OHLC etc. (Sorted by "Code") - """ - return self._derivatives_futures_api.execute( - self, - date_yyyymmdd=date_yyyymmdd, - category=category, - contract_flag=contract_flag, - ) - - def get_derivatives_futures_range( - self, - start_dt: DatetimeLike = "20170101", - end_dt: DatetimeLike = datetime.now(), - category: str = "", - contract_flag: str = "", - ) -> pd.DataFrame: - """ - 先物に関するOHLC等の情報を日付範囲指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - - Returns: - pd.DataFrame: 先物に関するOHLC等 (Code, Date列でソートされています) - """ - # pre-load id_token - self.get_id_token() - buff = [] - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - futures = [ - executor.submit( - self.get_derivatives_futures, - date_yyyymmdd=s.strftime("%Y-%m-%d"), - category=category, - contract_flag=contract_flag, - ) - for s in dates - ] - for future in as_completed(futures): - df = future.result() - buff.append(df) - return pd.concat(buff).sort_values(["Code", "Date"]) - - def get_derivatives_options( - self, - date_yyyymmdd: str, - category: str = "", - contract_flag: str = "", - code: str = "", - ) -> pd.DataFrame: - """ - get information on the OHLC etc. of Option API returns - - Args: - date_yyyymmdd: date of data (e.g. 20210907 or 2021-09-07) - Returns: - pd.DataFrame: - Futures' OHLC etc. (Sorted by "Code") - """ - return self._derivatives_options_api.execute( - self, - date_yyyymmdd=date_yyyymmdd, - category=category, - contract_flag=contract_flag, - code=code, - ) - - def get_derivatives_options_range( - self, - start_dt: DatetimeLike = "20170101", - end_dt: DatetimeLike = datetime.now(), - category: str = "", - contract_flag: str = "", - code: str = "", - ) -> pd.DataFrame: - """ - オプションに関するOHLC等の情報を日付範囲指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - - Returns: - pd.DataFrame: オプションに関するOHLC等 (Code, Date列でソートされています) - """ - # pre-load id_token - self.get_id_token() - buff = [] - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - options = [ - executor.submit( - self.get_derivatives_options, - date_yyyymmdd=s.strftime("%Y-%m-%d"), - category=category, - contract_flag=contract_flag, - code=code, - ) - for s in dates - ] - for option in as_completed(options): - df = option.result() - buff.append(df) - return pd.concat(buff).sort_values(["Code", "Date"]) - - def get_markets_short_selling_positions( - self, - code: str = "", - disclosed_date: str = "", - disclosed_date_from: str = "", - disclosed_date_to: str = "", - calculated_date: str = "", - ) -> pd.DataFrame: - """ - get short selling positions API returns - - Args: - code: issue code (e.g. 27800 or 2780) - If a 4-character issue code is specified, only the data of common stock - will be obtained for the issue on which both common and preferred stocks - are listed. - disclosed_date: disclosed date (e.g. 20240301 or 2024-03-01) - disclosed_date_from: disclosed date from (e.g. 20240301 or 2024-03-01) - disclosed_date_to: disclosed date to (e.g. 20240301 or 2024-03-01) - calculated_date: calculated date (e.g. 20240301 or 2024-03-01) - Returns: - pd.DataFrame: short selling positions (Sorted by "DisclosedDate", - "CalculatedDate", and "Code" columns) - """ - return self._markets_short_selling_positions_api.execute( - self, - code=code, - disclosed_date=disclosed_date, - disclosed_date_from=disclosed_date_from, - disclosed_date_to=disclosed_date_to, - calculated_date=calculated_date, - ) - - def get_markets_short_selling_positions_range( - self, - start_dt: DatetimeLike = "20131107", - end_dt: DatetimeLike = datetime.now(), - ) -> pd.DataFrame: - """ - 空売り残高報告データを日付範囲指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - - Returns: - pd.DataFrame: 空売り残高報告データ (DisclosedDate, CalculatedDate, - Code列でソートされています) - """ - # pre-load id_token - self.get_id_token() - buff = [] - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - futures = [ - executor.submit( - self.get_markets_short_selling_positions, - disclosed_date=s.strftime("%Y-%m-%d"), - ) - for s in dates - ] - for future in as_completed(futures): - df = future.result() - buff.append(df) - return pd.concat(buff).sort_values(["DisclosedDate", "CalculatedDate", "Code"]) - - def get_markets_daily_margin_interest( - self, - code: str = "", - from_yyyymmdd: str = "", - to_yyyymmdd: str = "", - date_yyyymmdd: str = "", - ) -> pd.DataFrame: - """ - get daily margin interest API returns - - Args: - code: issue code (e.g. 27800 or 2780) - If a 4-character issue code is specified, only the data of common stock - will be obtained for the issue on which both common and preferred stocks - are listed. - from_yyyymmdd: starting point of data period (e.g. 20210901 or 2021-09-01) - to_yyyymmdd: end point of data period (e.g. 20210907 or 2021-09-07) - date_yyyymmdd: date of data (e.g. 20210907 or 2021-09-07) - Returns: - pd.DataFrame: daily margin interest (Sorted by "Code" and "PublishedDate" columns) - """ - return self._markets_daily_margin_interest_api.execute( - self, - code=code, - from_yyyymmdd=from_yyyymmdd, - to_yyyymmdd=to_yyyymmdd, - date_yyyymmdd=date_yyyymmdd, - ) - - def get_daily_margin_interest_range( - self, - start_dt: DatetimeLike = "20080508", - end_dt: DatetimeLike = datetime.now(), - ) -> pd.DataFrame: - """ - 全銘柄の日々公表信用取引残高を日付範囲指定して取得 - - Args: - start_dt: 取得開始日 - end_dt: 取得終了日 - - Returns: - pd.DataFrame: 日々公表信用取引残高 (Code, PublishedDate列でソートされています) - """ - # pre-load id_token - self.get_id_token() - buff = [] - dates = pd.date_range(start_dt, end_dt, freq="D") - with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor: - futures = [ - executor.submit( - self.get_markets_daily_margin_interest, - date_yyyymmdd=s.strftime("%Y-%m-%d"), - ) - for s in dates - ] - for future in as_completed(futures): - df = future.result() - buff.append(df) - return pd.concat(buff).sort_values(["Code", "PublishedDate"]) diff --git a/jquantsapi/constants.py b/jquantsapi/constants.py index f85e89f..ff1806f 100644 --- a/jquantsapi/constants.py +++ b/jquantsapi/constants.py @@ -1,5 +1,5 @@ # ============================================================================ -# 共通データ(V1/V2両方で使用) +# 共通データ # ============================================================================ # ref. ja https://jpx-jquants.com/ja/spec/eq-master/sector17code @@ -82,601 +82,7 @@ # ============================================================================ -# V1 API用カラム定義 -# ============================================================================ - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/listed_info/sector17code -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/listed_info/sector17code -SECTOR_17_COLUMNS = ["Sector17Code", "Sector17CodeName", "Sector17CodeNameEnglish"] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/listed_info/sector33code -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/listed_info/sector33code -SECTOR_33_COLUMNS = [ - "Sector33Code", - "Sector33CodeName", - "Sector33CodeNameEnglish", - "Sector17Code", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/listed_info/marketcode -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/listed_info/marketcode -MARKET_SEGMENT_COLUMNS = [ - "MarketCode", - "MarketCodeName", - "MarketCodeNameEnglish", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/listed_info -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/listed_info -LISTED_INFO_COLUMNS = [ - "Date", - "Code", - "CompanyName", - "CompanyNameEnglish", - "Sector17Code", - "Sector17CodeName", - "Sector33Code", - "Sector33CodeName", - "ScaleCategory", - "MarketCode", - "MarketCodeName", -] -LISTED_INFO_STANDARD_PREMIUM_COLUMNS = [ - "Date", - "Code", - "CompanyName", - "CompanyNameEnglish", - "Sector17Code", - "Sector17CodeName", - "Sector33Code", - "Sector33CodeName", - "ScaleCategory", - "MarketCode", - "MarketCodeName", - "MarginCode", - "MarginCodeName", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/daily_quotes -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/daily_quotes -PRICES_DAILY_QUOTES_COLUMNS = [ - "Date", - "Code", - "Open", - "High", - "Low", - "Close", - "UpperLimit", - "LowerLimit", - "Volume", - "TurnoverValue", - "AdjustmentFactor", - "AdjustmentOpen", - "AdjustmentHigh", - "AdjustmentLow", - "AdjustmentClose", - "AdjustmentVolume", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/daily_quotes -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/daily_quotes -PRICES_DAILY_QUOTES_PREMIUM_COLUMNS = [ - "Date", - "Code", - "Open", - "High", - "Low", - "Close", - "UpperLimit", - "LowerLimit", - "Volume", - "TurnoverValue", - "AdjustmentFactor", - "AdjustmentOpen", - "AdjustmentHigh", - "AdjustmentLow", - "AdjustmentClose", - "AdjustmentVolume", - "MorningOpen", - "MorningHigh", - "MorningLow", - "MorningClose", - "MorningUpperLimit", - "MorningLowerLimit", - "MorningVolume", - "MorningTurnoverValue", - "MorningAdjustmentOpen", - "MorningAdjustmentHigh", - "MorningAdjustmentLow", - "MorningAdjustmentClose", - "MorningAdjustmentVolume", - "AfternoonOpen", - "AfternoonHigh", - "AfternoonLow", - "AfternoonClose", - "AfternoonUpperLimit", - "AfternoonLowerLimit", - "AfternoonVolume", - "AfternoonTurnoverValue", - "AfternoonAdjustmentOpen", - "AfternoonAdjustmentHigh", - "AfternoonAdjustmentLow", - "AfternoonAdjustmentClose", - "AfternoonAdjustmentVolume", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/prices_am -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/prices_am -PRICES_PRICES_AM_COLUMNS = [ - "Date", - "Code", - "MorningOpen", - "MorningHigh", - "MorningLow", - "MorningClose", - "MorningVolume", - "MorningTurnoverValue", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/indices -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/indices -INDICES_COLUMNS = [ - "Date", - "Code", - "Open", - "High", - "Low", - "Close", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/topix -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/topix -INDICES_TOPIX_COLUMNS = [ - "Date", - "Open", - "High", - "Low", - "Close", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/trades_spec -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/trades_spec -MARKETS_TRADES_SPEC = [ - "Section", - "PublishedDate", - "StartDate", - "EndDate", - "ProprietarySales", - "ProprietaryPurchases", - "ProprietaryTotal", - "ProprietaryBalance", - "BrokerageSales", - "BrokeragePurchases", - "BrokerageTotal", - "BrokerageBalance", - "TotalSales", - "TotalPurchases", - "TotalTotal", - "TotalBalance", - "IndividualsSales", - "IndividualsPurchases", - "IndividualsTotal", - "IndividualsBalance", - "ForeignersSales", - "ForeignersPurchases", - "ForeignersTotal", - "ForeignersBalance", - "SecuritiesCosSales", - "SecuritiesCosPurchases", - "SecuritiesCosTotal", - "SecuritiesCosBalance", - "InvestmentTrustsSales", - "InvestmentTrustsPurchases", - "InvestmentTrustsTotal", - "InvestmentTrustsBalance", - "BusinessCosSales", - "BusinessCosPurchases", - "BusinessCosTotal", - "BusinessCosBalance", - "OtherCosSales", - "OtherCosPurchases", - "OtherCosTotal", - "OtherCosBalance", - "InsuranceCosSales", - "InsuranceCosPurchases", - "InsuranceCosTotal", - "InsuranceCosBalance", - "CityBKsRegionalBKsEtcSales", - "CityBKsRegionalBKsEtcPurchases", - "CityBKsRegionalBKsEtcTotal", - "CityBKsRegionalBKsEtcBalance", - "TrustBanksSales", - "TrustBanksPurchases", - "TrustBanksTotal", - "TrustBanksBalance", - "OtherFinancialInstitutionsSales", - "OtherFinancialInstitutionsPurchases", - "OtherFinancialInstitutionsTotal", - "OtherFinancialInstitutionsBalance", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/weekly_margin_interest -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/weekly_margin_interest -MARKETS_WEEKLY_MARGIN_INTEREST = [ - "Date", - "Code", - "ShortMarginTradeVolume", - "LongMarginTradeVolume", - "ShortNegotiableMarginTradeVolume", - "LongNegotiableMarginTradeVolume", - "ShortStandardizedMarginTradeVolume", - "LongStandardizedMarginTradeVolume", - "IssueType", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/short_selling -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/short_selling -MARKET_SHORT_SELLING_COLUMNS = [ - "Date", - "Sector33Code", - "SellingExcludingShortSellingTurnoverValue", - "ShortSellingWithRestrictionsTurnoverValue", - "ShortSellingWithoutRestrictionsTurnoverValue", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/breakdown -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/breakdown -MARKETS_BREAKDOWN_COLUMNS = [ - "Date", - "Code", - "LongSellValue", - "ShortSellWithoutMarginValue", - "MarginSellNewValue", - "MarginSellCloseValue", - "LongBuyValue", - "MarginBuyNewValue", - "MarginBuyCloseValue", - "LongSellVolume", - "ShortSellWithoutMarginVolume", - "MarginSellNewVolume", - "MarginSellCloseVolume", - "LongBuyVolume", - "MarginBuyNewVolume", - "MarginBuyCloseVolume", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/trading_calendar -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/trading_calendar -MARKETS_TRADING_CALENDAR = [ - "Date", - "HolidayDivision", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/statements -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/statements -FINS_STATEMENTS_COLUMNS = [ - "DisclosedDate", - "DisclosedTime", - "LocalCode", - "DisclosureNumber", - "TypeOfDocument", - "TypeOfCurrentPeriod", - "CurrentPeriodStartDate", - "CurrentPeriodEndDate", - "CurrentFiscalYearStartDate", - "CurrentFiscalYearEndDate", - "NextFiscalYearStartDate", - "NextFiscalYearEndDate", - "NetSales", - "OperatingProfit", - "OrdinaryProfit", - "Profit", - "EarningsPerShare", - "DilutedEarningsPerShare", - "TotalAssets", - "Equity", - "EquityToAssetRatio", - "BookValuePerShare", - "CashFlowsFromOperatingActivities", - "CashFlowsFromInvestingActivities", - "CashFlowsFromFinancingActivities", - "CashAndEquivalents", - "ResultDividendPerShare1stQuarter", - "ResultDividendPerShare2ndQuarter", - "ResultDividendPerShare3rdQuarter", - "ResultDividendPerShareFiscalYearEnd", - "ResultDividendPerShareAnnual", - "DistributionsPerUnit(REIT)", - "ResultTotalDividendPaidAnnual", - "ResultPayoutRatioAnnual", - "ForecastDividendPerShare1stQuarter", - "ForecastDividendPerShare2ndQuarter", - "ForecastDividendPerShare3rdQuarter", - "ForecastDividendPerShareFiscalYearEnd", - "ForecastDividendPerShareAnnual", - "ForecastDistributionsPerUnit(REIT)", - "ForecastTotalDividendPaidAnnual", - "ForecastPayoutRatioAnnual", - "NextYearForecastDividendPerShare1stQuarter", - "NextYearForecastDividendPerShare2ndQuarter", - "NextYearForecastDividendPerShare3rdQuarter", - "NextYearForecastDividendPerShareFiscalYearEnd", - "NextYearForecastDividendPerShareAnnual", - "NextYearForecastDistributionsPerUnit(REIT)", - "NextYearForecastPayoutRatioAnnual", - "ForecastNetSales2ndQuarter", - "ForecastOperatingProfit2ndQuarter", - "ForecastOrdinaryProfit2ndQuarter", - "ForecastProfit2ndQuarter", - "ForecastEarningsPerShare2ndQuarter", - "NextYearForecastNetSales2ndQuarter", - "NextYearForecastOperatingProfit2ndQuarter", - "NextYearForecastOrdinaryProfit2ndQuarter", - "NextYearForecastProfit2ndQuarter", - "NextYearForecastEarningsPerShare2ndQuarter", - "ForecastNetSales", - "ForecastOperatingProfit", - "ForecastOrdinaryProfit", - "ForecastProfit", - "ForecastEarningsPerShare", - "NextYearForecastNetSales", - "NextYearForecastOperatingProfit", - "NextYearForecastOrdinaryProfit", - "NextYearForecastProfit", - "NextYearForecastEarningsPerShare", - "MaterialChangesInSubsidiaries", - "SignificantChangesInTheScopeOfConsolidation", - "ChangesBasedOnRevisionsOfAccountingStandard", - "ChangesOtherThanOnesBasedOnRevisionsOfAccountingStandard", - "ChangesInAccountingEstimates", - "RetrospectiveRestatement", - "NumberOfIssuedAndOutstandingSharesAtTheEndOfFiscalYearIncludingTreasuryStock", - "NumberOfTreasuryStockAtTheEndOfFiscalYear", - "AverageNumberOfShares", - "NonConsolidatedNetSales", - "NonConsolidatedOperatingProfit", - "NonConsolidatedOrdinaryProfit", - "NonConsolidatedProfit", - "NonConsolidatedEarningsPerShare", - "NonConsolidatedTotalAssets", - "NonConsolidatedEquity", - "NonConsolidatedEquityToAssetRatio", - "NonConsolidatedBookValuePerShare", - "ForecastNonConsolidatedNetSales2ndQuarter", - "ForecastNonConsolidatedOperatingProfit2ndQuarter", - "ForecastNonConsolidatedOrdinaryProfit2ndQuarter", - "ForecastNonConsolidatedProfit2ndQuarter", - "ForecastNonConsolidatedEarningsPerShare2ndQuarter", - "NextYearForecastNonConsolidatedNetSales2ndQuarter", - "NextYearForecastNonConsolidatedOperatingProfit2ndQuarter", - "NextYearForecastNonConsolidatedOrdinaryProfit2ndQuarter", - "NextYearForecastNonConsolidatedProfit2ndQuarter", - "NextYearForecastNonConsolidatedEarningsPerShare2ndQuarter", - "ForecastNonConsolidatedNetSales", - "ForecastNonConsolidatedOperatingProfit", - "ForecastNonConsolidatedOrdinaryProfit", - "ForecastNonConsolidatedProfit", - "ForecastNonConsolidatedEarningsPerShare", - "NextYearForecastNonConsolidatedNetSales", - "NextYearForecastNonConsolidatedOperatingProfit", - "NextYearForecastNonConsolidatedOrdinaryProfit", - "NextYearForecastNonConsolidatedProfit", - "NextYearForecastNonConsolidatedEarningsPerShare", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/statements-1 -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/statements-1 -FINS_FS_DETAILS_COLUMNS = [ - "DisclosedDate", - "DisclosedTime", - "LocalCode", - "DisclosureNumber", - "TypeOfDocument", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/dividend -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/dividend -FINS_DIVIDEND_COLUMNS = [ - "AnnouncementDate", - "AnnouncementTime", - "Code", - "ReferenceNumber", - "StatusCode", - "BoardMeetingDate", - "InterimFinalCode", - "ForecastResultCode", - "InterimFinalTerm", - "GrossDividendRate", - "RecordDate", - "ExDate", - "ActualRecordDate", - "PayableDate", - "CAReferenceNumber", - "DistributionAmount", - "RetainedEarnings", - "DeemedDividend", - "DeemedCapitalGains", - "NetAssetDecreaseRatio", - "CommemorativeSpecialCode", - "CommemorativeDividendRate", - "SpecialDividendRate", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/announcement -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/announcement -FINS_ANNOUNCEMENT_COLUMNS = [ - "Code", - "Date", - "CompanyName", - "FiscalYear", - "SectorName", - "FiscalQuarter", - "Section", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/index_option -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/index_option -OPTION_INDEX_OPTION_COLUMNS = [ - "Date", - "Code", - "WholeDayOpen", - "WholeDayHigh", - "WholeDayLow", - "WholeDayClose", - "NightSessionOpen", - "NightSessionHigh", - "NightSessionLow", - "NightSessionClose", - "DaySessionOpen", - "DaySessionHigh", - "DaySessionLow", - "DaySessionClose", - "Volume", - "OpenInterest", - "TurnoverValue", - "ContractMonth", - "StrikePrice", - "Volume(OnlyAuction)", - "EmergencyMarginTriggerDivision", - "PutCallDivision", - "LastTradingDay", - "SpecialQuotationDay", - "SettlementPrice", - "TheoreticalPrice", - "BaseVolatility", - "UnderlyingPrice", - "ImpliedVolatility", - "InterestRate", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/futures -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/futures -DERIVATIVES_FUTURES_COLUMNS = [ - "Date", - "Code", - "DerivativesProductCategory", - "WholeDayOpen", - "WholeDayHigh", - "WholeDayLow", - "WholeDayClose", - "MorningSessionOpen", - "MorningSessionHigh", - "MorningSessionLow", - "MorningSessionClose", - "NightSessionOpen", - "NightSessionHigh", - "NightSessionLow", - "NightSessionClose", - "DaySessionOpen", - "DaySessionHigh", - "DaySessionLow", - "DaySessionClose", - "Volume", - "OpenInterest", - "TurnoverValue", - "ContractMonth", - "Volume(OnlyAuction)", - "EmergencyMarginTriggerDivision", - "LastTradingDay", - "SpecialQuotationDay", - "SettlementPrice", - "CentralContractMonthFlag", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/options -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/options -DERIVATIVES_OPTIONS_COLUMNS = [ - "Date", - "Code", - "DerivativesProductCategory", - "UnderlyingSSO", - "WholeDayOpen", - "WholeDayHigh", - "WholeDayLow", - "WholeDayClose", - "MorningSessionOpen", - "MorningSessionHigh", - "MorningSessionLow", - "MorningSessionClose", - "NightSessionOpen", - "NightSessionHigh", - "NightSessionLow", - "NightSessionClose", - "DaySessionOpen", - "DaySessionHigh", - "DaySessionLow", - "DaySessionClose", - "Volume", - "OpenInterest", - "TurnoverValue", - "ContractMonth", - "StrikePrice", - "Volume(OnlyAuction)", - "EmergencyMarginTriggerDivision", - "PutCallDivision", - "LastTradingDay", - "SpecialQuotationDay", - "SettlementPrice", - "TheoreticalPrice", - "BaseVolatility", - "UnderlyingPrice", - "ImpliedVolatility", - "InterestRate", - "CentralContractMonthFlag", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/short_selling_positions -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/short_selling_positions -SHORT_SELLING_POSITIONS_COLUMNS = [ - "DisclosedDate", - "CalculatedDate", - "Code", - "ShortSellerName", - "ShortSellerAddress", - "DiscretionaryInvestmentContractorName", - "DiscretionaryInvestmentContractorAddress", - "InvestmentFundName", - "ShortPositionsToSharesOutstandingRatio", - "ShortPositionsInSharesNumber", - "ShortPositionsInTradingUnitsNumber", - "CalculationInPreviousReportingDate", - "ShortPositionsInPreviousReportingRatio", - "Notes", -] - -# ref. ja https://jpx.gitbook.io/j-quants-ja/api-reference/daily_margin_interest -# ref. en https://jpx.gitbook.io/j-quants-en/api-reference/daily_margin_interest -DAILY_MARGIN_INTEREST_COLUMNS = [ - "PublishedDate", - "Code", - "ApplicationDate", - "PublishReason.Restricted", - "PublishReason.DailyPublication", - "PublishReason.Monitoring", - "PublishReason.RestrictedByJSF", - "PublishReason.PrecautionByJSF", - "PublishReason.UnclearOrSecOnAlert", - "ShortMarginOutstanding", - "DailyChangeShortMarginOutstanding", - "ShortMarginOutstandingListedShareRatio", - "LongMarginOutstanding", - "DailyChangeLongMarginOutstanding", - "LongMarginOutstandingListedShareRatio", - "ShortLongRatio", - "ShortNegotiableMarginOutstanding", - "DailyChangeShortNegotiableMarginOutstanding", - "ShortStandardizedMarginOutstanding", - "DailyChangeShortStandardizedMarginOutstanding", - "LongNegotiableMarginOutstanding", - "DailyChangeLongNegotiableMarginOutstanding", - "LongStandardizedMarginOutstanding", - "DailyChangeLongStandardizedMarginOutstanding", - "TSEMarginBorrowingAndLendingRegulationClassification", -] - - -# ============================================================================ -# V2 API用カラム定義 +# API用カラム定義 # ============================================================================ # ref. ja https://jpx-jquants.com/ja/spec/eq-master/sector17code diff --git a/tests/test_client.py b/tests/test_client.py deleted file mode 100644 index 8ad821f..0000000 --- a/tests/test_client.py +++ /dev/null @@ -1,323 +0,0 @@ -from contextlib import nullcontext as does_not_raise -from datetime import datetime -from unittest.mock import MagicMock, patch - -import pandas as pd -import pytest -from dateutil import tz - -import jquantsapi - - -@pytest.mark.parametrize( - "mail_address, password, refresh_token," - "env, isfile, load," - "exp_mail_address, exp_password, exp_refresh_token, exp_refresh_token_expire," - "exp_raise", - ( - ( - None, - None, - None, - {}, - [True, False, True, False], - [{"dummy": {"mail_address": "mail_address"}}, {}], - "", - "", - "", - 0, - pytest.raises(ValueError), - ), - ( - None, - None, - None, - {"JQUANTS_API_CLIENT_CONFIG_FILE": ""}, - [True, True, True, True], - [ - { - "jquants-api-client": { - "mail_address": "mail_address@", - "password": "password", - } - }, - {}, - {}, - { - "jquants-api-client": { - "mail_address": "mail_address_overwrite@", - "refresh_token": "refresh_token", - } - }, - ], - "mail_address_overwrite@", - "password", - "refresh_token", - 6, - does_not_raise(), - ), - ( - None, - None, - None, - { - "JQUANTS_API_MAIL_ADDRESS": "mail_address_env@", - "JQUANTS_API_PASSWORD": "password_env", - "JQUANTS_API_REFRESH_TOKEN": "refresh_token_env", - }, - [True, False, False, False], - [ - { - "jquants-api-client": { - "mail_address": "mail_address@", - "password": "password", - "refresh_token": "refresh_token", - } - }, - ], - "mail_address_env@", - "password_env", - "refresh_token_env", - 6, - does_not_raise(), - ), - ( - "mail@", - "password", - None, - {}, - [False, False, False, False], - [], - "mail@", - "password", - "", - 0, - does_not_raise(), - ), - ( - "mail@", - None, - None, - {}, - [False, False, False, False], - [], - "mail@", - "", - "", - 0, - pytest.raises(ValueError), - ), - ( - "mail", - "password", - None, - {}, - [False, False, False, False], - [], - "mail", - "password", - "", - 0, - pytest.raises(ValueError), - ), - ( - None, - None, - "token", - {}, - [False, False, False, False], - [], - "", - "", - "token", - 6, - does_not_raise(), - ), - ( - "mail_address_param@", - "password_param", - "refresh_token_param", - {}, - [True, False, False, False], - [ - { - "jquants-api-client": { - "mail_address": "mail_address@", - "password": "password", - "refresh_token": "refresh_token", - } - }, - ], - "mail_address_param@", - "password_param", - "refresh_token_param", - 6, - does_not_raise(), - ), - ), -) -def test_client( - mail_address, - password, - refresh_token, - env, - isfile, - load, - exp_mail_address, - exp_password, - exp_refresh_token, - exp_refresh_token_expire, - exp_raise, -): - utcnow = pd.Timestamp("2022-09-08T22:00:00Z") - with exp_raise, patch.object( - jquantsapi.Client, "_is_colab", return_value=True - ), patch.object(jquantsapi.client.os.path, "isfile", side_effect=isfile), patch( - "builtins.open" - ), patch.dict( - jquantsapi.client.os.environ, env, clear=True - ), patch.object( - jquantsapi.client.tomllib, "load", side_effect=load - ), patch.object( - jquantsapi.client.pd.Timestamp, "utcnow", return_value=utcnow - ): - cli = jquantsapi.Client( - refresh_token=refresh_token, mail_address=mail_address, password=password - ) - assert cli._mail_address == exp_mail_address - assert cli._password == exp_password - assert cli._refresh_token == exp_refresh_token - assert cli._refresh_token_expire == utcnow + pd.Timedelta( - exp_refresh_token_expire, unit="D" - ) - - -@pytest.mark.parametrize( - "init_mail_address, init_password, param_mail_address, param_password, exp_raise", - ( - # use private variable via constructor - ("m@", "p", None, None, does_not_raise()), - ("", "", None, None, pytest.raises(ValueError)), - ("m", "p", None, None, pytest.raises(ValueError)), - # use parameter - (None, None, "m@", "p", does_not_raise()), - (None, None, "", "", pytest.raises(ValueError)), - (None, None, "m", "p", pytest.raises(ValueError)), - # overwrite - ("m@", "p", "", "", pytest.raises(ValueError)), - ("m@", "p", "m", "p", pytest.raises(ValueError)), - ), -) -def test_get_refresh_token( - init_mail_address, init_password, param_mail_address, param_password, exp_raise -): - config = { - "mail_address": "", - "password": "", - "refresh_token": "dummy_token", - } - - with exp_raise, patch.object( - jquantsapi.Client, "_load_config", return_value=config - ), patch.object(jquantsapi.Client, "_post") as mock_post: - mock_post.return_value.json.return_value = {"refreshToken": "ret_token"} - - cli = jquantsapi.Client( - refresh_token="dummy_token", - mail_address=init_mail_address, - password=init_password, - ) - # overwrite expire time - cli._refresh_token_expire = pd.Timestamp.utcnow() - ret = cli.get_refresh_token(param_mail_address, param_password) - assert ret == "ret_token" - - -@pytest.mark.parametrize( - "section, from_yyyymmdd, to_yyyymmdd, exp_params", - ( - ("", "", "", {}), - ("TSEPrime", "", "", {"section": "TSEPrime"}), - ( - jquantsapi.MARKET_API_SECTIONS.TSE1st, - "", - "", - {"section": "TSE1st"}, - ), - ("", "20220101", "", {"from": "20220101"}), - ("", "", "20220101", {"to": "20220101"}), - ( - "TSEPrime", - "20220101", - "20220102", - {"section": "TSEPrime", "from": "20220101", "to": "20220102"}, - ), - ), -) -def test_get_markets_trades_spec(section, from_yyyymmdd, to_yyyymmdd, exp_params): - config = { - "mail_address": "", - "password": "", - "refresh_token": "dummy_token", - } - - ret_value = '{"trades_spec": []}' - exp_ret_len = 0 - exp_raise = does_not_raise() - - with exp_raise, patch.object( - jquantsapi.Client, "_load_config", return_value=config - ), patch.object(jquantsapi.Client, "_get") as mock_get: - mock_get.return_value.text = ret_value - - cli = jquantsapi.Client() - ret = cli.get_markets_trades_spec( - section=section, from_yyyymmdd=from_yyyymmdd, to_yyyymmdd=to_yyyymmdd - ) - args, _ = mock_get.call_args - assert args[1] == exp_params - assert len(ret) == exp_ret_len - - -def test_get_price_range(): - """ - get_price_range()を呼ぶ際、引数に様々な型が入っていても問題なく - get_prices_daily_quotes()に単一の年月日が渡される事を確認する。 - """ - # テストではHTTP通信を行わず、 - # get_id_token()およびget_prices_daily_quotes()をモックすることで、 - # 実際に通信が発生しないようにする。 - mock = MagicMock(return_value=pd.DataFrame(columns=["Code", "Date"])) - cli = jquantsapi.Client(refresh_token="dummy") - cli.get_id_token = MagicMock() - cli.get_prices_daily_quotes = mock # get_prices_daily_quotes() をモックに置き換える - formats = { - # テストする期間はいつでも良いので、何かが起こりやすい閏日をテスト対象に含む - "str_8digits": ("20200227", "20200302"), - "str_split_by_hyphen": ("2020-02-27", "2020-03-02"), - "datetime_without_tz": (datetime(2020, 2, 27), datetime(2020, 3, 2)), - "datetime_with_tz": ( - datetime(2020, 2, 27, tzinfo=tz.gettz("Asia/Tokyo")), - datetime(2020, 3, 2, tzinfo=tz.gettz("Asia/Tokyo")), - ), - "pd.Timestamp": (pd.Timestamp("2020-02-27"), pd.Timestamp("2020-03-02")), - } - - for _fmt, (start, end) in formats.items(): - cli.get_price_range(start, end) - - # 呼び出しの履歴と、get_prices_daily_quotes()が呼ばれた際の年月日8桁の引数を比較 - # 並列実行のため順序は保証されないので、セットとして比較 - expected_dates = { - "2020-02-27", - "2020-02-28", - "2020-02-29", - "2020-03-01", - "2020-03-02", - } - actual_dates = { - call_obj.kwargs["date_yyyymmdd"] for call_obj in mock.mock_calls - } - assert actual_dates == expected_dates - assert len(mock.mock_calls) == 5 - mock.reset_mock()