pandasで株価データをCSV自動保存!蓄積データで分析精度を上げる方法

Python実装・コード

※本記事のコードや情報は執筆時点の仕様に基づいています。投資は自己責任であり、必ずデモ環境や少額資金でテストした上で運用してください。

yfinanceで株価データを取得できるようになったら、次に必要なのはデータの保存と蓄積です。取得したデータをCSVファイルとして保存しておけば、Excelでの分析や、後日のバックテストにそのまま活用できます。

しかし、単純に to_csv() を実行するだけでは、日本語の文字化けが発生したり、既存データが上書きされてしまったりと、実用上の問題が多く発生します。

この記事では、pandasを使った基本的なCSV保存から、文字化けを防ぐエンコーディング設定、既存ファイルへの追記処理、複数銘柄の一括保存、そして日付フォルダによる自動整理まで、実運用で必要なテクニックをすべてコピペ可能なコード付きで解説します。

CSVファイルで保存するメリットと基本知識

データベースやJSON形式など保存方法は複数ありますが、個人の株価分析においてCSV形式が最も実用的です。

CSV形式を選ぶ理由

保存形式 Excel対応 軽量性 可読性 推奨度
CSV ◎ ダブルクリックで開ける ◎ テキストエディタで閲覧可能
Excel (.xlsx) △ ファイルサイズが大きい × バイナリ形式
JSON × 変換が必要
SQLite × 専用ツールが必要 × △(大量データ向き)

CSVは「どの環境でも開ける」「Pythonでの読み書きが最も簡単」「Excelとの互換性が高い」という3つの利点を備えています。

pandasのDataFrameとCSVの関係

yfinanceで取得した株価データは、pandasのDataFrameというテーブル形式のオブジェクトとして格納されます。pandasにはDataFrameをCSVファイルとして書き出す to_csv() メソッドが標準搭載されており、1行のコードで保存が完了します。

保存時に注意すべき3つのポイント

CSVで株価データを保存する際、以下の3点を事前に理解しておく必要があります。

  • 文字コード(エンコーディング): UTF-8で保存するとExcelで文字化けする場合がある
  • インデックスの扱い: 日付がインデックスに入っているため、保存時の設定に注意が必要
  • 追記と上書きの制御: デフォルトでは上書き保存されるため、蓄積するには追記処理が必要

【コピペOK】基本の株価データ取得&CSV保存コード

まずは最もシンプルな形で、1銘柄の株価データを取得してCSVに保存するコードを紹介します。

基本コード:1銘柄を1ファイルに保存

以下のコードを save_stock_csv.py として保存し、実行してください。


import yfinance as yf
import pandas as pd
from datetime import datetime

# ==============================
# 設定エリア
# ==============================
SYMBOL = "7203.T"          # トヨタ自動車
PERIOD = "1y"              # 取得期間(1y=1年分)
OUTPUT_DIR = "./stock_data" # 保存先フォルダ

# ==============================
# メイン処理
# ==============================
def save_stock_to_csv():
    import os
    os.makedirs(OUTPUT_DIR, exist_ok=True)

    print(f"--- {SYMBOL} のデータを取得中 ---")
    ticker = yf.Ticker(SYMBOL)
    df = ticker.history(period=PERIOD)

    if df.empty:
        print("データが取得できませんでした。銘柄コードを確認してください。")
        return

    # インデックス(日付)をカラムに変換
    df.reset_index(inplace=True)

    # 日付フォーマットを整形(時刻情報を除去)
    df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")

    # ファイル名の生成
    filename = f"{OUTPUT_DIR}/{SYMBOL.replace('.', '_')}.csv"

    # CSV保存(BOM付きUTF-8でExcel文字化け防止)
    df.to_csv(filename, index=False, encoding="utf-8-sig")

    print(f"--- 保存完了: {filename} ---")
    print(f"--- データ件数: {len(df)}行 ---")

if __name__ == "__main__":
    save_stock_to_csv()

コードのポイント解説

このコードには、実用上重要な処理がいくつか含まれています。

  • os.makedirs(OUTPUT_DIR, exist_ok=True): 保存先フォルダが存在しない場合に自動作成する。exist_ok=True により、既にフォルダがあってもエラーにならない
  • df.reset_index(inplace=True): yfinanceのデータは日付がインデックスに格納されているため、通常のカラムに変換してからCSVに書き出す
  • encoding="utf-8-sig": BOM(バイトオーダーマーク)付きUTF-8で保存することで、Excelでダブルクリックした際の日本語文字化けを防止する

encoding="utf-8-sig" は日本語Windows環境でCSVを扱う際の必須設定です。 通常の utf-8 で保存すると、Excelで開いた際に日本語カラム名が文字化けします。

【コピペOK】複数銘柄を一括でCSV保存するコード

実際の運用では、複数の銘柄を監視・分析するケースが大半です。リスト形式で銘柄を指定し、一括で保存するコードを紹介します。

複数銘柄一括保存コード


