朝から株野郎?計画2
前回の記事
DBは何を使う?
ふうこさんに相談したところ、
Androidアプリと連携するのであれば、SQLiteかPostgreSQLが鉄板とのこと。
| DB種類 | 特徴 | 向いてる用途 | ふうこ評価 |
|---|---|---|---|
| SQLite | ファイル型DB。導入が超カンタン。 | 小規模アプリ、ローカル開発 | ⭐️⭐️⭐️⭐️(最初に◎) |
| PostgreSQL | 本格的なRDBMS。拡張性高い。 | サーバーに置いて複数アプリからアクセス | ⭐️⭐️⭐️⭐️⭐️(中〜長期で最強) |
よし、まずは簡単そうなSQLiteにしよう。
公開とかが見えてきたらPostgreSQLに切り替えることを検討ということで!!!
データの流れ方を整理すると、こんな感じ。
yFinanceから株データを取得→DB保存→データ加工→FastAPI→Android
テーブル設計する
テーブルは以下を検討。
company_info テーブル(企業指標など:上書き保存)
| カラム名 | 型 | 説明 |
|---|---|---|
| id | INTEGER | 自動採番・主キー |
| symbol | TEXT | 銘柄コード(例: 7203.T) |
| date | TEXT | データ取得日(例: 2025-07-06) |
| market_cap | REAL | 時価総額 |
| enterprise_value | REAL | 企業価値(Enterprise Value) |
| trailing_pe | REAL | PER(株価収益率) |
| forward_pe | REAL | 予想PER |
| peg_ratio | REAL | PEGレシオ |
| price_to_book | REAL | PBR(株価純資産倍率) |
| earnings_quarterly_growth | REAL | 四半期利益成長率(前年比) |
| dividend | REAL | 年間配当額(1株あたり) |
| dividend_yield | REAL | 配当利回り(%) |
| payout_ratio | REAL | 配当性向(%) |
| last_dividend_date | TEXT | 直近の配当支払日 |
| ex_dividend_date | TEXT | 権利落ち日 |
stock_prices テーブル(株価履歴:日々追加)
| カラム名 | 型 | 説明 |
|---|---|---|
| id | INTEGER | 自動採番・主キー |
| symbol | TEXT | 銘柄コード(例: 7203.T) |
| date | TEXT | 取引日(例: 2025-07-06) |
| open | REAL | 始値 |
| high | REAL | 高値 |
| low | REAL | 安値 |
| close | REAL | 終値 |
| volume | INTEGER | 出来高 |
DBセットアップする!
Pythonでinit_db.pyを新規作成。
以下コードを書いて、F5で実行。
import sqlite3
def init_db():
# データベースに接続(なければ作成)
conn = sqlite3.connect('stocks.db')
cursor = conn.cursor()
# 企業情報テーブルの作成
cursor.execute('''
CREATE TABLE IF NOT EXISTS company_info (
id INTEGER PRIMARY KEY AUTOINCREMENT,
symbol TEXT NOT NULL,
date TEXT NOT NULL,
market_cap REAL,
enterprise_value REAL,
trailing_pe REAL,
forward_pe REAL,
peg_ratio REAL,
price_to_book REAL,
earnings_quarterly_growth REAL,
dividend REAL,
dividend_yield REAL,
payout_ratio REAL,
last_dividend_date TEXT,
ex_dividend_date TEXT,
UNIQUE (symbol) ON CONFLICT REPLACE
)
''')
# 株価データテーブルの作成
cursor.execute('''
CREATE TABLE IF NOT EXISTS stock_prices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
symbol TEXT NOT NULL,
date TEXT NOT NULL,
open REAL,
high REAL,
low REAL,
close REAL,
volume INTEGER,
UNIQUE (symbol, date) ON CONFLICT REPLACE
)
''')
# 株価データのインデックスを作成
cursor.execute('''
CREATE INDEX IF NOT EXISTS idx_stock_prices_symbol_date ON stock_prices (symbol, date)
''')
# 企業情報のインデックスを作成
cursor.execute('''
CREATE INDEX IF NOT EXISTS idx_company_info_symbol_date ON company_info (symbol, date)
''')
# 株価データのユニーク制約を追加
cursor.execute('''
CREATE UNIQUE INDEX IF NOT EXISTS idx_unique_stock_prices ON stock_prices (symbol, date)
''')
# 変更を保存して接続を閉じる
conn.commit()
conn.close()
if __name__ == "__main__":
init_db()
print("データベースの初期化が完了しました。")
エラーがなければinit_db.pyと同じフォルダに「stocks.db」ができる。
さっそく中身を確認!!!
・・・と思ったら、見れなかった😮

