📈

ChatGptに「最強の投資家」として数百社への投資判断を行ってもらい、結果をスプシに一括出力しよう

に公開

はじめに

株式投資をしてみようと思い立ったのですが、知識も何もない状態ではどう始めればいいのかわかりません。日本だけでも上場企業が4000社以上あり、そこから伸びる企業を正確に見つけ出すのは素人には困難です。そこで以下のように考えました。

「最強の投資家の思考をChatGptに模倣させて、上場企業全社について投資判断をして貰えばいいのではないか?」

「最強の投資家」というワードでGoogle検索をかけるとウォーレン・バフェット氏の名前が出てきます。彼の思考を模倣させば勝率が高いはずと考え、ChatGptに彼の思考を模倣させて投資判断を下してもらうための仕組みを考えました。

当記事では、OpenAI API(ChatGPT)を使って、企業への投資判断結果を自動でGoogleスプレッドシートに出力する仕組みを作りました。

スプレッドシートの準備

スプレッドシートを準備しましょう。
1行目はヘッダーにし、2行目以降のA列に調査したい企業名を入力していきます。

バフェットコード」から、日本の上場企業の時価総額TOP100社の名前をコピーしてそのままスプシにコピペしました。

スプレッドシートのIDを控えておきます。

Google Cloudでサービスアカウントを作成

  • 最初にGoogleアカウントを作成します。
  • Google Cloud Consoleにアクセスして、新規プロジェクトを作成します。
  • Google Sheets APIを有効化
    • 「APIとサービス」→「ライブラリ」→「Google Sheets API」を有効化
  • サービスアカウント作成
    • 「APIとサービス」→「認証情報」→「認証情報を作成」→「サービスアカウント」
    • サービスアカウントには任意の名前をつけます。ロールは何も付与しなくて大丈夫です。
  • サービスアカウントのキー(credentials.json)を作成
    • サービスアカウント画面の右側の3点ボタンを押し、「鍵を管理」を選択
    • →「キー」タブ→「鍵を追加」→「新しい鍵を作成」→ キーのタイプ:「JSON」を選択しダウンロード
    • このJSONファイルは外部に漏らさないように注意してください。
  • スプレッドシートの共有設定
    • ダウンロードされたjsonファイルにclient_emailという値が入っています。
    • スプレッドシートの「共有」からこのメールアドレスを編集者または範囲指定編集者として追加

OpenAI APIキーの取得

  • OpenAI Platformにログイン
  • Settings」>「API keys」からAPIキーを新規発行し、控えておきます
  • ただし、APIキーを発行しても何も課金しなければAPIを叩くことはできません。
  • 「Billing」ページから課金を行う必要があります。最低課金ラインである5ドル(記事公開当時 733円)を課金しましょう。

Node.js/TypeScriptプロジェクトのセットアップ

  • コードエディターをPCにダウンロードして、新規フォルダを開きましょう。(Cursor, Visual Studio Codeなど何かしらを適当に使ってください)

  • ターミナルから、必要なパッケージをインストール

npm init -y
npm install google-spreadsheet openai google-auth-library typescript 
npx tsc --init
  • 以下のts.config.jsonを作成
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Node",
    "esModuleInterop": true,
    "strict": true,
    "skipLibCheck": true
  }
}
  • index.tsファイルを作り、以下の内容を貼り付けます。
  • 以下の情報だけご自身が先述の工程で取得した値に置き換えてください
    • SPREADSHEET_ID
    • SHEET_TITLE
    • GOOGLE_SERVICE_ACCOUNT_EMAIL
    • GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY
    • OPENAI_API_KEY
import { JWT } from "google-auth-library";
import { GoogleSpreadsheet } from "google-spreadsheet";
import OpenAI from "openai";

// 先述の工程で取得したスプレッドシートのIDを設定
const SPREADSHEET_ID = "xxxx";
const SHEET_TITLE = 'シート名';

