日経平均株価を予想するためにすること
まず始めに日経平均株価をPythonで予想して、投資に役立てたいという熱意がありました。
そのためにPPDACサイクル(Problem->Plan->Data->Analysis->Conclusion)を回すことを考えてみました。
今回のPPDACサイクル
Problem:日経平均株価の動きを予想したい!
Plan:日経平均株価、出来高、空売り比率から予想する(ことができるのでは?という仮定)
Data:日経平均株価と出来高は、pandas-datareaderから取得する。空売り比率は、下記サイトからPDFファイルを集め、Pythonでcsv出力する。
JPXサイト
https://www.jpx.co.jp/markets/statistics-equities/short-selling/index.html
Analysis:それぞれの相関関係を調べる。(前編では扱わないです。というか後編があるかも分からないです。)
Conclusion:未定。。。相関関係があれば良いのだけど。
Data取得
(1)pandas-datareaderを用いた日経平均株価と出来高の取得+csv出力
株価取得のソースコード
終値の値のみをcsv出力しています。
import pandas_datareader.data as web
import datetime
import csv
year = '22'
month = '01'
start = datetime.datetime(2022, 1, 1)
end = datetime.datetime(2022, 1, 31)
tsd = web.DataReader("^N225", "yahoo", start, end)
print(tsd)
with open(f'./20220110_NIKKEI/csv/{year}{month}Close_price.csv', 'w') as f:
writer = csv.writer(f)
writer.writerow(tsd['Close'])
出来高取得のソースコード
出来高をcsv出力しています。
import pandas_datareader.data as web
import datetime
import csv
year = '22'
month = '01'
start = datetime.datetime(2022, 1, 1)
end = datetime.datetime(2022, 1, 31)
tsd = web.DataReader("^N225", "yahoo", start, end)
print(tsd)
with open(f'./20220110_NIKKEI/csv/{year}{month}Volume.csv', 'w') as f:
writer = csv.writer(f)
writer.writerow(tsd['Volume'])
(2)JPXサイトから取得したpdfファイルをcsv出力
まずはJPXサイトからpdfファイルをダウンロードします。
これにはchromeの拡張機能の"DownThemAll!"を使用しました。(ファイルを1回しかダウンロードしないため、あまりソースコード化する必要を感じませんでした。。。)
https://chrome.google.com/webstore/detail/downthemall/nljkibfhlpcnanjgbnlnbjecgicbjkge?hl=en
ダウンロードしたPDFファイルのテキスト化
ダウンロードしたPDFファイルをテキストファイル化しています。
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage
import os
input = './20220110_NIKKEI/pdf/'
def pdf2text(yearMonth, yearMonthDay):
input_path = f'./20220110_NIKKEI/pdf/{yearMonth}/{yearMonthDay}-m.pdf'
output_path = f'./20220110_NIKKEI/pdf/{yearMonth}/{yearMonthDay}-m.txt'
manager = PDFResourceManager()
with open(output_path, "wb") as output:
with open(input_path, 'rb') as input:
with TextConverter(manager, output, codec='utf-8', laparams=LAParams()) as conv:
interpreter = PDFPageInterpreter(manager, conv)
for page in PDFPage.get_pages(input):
interpreter.process_page(page)
for i in range(32):
if i < 10:
ym = '202110'
ymd = f'21100{i}'
input_file = f'{input}{ym}/{ymd}-m.pdf'
if(os.path.exists(input_file)):
pdf2text(ym, ymd)
else:
ym = '202110'
ymd = f'2110{i}'
input_file = f'{input}{ym}/{ymd}-m.pdf'
if(os.path.exists(input_file)):
pdf2text(ym, ymd)
else:
print('FINISH!')
次にテキスト化ファイルのcsv出力します。
色々、ハマる所はありましたが、csv出力する箇所は、「価格規制ありの空売り比率」に絞りました。
import os
import csv
year = '21'
month = '10'
pathOrigin = './20220110_NIKKEI/text/'
new_list = []
final_list = []
def short_ratio(nameNum):
new_path = f'{pathOrigin}{year}{month}{nameNum}-m.txt'
with open(new_path) as f:
contents = f.readlines()[44]
new_list.append(contents)
#print(new_list)
for i in range(32):
if i < 10:
num = f'0{i}'
path_Under = f'{pathOrigin}{year}{month}{num}-m.txt'
if(os.path.exists(path_Under)):
short_ratio(num)
else:
num = i
path_Over = f'{pathOrigin}{year}{month}{num}-m.txt'
if(os.path.exists(path_Over)):
short_ratio(i)
#print(new_list)
for list in new_list:
list = list.replace('%\n', '')
final_list.append(list)
print(final_list)
path_final = f'./20220110_NIKKEI/csv/{year}{month}short.csv'
with open(path_final, 'w') as f:
writer = csv.writer(f)
writer.writerow(final_list)
本記事は、私の備忘録的な扱いです。。。
結構、苦労してここまで来ました(祝日1日使いました)が、分析まで至らず残念でした。。。
後日談というか後編
単回帰分析による日経平均株価の予想プログラムを書いたよー
import pandas_datareader.data as pdr
import statsmodels.api as sm
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
start="2022/10/10"
end="2022/11/10"
n225=pdr.DataReader("NIKKEI225", "fred", start, end).dropna()
ln_n225=np.log(n225.dropna())
ln_n225.columns=['Close']
y=ln_n225
x=range(len(ln_n225))
x=sm.add_constant(x)
model=sm.OLS(y, x)
results=model.fit()
print(results.summary())
plt.plot(y, label='Close', color="blue")
results.fittedvalues.plot(label='prediction', style='--')
plt.ylabel('log(n225 index)')
plt.legend(loc='upper left')
plt.show()
future_Results=results.params[0]+results.params[1]*(len(x)+1)
print(f'明日の日経平均予想価格は、{int(np.exp(future_Results))}です。')
何をしているかと言うと?
日経平均株価の対数から単回帰直線を引き、その直線を伸ばして「明日の日経平均株価」を予測しています。
(精度は保証しません!)
GitHubで公開しているよー
追加記事
日経平均株価と商品先物価格との相関関係を調べたよ
日経平均株価とカカオ・銅・砂糖の先物価格の相関係数を調べました。
結果:相関係数0.63→0.68(コードを修正しました)
処理:日経平均価格終値 vs (カカオ * a)^pa * (銅 * b)^pb - (砂糖 * c)^pcという数式を立てて、機械学習っぽいことで最適化しました。
以下、Pythonコードです。
import yfinance as yf
import pandas as pd
from scipy.optimize import minimize
from scipy.stats import pearsonr
class Data:
def __init__(self, symbol, start_date, end_date):
self.symbol = symbol
self.start_date = start_date
self.end_date = end_date
def get_data(self):
data = yf.download(self.symbol, start=self.start_date, end=self.end_date)
return data["Close"].to_frame(name=self.symbol) # 終値のDataFrameを返す
# インスタンスの作成とデータの取得
cacao_instance = Data("CC=F", "1990-01-01", "2024-03-31")
cacao_close_df = cacao_instance.get_data().rename(columns={"CC=F": "Cacao Close"})
copper_instance = Data("HG=F", "1990-01-01", "2024-03-31")
copper_close_df = copper_instance.get_data().rename(columns={"HG=F": "Copper Close"})
sugar_instance = Data("SB=F", "1990-01-01", "2024-03-31")
sugar_close_df = sugar_instance.get_data().rename(columns={"SB=F": "Sugar Close"})
nikkei_instance = Data("^N225", "1990-01-01", "2024-03-31")
nikkei_close_df = nikkei_instance.get_data().rename(columns={"^N225": "Nikkei Close"})
exchange_instance = Data("JPY=X", "1990-01-01", "2024-03-31")
exchange_rate_df = exchange_instance.get_data().rename(columns={"JPY=X": "Exchange Rate"})
# データフレームの結合とドル建て日経平均株価の計算
merged_data = pd.concat([cacao_close_df, copper_close_df, sugar_close_df, nikkei_close_df, exchange_rate_df], axis=1)
merged_data["Nikkei Close USD"] = merged_data["Nikkei Close"] / merged_data["Exchange Rate"]
merged_data_clean = merged_data.dropna()
# 目的関数
def objective(params):
a, p_a, b, p_b, c, p_c = params
mixed_close = (merged_data_clean['Cacao Close'] * a) ** p_a * \
(merged_data_clean['Copper Close'] * b) ** p_b - \
(merged_data_clean['Sugar Close'] * c) ** p_c
corr, _ = pearsonr(mixed_close, merged_data_clean['Nikkei Close USD'])
return -corr
# 初期係数と冪乗、最適化の実行、結果の表示
initial_params = [1, 1, 1, 1, 1, 1] # 係数と冪乗の初期値
result = minimize(objective, initial_params, method='BFGS')
print(f"Optimized Coefficients and Powers: {result.x}")
print(f"Maximum Correlation: {-result.fun}")