import yfinance as yf
import pandas as pd
import os
import time

# ==============================
# 設定エリア
# ==============================
SYMBOLS = [
    "7203.T",   # トヨタ自動車
    "6758.T",   # ソニーグループ
    "9984.T",   # ソフトバンクグループ
    "8306.T",   # 三菱UFJフィナンシャルG
    "6861.T",   # キーエンス
]
PERIOD = "1y"
OUTPUT_DIR = "./stock_data"

# ==============================
# メイン処理
# ==============================
def save_multiple_stocks():
    os.makedirs(OUTPUT_DIR, exist_ok=True)

    results = []

    for symbol in SYMBOLS:
        print(f"[取得中] {symbol}...")
        try:
            ticker = yf.Ticker(symbol)
            df = ticker.history(period=PERIOD)

            if df.empty:
                print(f"  → {symbol}: データなし(スキップ)")
                results.append({"銘柄": symbol, "状態": "失敗", "件数": 0})
                continue

            df.reset_index(inplace=True)
            df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")

            filename = f"{OUTPUT_DIR}/{symbol.replace('.', '_')}.csv"
            df.to_csv(filename, index=False, encoding="utf-8-sig")

            print(f"  → 保存完了: {filename}({len(df)}行)")
            results.append({"銘柄": symbol, "状態": "成功", "件数": len(df)})

        except Exception as e:
            print(f"  → {symbol}: エラー発生 - {e}")
            results.append({"銘柄": symbol, "状態": "エラー", "件数": 0})

        # サーバー負荷軽減のため1秒待機
        time.sleep(1)

    # 結果サマリーを表示
    print("n=== 保存結果サマリー ===")
    summary_df = pd.DataFrame(results)
    print(summary_df.to_string(index=False))

if __name__ == "__main__":
    save_multiple_stocks()

一括保存コードの設計ポイント

  • try-except による例外処理: 1銘柄のエラーで全体が停止しないよう、個別にエラーをキャッチしている
  • time.sleep(1): 連続アクセスによるサーバー負荷を軽減するため、1銘柄ごとに1秒の待機を設けている
  • 結果サマリーの出力: 全銘柄の処理完了後、成功・失敗の一覧をテーブル形式で表示する

yfinanceは無料サービスであるため、短時間に大量のリクエストを送ると一時的にブロックされる場合があります。time.sleep(1) は削除しないでください。

【コピペOK】既存CSVへのデータ追記(蓄積型)

日次で株価データを蓄積していく場合、毎回上書きするのではなく、既存のCSVファイルに新しいデータを追記する処理が必要です。

追記型保存コード


import yfinance as yf
import pandas as pd
import os

# ==============================
# 設定エリア
# ==============================
SYMBOL = "7203.T"
OUTPUT_DIR = "./stock_data"

# ==============================
# 追記型保存処理
# ==============================
def append_stock_data():
    os.makedirs(OUTPUT_DIR, exist_ok=True)
    filename = f"{OUTPUT_DIR}/{SYMBOL.replace('.', '_')}.csv"

    # 新規データを取得(直近5日分)
    print(f"--- {SYMBOL} の最新データを取得中 ---")
    ticker = yf.Ticker(SYMBOL)
    new_df = ticker.history(period="5d")

    if new_df.empty:
        print("新規データの取得に失敗しました。")
        return

    new_df.reset_index(inplace=True)
    new_df["Date"] = new_df["Date"].dt.strftime("%Y-%m-%d")

    # 既存ファイルがある場合は読み込んで結合
    if os.path.exists(filename):
        existing_df = pd.read_csv(filename, encoding="utf-8-sig")
        combined_df = pd.concat([existing_df, new_df], ignore_index=True)

        # 日付の重複を除去(最新データを優先)
        combined_df.drop_duplicates(subset=["Date"], keep="last", inplace=True)
        combined_df.sort_values("Date", inplace=True)
        combined_df.reset_index(drop=True, inplace=True)

        print(f"  既存データ: {len(existing_df)}行")
        print(f"  結合後    : {len(combined_df)}行")
    else:
        combined_df = new_df
        print(f"  新規作成  : {len(combined_df)}行")

    # 保存
    combined_df.to_csv(filename, index=False, encoding="utf-8-sig")
    print(f"--- 保存完了: {filename} ---")

if __name__ == "__main__":
    append_stock_data()

追記処理の仕組み

この追記型コードは以下のロジックで動作します。

  1. 新規データを取得する
  2. 既存CSVファイルが存在するか確認する
  3. 存在する場合は既存データと新規データを pd.concat() で結合する
  4. drop_duplicates() で日付の重複行を除去する(keep="last" により最新データが優先される)
  5. 日付でソートして保存する

drop_duplicates(subset=["Date"], keep="last") が重要です。この処理がないと、同じ日付のデータが重複して蓄積されてしまいます。

保存したCSVファイルをPythonで読み込む方法

蓄積したCSVデータを分析に使うための読み込み方法も押さえておいてください。