// 先述の工程で取得したGoogleサービスアカウントのemailとkeyを貼ります。
const GOOGLE_SERVICE_ACCOUNT_EMAIL = "xxx@yyy.iam.gserviceaccount.com";
const GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\nxxxxx"

// 先述の工程で取得したOpenAI APIのキーを貼ります
const OPENAI_API_KEY = "secret";

const openai = new OpenAI({
  apiKey: OPENAI_API_KEY,
});

const OUTPUT_JSON = {
  buffett_recommendation: "BUY | HOLD | SELL",
  understandable_business: "事業は理解可能か?10年後を予測できるか?",
  economic_moat: "競争優位性の強さ(Wide/Narrow/None)と説明",
  business_quality: "ROE・利益成長・負債の健全性評価",
  management_quality: "経営陣の株主価値創造能力",
  intrinsic_value: "本質的価値と現在価格の比較",
  margin_of_safety: "安全域(%)",
  forever_hold_worthy: "永続保有に値するか?理由",
  buffett_would_buy: "バフェットなら投資するか?(Yes/No/Maybe)",
  key_concern: "最大の懸念点",
  investment_thesis: "バフェット流投資判断の要約(200文字)",
};

// 構造化JSONで出力させます
// これにより、分析結果をより正確に、かつ効率的に取得できます
const buildPrompt = (company: string) => `
You are Warren Buffett analyzing ${company}. Apply the Berkshire Hathaway investment criteria.

BUFFETT'S INVESTMENT CHECKLIST:

1. **Circle of Competence**: Can I understand this business and predict it in 10 years?
2. **Economic Moat**: Strong competitive advantages (brand, network effects, switching costs, scale)
3. **Wonderful Business**: High ROE (15%+), consistent earnings, minimal debt, pricing power
4. **Great Management**: Honest, shareholder-focused, smart capital allocation
5. **Margin of Safety**: Buy below intrinsic value with 25%+ discount
6. **Forever Hold**: Quality business I'd own for decades

REJECTION CRITERIA:
❌ Complex/unpredictable businesses, commodity industries, high debt, poor management

BUFFETT PHILOSOPHY:
- "Price is what you pay, value is what you get"
- "Time is friend of wonderful business"
- Think like buying entire company, not just shares
- "Be greedy when others are fearful"

Return JSON in Japanese:

${JSON.stringify(OUTPUT_JSON)}

Think: "Would I be happy owning this entire business for 20 years?"
`;

const fetchCompanyInfo = async (company: string) => {
  const response = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [
      { role: "system", content: "You are a concise, fact-driven analyst." },
      { role: "user", content: buildPrompt(company) },
    ],
    // temperatureを低めに設定して、回答に一貫性を持たせます
    temperature: 0,
    max_tokens: 1000,
  });

  const content = response.choices[0]?.message?.content ?? "No data found.";

  // 文字列をJSONに変換します
  const processedContent = content.replace(/^```json\n|```$/g, "");
  return JSON.parse(processedContent);
};

const chunkArray = <T>(array: T[], size: number): T[][] => {
  const result: T[][] = [];
  for (let i = 0; i < array.length; i += size) {
    result.push(array.slice(i, i + size));
  }
  return result;
};

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

const updateSpreadsheet = async () => {
  const serviceAccountAuth = new JWT({
    email: GOOGLE_SERVICE_ACCOUNT_EMAIL,
    key: GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY,
    scopes: ["https://www.googleapis.com/auth/spreadsheets"],
  });

  const doc = new GoogleSpreadsheet(SPREADSHEET_ID, serviceAccountAuth);
  await doc.loadInfo();

  const sheet = doc.sheetsByTitle[SHEET_TITLE];
  sheet.setHeaderRow(["会社名", ...Object.values(OUTPUT_JSON)]);
  const rows = await sheet.getRows();

  // 10件ずつ分割
  const chunks = chunkArray(rows, 10);

  for (const chunk of chunks) {
    await Promise.all(
      chunk.map(async (row) => {
        try {
          const companyName = row.get("会社名");
          const info = await fetchCompanyInfo(companyName);
          console.log({ info });

          Object.entries(OUTPUT_JSON).forEach(([key, headerLabel]) => {
            row.set(
              headerLabel,
              info[key as keyof typeof info]
                .replace(new RegExp(`^${headerLabel}:`, "g"), "")
                .trim()
            );
          });

          await row.save();
          // エラーが起きたらキャッチしておく
        } catch {}
      })
    );

    // 3秒待つ
    await delay(3000);
  }
};