私のVSCodeにはDBの中を見るための拡張機能がなかったのね。
拡張機能を入れよう。
SQLiteで検索したらめっちゃいっぱい出てきた。
インストール数が多いのに、高評価なSQLiteViewerにしよう。

やっとDBの中を確認できました😅
私が作ったテーブル2個と、SQLiteが勝手に作ったテーブル1つありますね。
内容については想定通りなので、よし!

データ入れてみるか
データを突っ込まないと話にならないので、アメリカと日本から1社ずつ選択して
入れてみることにする。
アメリカはAAPL(アップル)、日本は7203.T(トヨタ自動車)
PEGが取れないことが分かったので、ありものデータで無理やり計算。
(そこまでしてPEGいるのかな💦後で削除するかも。)
コパイロットが空気を読んでコードを先に書いてくれるから、SQL書くのもめっちゃ楽だった。
自分で書くとスペルミスで余裕で時間つぶすので、本当AIってすごいなって思った。
企業情報テーブル編
import sqlite3
import yfinance as yf
from datetime import datetime, timedelta
def update_company_info(symbol:str):
# yfinanceを使用して指定銘柄の情報を取得
ticker = yf.Ticker(symbol)
info = ticker.info
# 四半期成長率を使ってPEG計算(PEGが取れないので)
earnings_quarterly_growth = info.get('earningsQuarterlyGrowth', None)
if earnings_quarterly_growth is not None:
# 四半期成長率を年率換算
eps_growth_rate = (1 + earnings_quarterly_growth) ** 4 - 1
else:
eps_growth_rate = None
# PEG比率の計算
trailing_pe = info.get('trailingPE', None)
if eps_growth_rate and eps_growth_rate != 0:
peg_ratio = trailing_pe / eps_growth_rate
else:
peg_ratio = None
# 今日の日付を取得
today = datetime.now().strftime("%Y-%m-%d")
# データベースに接続
conn = sqlite3.connect('stocks.db')
cursor = conn.cursor()
# 企業情報の準備
company_info = {
"symbol": symbol,
"date": today,
"market_cap": info.get('marketCap', None),
"enterprise_value": info.get('enterpriseValue', None),
"trailing_pe": info.get('trailingPE', None),
"forward_pe": info.get('forwardPE', None),
"peg_ratio": peg_ratio,
"price_to_book": info.get('priceToBook', None),
"earnings_quarterly_growth": info.get('earningsQuarterlyGrowth', None),
"dividend": info.get('dividendRate', None),
"dividend_yield": info.get('dividendYield', None),
"payout_ratio": info.get('payoutRatio', None),
"last_dividend_date": info.get('lastDividendDate', None),
"ex_dividend_date": info.get('exDividendDate', None)
}
# 日付の変換
if company_info["last_dividend_date"]:
company_info["last_dividend_date"] = datetime.fromtimestamp(company_info["last_dividend_date"]).strftime("%Y-%m-%d")
if company_info["ex_dividend_date"]:
company_info["ex_dividend_date"] = datetime.fromtimestamp(company_info["ex_dividend_date"]).strftime("%Y-%m-%d")
# 企業情報をデータベースに挿入または更新
cursor.execute('''
INSERT INTO company_info (symbol, date, market_cap, enterprise_value, trailing_pe, forward_pe,
peg_ratio, price_to_book, earnings_quarterly_growth, dividend,
dividend_yield, payout_ratio, last_dividend_date, ex_dividend_date)
VALUES (:symbol, :date, :market_cap, :enterprise_value, :trailing_pe, :forward_pe,
:peg_ratio, :price_to_book, :earnings_quarterly_growth, :dividend,
:dividend_yield, :payout_ratio, :last_dividend_date, :ex_dividend_date)
ON CONFLICT(symbol, date) DO UPDATE SET
market_cap = excluded.market_cap,
enterprise_value = excluded.enterprise_value,
trailing_pe = excluded.trailing_pe,
forward_pe = excluded.forward_pe,
peg_ratio = excluded.peg_ratio,
price_to_book = excluded.price_to_book,
earnings_quarterly_growth = excluded.earnings_quarterly_growth,
dividend = excluded.dividend,
dividend_yield = excluded.dividend_yield,
payout_ratio = excluded.payout_ratio,
last_dividend_date = excluded.last_dividend_date,
ex_dividend_date = excluded.ex_dividend_date
''', company_info)
# 変更を保存
conn.commit()
# 接続を閉じる
conn.close()
# 結果出力
print(f"企業情報を更新しました: {symbol} - {today}")
if __name__ == "__main__":
# 例としてAAPLとトヨタ自動車の企業情報を更新
update_company_info("7203.T")
F5で実行してから、stocks.dbを確認。
2行目はスペルミスしてアップルを「APPL」としたので、データが取得できず、
nullが入ってます。恥ずかしい。。。😂

