😸

東証銘柄の株価を取得してGoogleスプレッドシートを更新する

に公開

まず結論

個人用の集計表で東証銘柄の価格を更新するなら、Node.js から yahoo-finance2 を呼び、Sheets API へまとめて書き込む方法があります。ただし Yahoo Finance の API は非公式です。売買判断や業務システムには、契約条件と品質保証が明確な J-Quants API や JPX の有償データを選びます。

この記事の例は、Node.js 22 以降、yahoo-finance2 4 系、Google Sheets API v4 を前提にします。導入時は利用するバージョンの README と型定義を確認してください。

import YahooFinance from "yahoo-finance2";
import { google } from "googleapis";

const yahooFinance = new YahooFinance();
const quote = await yahooFinance.quote("7203.T");
console.log(quote.regularMarketPrice);

使う場面

この構成が向くのは、次の条件です。

  • 個人用の資産集計など、多少の遅延や欠損を許容できる
  • API の変更時に自分で追随できる
  • 価格を売買執行や顧客向け表示へ直接使わない

スプレッドシート内で完結させたい場合は GOOGLEFINANCE も候補ですが、公式ヘルプは多くの海外市場を対象外としています。対象銘柄で取得できるか先に試してください。

構文と設定項目

項目 補足
東証のシンボル 7203.T Yahoo Finance形式
スプレッドシートID URL中のID 環境変数で渡す
書き込み範囲 Prices!A2:C 行数に合わせて終端を組み立てる
認証 Application Default Credentials またはサービスアカウント 対象シートを共有し、Sheets APIを有効にする
実行環境 Node.js 22 以降 yahoo-finance2 4 系を利用する

API キーや認証 JSON をソースコードへ埋め込まず、実行環境のシークレットとして管理します。

サービスアカウントを使う場合は、Google Cloud で Sheets API を有効にし、サービスアカウントのメールアドレスを対象スプレッドシートへ共有します。SPREADSHEET_ID と認証情報の場所は環境変数などで渡し、認証 JSON をリポジトリへ追加しません。

実装例

次は Node.js で複数銘柄を取得し、値を一括更新する骨格です。再試行の回数や間隔は、データの鮮度と API の利用制限に合わせて決めてください。

import YahooFinance from "yahoo-finance2";
import { google } from "googleapis";

const symbols = ["7203.T", "6758.T"];
const yahooFinance = new YahooFinance();

async function loadRows(): Promise<(string | number | null)[][]> {
  return Promise.all(
    symbols.map(async (symbol) => {
      const quote = await yahooFinance.quote(symbol);
      return [
        symbol,
        quote.regularMarketPrice ?? null,
        quote.regularMarketTime?.toISOString() ?? null,
      ];
    }),
  );
}

async function updateSheet(): Promise<void> {
  const spreadsheetId = process.env.SPREADSHEET_ID;
  if (!spreadsheetId) {
    throw new Error("SPREADSHEET_ID is required");
  }

  const auth = new google.auth.GoogleAuth({
    scopes: ["https://www.googleapis.com/auth/spreadsheets"],
  });
  const sheets = google.sheets({ version: "v4", auth });
  const values = await loadRows();

  // 1件でも価格を取得できなければ、前回値を残したまま更新しない
  if (values.length === 0 || values.some(([, price]) => typeof price !== "number")) {
    throw new Error("A quote did not contain a numeric price");
  }

  await sheets.spreadsheets.values.update({
    spreadsheetId,
    range: `Prices!A2:C${values.length + 1}`,
    valueInputOption: "RAW",
    requestBody: { values },
  });
}

try {
  await updateSheet();
} catch (error) {
  console.error("価格の取得またはスプレッドシートの更新に失敗しました", error);
  process.exitCode = 1;
}

loadRows()Promise.all で全銘柄の取得が終わるまで待ち、取得処理または価格の検証に失敗した場合は values.update を呼びません。そのため、取得失敗時に前回の値を消さずに済みます。コード例は認証情報を用いた実行確認をしていないため、まずコピーした検証用スプレッドシートで試してください。

つまずきやすい点

非公式APIを安定したデータソースとみなす

yahoo-finance2 自身が、Yahoo との提携がない非公式ライブラリだと明記しています。レスポンス変更、利用制限、欠損を前提にします。

セルを1件ずつ更新する

API 呼び出し回数が増え、遅くなります。2 次元配列を作って spreadsheets.values.update でまとめて書き込みます。

価格だけを保存する

取得時刻、通貨、取引所を一緒に持たないと、後から値の意味を確認できません。少なくとも取得時刻を保存します。

エラー時に前回値を消す

取得失敗と価格 0 を区別します。前回値を残す場合も、最終成功時刻とエラー状態を別列で示します。上の例では、取得または検証に失敗した時点で更新処理を止め、標準エラー出力へ記録します。

関連する機能

まとめ

試作や個人集計なら、非公式 API と Sheets API の組み合わせは手軽です。用途が重要になるほど、データの契約、時刻、欠損時の扱いを先に決め、公式または有償のデータソースへ切り替えます。

Discussion