updateSpreadsheet()
  .then(() => {
    console.log("スプレッドシート更新完了");
  })
  .catch(console.error);
  • ディレクトリの状況はこのようになっているはずです。

プロンプトについての解説

You are Warren Buffett analyzing ${company}. Apply the Berkshire Hathaway investment criteria.

BUFFETT'S INVESTMENT CHECKLIST:

1. **Circle of Competence**: Can I understand this business and predict it in 10 years?
2. **Economic Moat**: Strong competitive advantages (brand, network effects, switching costs, scale)
3. **Wonderful Business**: High ROE (15%+), consistent earnings, minimal debt, pricing power
4. **Great Management**: Honest, shareholder-focused, smart capital allocation
5. **Margin of Safety**: Buy below intrinsic value with 25%+ discount
6. **Forever Hold**: Quality business I'd own for decades

REJECTION CRITERIA:
❌ Complex/unpredictable businesses, commodity industries, high debt, poor management

BUFFETT PHILOSOPHY:
- "Price is what you pay, value is what you get"
- "Time is friend of wonderful business"
- Think like buying entire company, not just shares
- "Be greedy when others are fearful"

Return JSON in Japanese:

{
  buffett_recommendation: "BUY | HOLD | SELL",
  understandable_business: "事業は理解可能か?10年後を予測できるか?",
  economic_moat: "競争優位性の強さ(Wide/Narrow/None)と説明",
  business_quality: "ROE・利益成長・負債の健全性評価",
  management_quality: "経営陣の株主価値創造能力",
  intrinsic_value: "本質的価値と現在価格の比較",
  margin_of_safety: "安全域(%)",
  forever_hold_worthy: "永続保有に値するか?理由",
  buffett_would_buy: "バフェットなら投資するか?(Yes/No/Maybe)",
  key_concern: "最大の懸念点",
  investment_thesis: "バフェット流投資判断の要約(200文字)",
};

Think: "Would I be happy owning this entire business for 20 years?"

プロンプトはこのようになっています。ChatGptの思考の精度を上げるために、命令文は基本的に日本語ではなく英語を使っています。

最初に以下のような一文を加えることで、ChatGptにウォーレン・バフェットの思考を模倣させることができます。

You are Warren Buffett analyzing ${company}.
Apply the Berkshire Hathaway investment criteria.

↓
(日本語訳)
あなたはウォーレン・バフェットとして ${company} を分析します。
バークシャー・ハサウェイの投資基準を適用してください。

また、各企業ごとの調査について、共通のフォーマットで結果が出力されるようにしています。共通フォーマットで返答させることで、スプレッドシートに表示する際に、同じ列に同じ情報を並べることが可能になります。

リサーチの実行

以下のコマンドを実行します。

npx tsx index.ts

今回は日本の上場企業の時価総額TOP100について判断を下してもらいましたが、投資判断=yesの会社は0という結果に終わりました。

日本の上場企業には投資をしない方がいいということなのでしょうか。。。

料金について

  • モデル: gpt-4o
  • 調査対象の企業数: 100
  • 1リクエストあたりのmaxトークン: 1000
  • 料金: 0.5ドル

100社分の情報を調べるのに、0.5ドル(日本円換算で数十円)しかかかりませんでした。
かなりお得に調査ができますね!

おわりに

この仕組みを使えば、大量の企業に対する投資判断を短い時間で行えるようになるかもしれません。
プロンプトを工夫すれば、より個々人が得たい情報を手に入れることができるでしょう。
ぜひみなさんも試してみてください!

Discussion