ここまで来て。。。
ミスというほどではないのですが、企業情報テーブルはsymbolをキーに常に上書きしに行くので
symbolをキーにすればいいじゃんって気づきました。
ID削除してsymbolをプライマリキーに修正することに。
# 企業情報テーブルの作成
cursor.execute('''
CREATE TABLE IF NOT EXISTS company_info (
symbol TEXT PRIMARY KEY,
date TEXT NOT NULL,
market_cap REAL,
enterprise_value REAL,
trailing_pe REAL,
forward_pe REAL,
peg_ratio REAL,
price_to_book REAL,
eps_growth_rate REAL,
earnings_quarterly_growth REAL,
dividend REAL,
dividend_yield REAL,
payout_ratio REAL,
last_dividend_date TEXT,
ex_dividend_date TEXT
)
''')
DBを作り直しになるので、DB削除します。
rm stocks.db
で、もう1回init_dbをF5で実行。
idが消えて、symbolがキーになりました!

株価テーブル編
新規ファイル「update_stock_prices.py」を作成し、コードを記述していきます。
企業情報テーブルとほぼ同じようなコーディングです。
共通のレコード追加変更関数作ればいいのかなって思いましたが、
テーブルが増えそうだなと感じたときにやります🤮
そんなわけでコード。
import sqlite3
import yfinance as yf
from datetime import datetime, timedelta
def update_strock_prices(symbol: str):
# yfinanceを使用して指定銘柄の株価データを取得
ticker = yf.Ticker(symbol)
hist = ticker.history(period="1d") # 最新の株価データを取得
# データが取得できなかった場合の処理
if hist.empty:
print(f"株価データがありませんでした: {symbol}")
return
# 最新の株価データを取得
latest_data = hist.iloc[-1]
date = latest_data.name.strftime("%Y-%m-%d")
# データベースに接続
conn = sqlite3.connect('stocks.db')
cursor = conn.cursor()
# 株価データの準備
stock_price = {
"symbol": symbol,
"date": date,
"open": latest_data['Open'],
"high": latest_data['High'],
"low": latest_data['Low'],
"close": latest_data['Close'],
"volume": int(latest_data['Volume'])
}
# 株価データをデータベースに挿入または更新
columns = [
"symbol", "date", "open", "high", "low", "close", "volume"
]
insert_columns = ', '.join(columns)
placeholders = ', '.join([':' + col for col in columns])
update_columns = ', '.join([f"{col} = excluded.{col}" for col in columns[2:]]) # open, high, low, close, volume
sql = f'''
INSERT INTO stock_prices ({insert_columns})
VALUES ({placeholders})
ON CONFLICT(symbol, date) DO UPDATE SET
{update_columns}
'''
# SQL文を実行
cursor.execute(sql, stock_price)
# 変更を保存して接続を閉じる
conn.commit()
conn.close()
print(f"株価データを更新しました: {symbol} - {date}")
if __name__ == "__main__":
# 例としてAAPLの株価データを更新
update_strock_prices("AAPL") # Apple
update_strock_prices("7203.T") # トヨタ自動車
実行すると、直近のアップルとトヨタ自動車の株価が株価テーブルに追加されます。
DBに個別銘柄の情報を登録することができたので、次回は東証プライムの企業情報と
株価を一括登録にチャレンジします。
Discussion