基本の読み込みコード


import pandas as pd

df = pd.read_csv("./stock_data/7203_T.csv", encoding="utf-8-sig")
print(df.head())
print(f"データ件数: {len(df)}行")
print(f"期間: {df['Date'].iloc[0]} 〜 {df['Date'].iloc[-1]}")

日付カラムをdatetime型に変換する

CSVから読み込んだ日付カラムは文字列型になっています。時系列分析を行う場合は、datetime型に変換する必要があります。


df["Date"] = pd.to_datetime(df["Date"])
df.set_index("Date", inplace=True)

この変換を行うことで、df["2025-01":"2025-06"] のような期間指定によるスライスが可能になります。

Excelで開く場合の注意点

BOM付きUTF-8(utf-8-sig)で保存していれば、CSVファイルをダブルクリックするだけでExcelで正常に表示されます。

ただし、Excelは日付の自動変換機能を持っているため、意図しないフォーマット変換が発生する場合があります。データの正確性が重要な分析では、Excelではなく必ずPython(pandas)で読み込むことを推奨します。

日付フォルダによる自動整理

データが蓄積されていくと、ファイル管理が煩雑になります。保存日ごとにフォルダを自動作成する仕組みを導入すると管理が容易になります。

フォルダ構成の例


stock_data/
├── 2026-02-18/
│   ├── 7203_T.csv
│   └── 6758_T.csv
├── 2026-02-19/
│   ├── 7203_T.csv
│   └── 6758_T.csv
└── 2026-02-20/
    ├── 7203_T.csv
    └── 6758_T.csv

【コピペOK】日付フォルダ自動生成コード


import yfinance as yf
import pandas as pd
import os
from datetime import datetime

# ==============================
# 設定エリア
# ==============================
SYMBOL = "7203.T"
BASE_DIR = "./stock_data"

# ==============================
# 日付フォルダ保存処理
# ==============================
def save_with_date_folder():
    today = datetime.now().strftime("%Y-%m-%d")
    output_dir = f"{BASE_DIR}/{today}"
    os.makedirs(output_dir, exist_ok=True)

    print(f"--- {SYMBOL} のデータを取得中 ---")
    ticker = yf.Ticker(SYMBOL)
    df = ticker.history(period="1y")

    if df.empty:
        print("データが取得できませんでした。")
        return

    df.reset_index(inplace=True)
    df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")

    filename = f"{output_dir}/{SYMBOL.replace('.', '_')}.csv"
    df.to_csv(filename, index=False, encoding="utf-8-sig")

    print(f"--- 保存完了: {filename} ---")
    print(f"--- 保存先フォルダ: {output_dir} ---")

if __name__ == "__main__":
    save_with_date_folder()

この方式であれば、毎日スクリプトを実行するだけで日付別にデータが自動整理されます。Windowsのタスクスケジューラと組み合わせれば、完全自動での日次データ蓄積も可能です。

よくあるエラーと対処法

CSVをExcelで開くと数値が文字列として扱われる

Excelの仕様により、先頭が「0」の数値や、桁数の多い数値が文字列として認識されることがあります。これはCSVファイル側の問題ではなく、Excel側の表示仕様です。

正確なデータ分析を行う場合は、Excelではなく以下のようにpandasで読み込んでください。


df = pd.read_csv("data.csv", encoding="utf-8-sig")
print(df.dtypes)  # 各カラムのデータ型を確認

保存したCSVのファイルサイズが異常に大きい

yfinanceから取得したデータに不要なカラムが含まれている場合があります。必要なカラムだけを選択して保存することで、ファイルサイズを削減できます。


columns_to_save = ["Date", "Open", "High", "Low", "Close", "Volume"]
df[columns_to_save].to_csv(filename, index=False, encoding="utf-8-sig")

「PermissionError: [Errno 13]」が発生する

保存先のCSVファイルがExcelや別のプログラムで開かれている場合に発生します。保存先ファイルをすべて閉じてから再実行してください。

Pythonスクリプト実行中は、出力先のCSVファイルをExcelで開かないことを習慣にしてください。ファイルロックによる書き込みエラーの最も多い原因です。

まとめ

pandasとyfinanceを組み合わせた株価データのCSV保存について、以下のポイントを解説しました。

  • CSVの保存には df.to_csv() を使用し、encoding="utf-8-sig" を指定してExcelでの文字化けを防止する
  • reset_index() で日付をカラムに変換してから保存する
  • 複数銘柄は for ループで一括処理し、time.sleep(1) でサーバー負荷を軽減する
  • 追記型保存では pd.concat()drop_duplicates() を組み合わせて重複を排除する
  • 日付フォルダを自動生成することで、蓄積データの管理が容易になる

CSVファイルへのデータ保存は、テクニカル分析やバックテストを行うための土台です。このコードを応用して日次データの自動蓄積を実現し、次のステップである移動平均線やRSIの計算処理に進んでください。

タイトルとURLをコピーしました