この記事で分かること
- 証券口座へのログイン&資産状況取得を自動化できる
- Googleスプレッドシートとの連携を自動化できる
- 資産状況を自動でLINE通知できる
もくじ
Pythonで株価取得を自動化したサンプルコード【コピペでOK】
先に結論から。
自動株価取得のサンプルコードは以下のとおりです。
# 日時を取得 import datetime time = datetime.datetime.now() time = time.strftime('%Y.%m.%d') # スプレッドシート連携 import gspread import json from oauth2client.service_account import ServiceAccountCredentials scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive'] credentials = ServiceAccountCredentials.from_json_keyfile_name('ダウンロードしたjsonファイルのパス', scope) gc = gspread.authorize(credentials) SPREADSHEET_KEY = '共有したスプレッドシートキー' worksheet = gc.open_by_key(SPREADSHEET_KEY).worksheet('シート名') # 書込行を取得 line = worksheet.acell('Q2').value # Chrome起動 from selenium import webdriver from time import sleep from selenium.webdriver.chrome.options import Options option = Options() option.add_argument('--headless') browser=webdriver.Chrome(options=option) # まずはSBI証券 url="https://site2.sbisec.co.jp/ETGate/" browser.get(url) sleep(10) try: # 「ユーザID」入力 elem_user_id=browser.find_element_by_name("user_id") elem_user_id.send_keys("ユーザ名") # 「パスワード」入力 elem_user_password=browser.find_element_by_name("user_password") elem_user_password.send_keys("パスワード") # 「ログイン」ボタンクリック elem_ACT_login=browser.find_element_by_name("ACT_login") elem_ACT_login.click() sleep(5) # 口座管理に遷移 browser.find_element_by_xpath("/html/body/div[1]/div[2]/div/ul/li[3]/a").click() # 口座(外貨建)に遷移 browser.find_element_by_xpath("/html/body/div[1]/div[3]/div/div/ul/li[2]/div").click() # ドル円を取得 doller_yen_market = float(browser.find_element_by_xpath("/html/body/div[1]/table[2]/tbody/tr/td[1]/table/tbody/tr/td[2]/table[2]/tbody/tr[1]/td[2]/table[5]/tbody/tr/td[1]/table[1]/tbody/tr[2]/td[2]").text.replace(',','')) # SBI_総額($)を取得 sbi_doller_asset = float(browser.find_element_by_xpath("/html/body/div[1]/table[2]/tbody/tr/td[1]/table/tbody/tr/td[2]/table[2]/tbody/tr[1]/td[2]/table[5]/tbody/tr/td[1]/table[2]/tbody/tr[2]/td[3]/table/tbody/tr[1]/td[2]/b").text.replace(',','')) # 円建ての資産総額を取得 sbi_asset = float(browser.find_element_by_xpath("/html/body/div[1]/table[2]/tbody/tr/td[1]/table/tbody/tr/td[2]/table[2]/tbody/tr[1]/td[2]/table[5]/tbody/tr/td[1]/table[2]/tbody/tr[2]/td[3]/table/tbody/tr[2]/td[2]/b").text.replace(',','')) # 円建ての資産損益を取得 sbi_gain = float(browser.find_element_by_xpath("/html/body/div[1]/table[2]/tbody/tr/td[1]/table/tbody/tr/td[2]/table[2]/tbody/tr[1]/td[2]/table[5]/tbody/tr/td[1]/table[3]/tbody/tr[3]/td[3]/span").text.replace(',','')) #VTI保有数量 vti_amount = float(browser.find_element_by_xpath("/html/body/div[1]/table[2]/tbody/tr/td[1]/table/tbody/tr/td[2]/table[2]/tbody/tr[1]/td[2]/table[5]/tbody/tr/td[3]/table[4]/tbody/tr[3]/td[1]").text.replace(',','')) #VTI取得単価 vti_acquisition_price = float(browser.find_element_by_xpath("/html/body/div[1]/table[2]/tbody/tr/td[1]/table/tbody/tr/td[2]/table[2]/tbody/tr[1]/td[2]/table[5]/tbody/tr/td[3]/table[4]/tbody/tr[3]/td[2]").text.replace(',','')) #VTI現在値 vti_present_value = float(browser.find_element_by_xpath("/html/body/div[1]/table[2]/tbody/tr/td[1]/table/tbody/tr/td[2]/table[2]/tbody/tr[1]/td[2]/table[5]/tbody/tr/td[3]/table[4]/tbody/tr[3]/td[3]").text.replace(',','')) #買付余力取得 browser.find_element_by_xpath("/html/body/div[1]/table[2]/tbody/tr/td[1]/table/tbody/tr/td[2]/map/area[3]").click() purchase_capacity = float(browser.find_element_by_xpath("/html/body/div[1]/table[2]/tbody/tr/td[1]/table/tbody/tr/td[2]/table[2]/tbody/tr[1]/td[2]/div/form/table[2]/tbody/tr/td/table/tbody/tr[9]/td[2]").text.replace(',','')) except : line=int(line) yline=line-1 yline=str(yline) vti_amount = worksheet.acell("B"+yline).value vti_acquisition_price = worksheet.acell("C"+yline).value vti_present_value = worksheet.acell("D"+yline).value doller_yen_market = worksheet.acell("F"+yline).value sbi_doller_asset = worksheet.acell("G"+yline).value sbi_asset = worksheet.acell("H"+yline).value sbi_gain = worksheet.acell("I"+yline).value sbi_asset = sbi_asset.replace("¥","") sbi_asset = sbi_asset.replace(",","") sbi_gain = sbi_gain.replace("¥","") sbi_gain = sbi_gain.replace(",","") sbi_asset = int(sbi_asset) sbi_gain = int(sbi_gain) purchase_capacity = 1000 print(time + " SBI証券取得不可。前日分を反映します。") line=str(line) # ここから楽天証券 url="https://www.rakuten-sec.co.jp/" browser.get(url) sleep(10) try: # 「ユーザID」入力 elem_user_id=browser.find_element_by_name("loginid") elem_user_id.send_keys("ユーザ名") # 「パスワード」入力 elem_user_password=browser.find_element_by_name("passwd") elem_user_password.send_keys("パスワード") # 「ログイン」ボタンクリック elem_ACT_login=browser.find_element_by_class_name("s3-form-login__btn") elem_ACT_login.click() sleep(5) # 楽天証券の総額を取得 rak_asset = browser.find_element_by_xpath("/html/body/div[2]/div/div[1]/form[2]/table/tbody/tr[1]/td/span/div/table/tbody/tr[2]/td[1]/div[1]/table/thead/tr[2]/td[2]/nobr/span/span[1]/nobr").text.replace(',','') rak_asset = rak_asset.replace(" 円","") # 楽天証券の損益を取得 rak_gain = browser.find_element_by_xpath("/html/body/div[2]/div/div[1]/form[2]/table/tbody/tr[1]/td/span/div/table/tbody/tr[2]/td[1]/div[1]/table/thead/tr[2]/td[3]/nobr/span/span[1]/nobr/span").text.replace(',','') rak_gain = rak_gain.replace(" 円","") rak_gain = rak_gain.replace("+","") except : line=int(line) yline=line-1 yline=str(yline) rak_asset = worksheet.acell("J"+yline).value rak_gain = worksheet.acell("K"+yline).value rak_asset = rak_asset.replace("¥","") rak_asset = rak_asset.replace(",","") rak_gain = rak_gain.replace("¥","") rak_gain = rak_gain.replace(",","") rak_asset=int(rak_asset) rak_gain=int(rak_gain) print(time + " 楽天証券取得不可。前日分を反映します。") line=str(line) # ここからDC url="https://life.smtb.jp/Lifeguide/faces/xhtml/biz/F69914010/G699140010.xhtml" browser.get(url) sleep(10) try : # 「ユーザID」入力 elem_user_id=browser.find_element_by_name("f_personal:kojinId") elem_user_id.send_keys("個人ID") # 「パスワード」入力 elem_user_password=browser.find_element_by_name("f_personal:kojinPw") elem_user_password.send_keys("パスワード") # 「ログイン」ボタンクリック elem_ACT_login=browser.find_element_by_name("f_personal:j_idt40") elem_ACT_login.click() sleep(10) # DC総額を取得 dc_asset = browser.find_element_by_xpath("/html/body/div[4]/div[1]/div/div/div/form[1]/div/div[2]/div/div[1]/div/table/tbody/tr[1]/td[2]").text.replace(',','') dc_asset = dc_asset.replace("円","") # DC損益を取得 dc_gain = browser.find_element_by_xpath("/html/body/div[4]/div[1]/div/div/div/form[1]/div/div[2]/div/div[1]/div/table/tbody/tr[2]/td[2]").text.replace(',','') dc_gain = dc_gain.replace("円","") except : line=int(line) yline=line-1 yline=str(yline) dc_asset = worksheet.acell("L"+yline).value dc_gain = worksheet.acell("M"+yline).value dc_asset = dc_asset.replace("¥","") dc_asset = dc_asset.replace(",","") dc_gain = dc_gain.replace("¥","") dc_gain = dc_gain.replace(",","") dc_asset=int(dc_asset) dc_gain=int(dc_gain) print(time + " DC取得不可。前日分を反映します。") line=str(line) browser.quit() # スプレッドシートへ転記 # 日付を入力 worksheet.update_acell("A"+line,time) # VTI保有数量を入力 worksheet.update_acell("B"+line,vti_amount) # VTI取得単価を入力 worksheet.update_acell("C"+line,vti_acquisition_price) # VTI現在値を入力 worksheet.update_acell("D"+line,vti_present_value) # ドル円を入力 worksheet.update_acell("F"+line,doller_yen_market) # SBI証券の総額($)を入力 worksheet.update_acell("G"+line,sbi_doller_asset) # SBI証券の総額(円)を入力 worksheet.update_acell("H"+line,sbi_asset) # SBI証券の損益を入力 worksheet.update_acell("I"+line,sbi_gain) # 楽天証券の総額を入力 worksheet.update_acell("J"+line,rak_asset) # 楽天証券の損益を入力 worksheet.update_acell("K"+line,rak_gain) # DCの総額を入力 worksheet.update_acell("L"+line,dc_asset) # DC証券の損益を入力 worksheet.update_acell("M"+line,dc_gain) # 前日比を取得 change_rate = worksheet.acell("E"+line).value change_rate = float(change_rate.replace("%","")) # LINE連携 import requests TOKEN = '自分のトークン' api_url = 'https://notify-api.line.me/api/notify' # 金額取得 sbi_asset = worksheet.acell("H"+line).value sbi_gain = worksheet.acell("I"+line).value rak_asset = worksheet.acell("J"+line).value rak_gain = worksheet.acell("K"+line).value dc_asset = worksheet.acell("L"+line).value dc_gain = worksheet.acell("M"+line).value total_asset = worksheet.acell("N"+line).value total_gain = worksheet.acell("O"+line).value # メッセージを作成 send_contents = "\n"+"SBI総額:"+str(sbi_asset)+"\n"+"SBI損益:"+str(sbi_gain)+"\n"+"楽天総額:"+str(rak_asset)+"\n"+"楽天損益:"+str(rak_gain)+"\n"+"DC総額:"+str(dc_asset)+"\n"+"DC損益:"+str(dc_gain)+"\n"+"総額:"+str(total_asset)+"\n"+"損益:"+str(total_gain) TOKEN_dic = {'Authorization': 'Bearer' + ' ' + TOKEN} send_dic = {'message': send_contents} #LINE送信 requests.post(api_url, headers=TOKEN_dic, data=send_dic) # おまけ # VTIが前日比-2%以下ならLINE通知 if change_rate <= -2 : send_contents = "\n"+"VTI "+str(change_rate)+"%だよ" TOKEN_dic = {'Authorization': 'Bearer' + ' ' + TOKEN} send_dic = {'message': send_contents} requests.post(api_url, headers=TOKEN_dic, data=send_dic) # 買付余力が$1,000切ったらLINE通知 if purchase_capacity < 1000 : send_contents = "\n"+"買付余力が$1,000切ったよ" TOKEN_dic = {'Authorization': 'Bearer' + ' ' + TOKEN} send_dic = {'message': send_contents} requests.post(api_url, headers=TOKEN_dic, data=send_dic)
これを任意のフォルダにPythonファイル(〜.py)として保存します。
Pythonで自動化したことの概要【完成イメージ】
今回つくったプログラムで自動化したことは大きく3つ。
- 証券口座から資産状況を取得
- 取得した資産状況をスプレッドシートへ転記
- 結果をLINE通知
① : 証券口座から資産状況を取得
コードの26行目〜158行目までがそうですね。
僕の場合、以下3つの口座で運用しています。
- SBI証券・・米国ETF(VTI)積立
- 楽天証券・・つみたてNISA
- 三井住友信託銀行・・企業型DC
取得してる情報はそれぞれこんな感じです。
SBI証券
- VTI保有数量
- VTI取得単価
- VTI現在値
- ドル円相場
- 保有資産評価額
- 資産損益
楽天証券
- 保有資産評価額
- 資産損益
三井住友信託銀行
- 保有資産評価額
- 資産損益
- ログインする
- 値が表示されたページにいく
- 値を変数に格納する
といった流れはどの口座も共通です。
なお、try-exceptで書いてますが、メンテナンス時間帯などでログインできないこともあるので、もし値の取得で何らかのエラーがあった場合は、スプレッドシート上の前日値をとってくるようになってます。
② : 取得した資産状況をスプレッドシートへ転記
コードの6〜16行目、161〜189行目がそうです。
①で取得した情報をGoogleスプレッドシートに記録していきます。
事前にGoogle Cloud Platformに登録してアカウントキーを取得する必要がありますが、『Python スプレッドシート』でググれば大丈夫です。
日々記録していくことで、後々データ分析とかにも応用できそうですね。
最終行に追記していってほしいので、セルQ2に書き込み行を求める関数が入っていて、lineという変数に代入しています。(16行目)
③ : 結果をLINE通知
192行目〜211行目ですね。
スプレッドシートに入力された値を取得しつつ、「send_contents」でメッセージを指定する感じです。
PythonプログラムからLINE通知させるには、LINE NotifyというAPIに登録しトークンを発行する必要がありますが、それもググればすぐ分かります。
初めてプログラムを動かして無事LINEが届くとちょっと感動です。
おまけ : if分も使ってみる
213行目〜226行目ですね。
初心者ながら、なんとなくif分くらいは使ってみようと思って条件を入れました。
①:VTIが前日比-2%以下ならLINE通知
スプレッドシートのE列でVTIの前日比を計算しています。
基本的には毎月定額積立ですが、前日比-2%以下になったら買い増しするかも・・、という遊び感覚で入れた部分です。
②:買付余力が$1,000切ったらLINE通知
手数料を考慮した関係で、住信SBIネット銀行でドル転してSBI証券に資金移動するというめんどくさい方式をとってます。
そのせいで、うっかりしてると買付余力不足になるので$1,000以下になったら教えてもらうのが目的です。
Pythonファイルを定期実行させる
① : cronの設定をする
プログラムはできましたが、これだけでは手起動しないと動いてくれません。
そこで、macのcron(クーロン)という機能を使って定期実行してもらうよう設定します。
(1)ターミナルを起動して「echo $PATH」というコマンドを入力し、結果をコピーしておきましょう。
(base) 2007th@2007thnoAir ~ % echo $PATH /Users/2007th/miniforge3/bin:/Users/2007th/miniforge3/condabin:/Library/Frameworks/Python.framework/Versions/3.9/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin:/opt/homebrew/bin/ (base) 2007th@2007thnoAir ~ %
(2)次に「crontab -e」と実行して「i」(インサートモード)を入力するとcronが編集可能になります。
(3)(1)でコピーしたPATH情報をcronに貼り付けます。
PATH=/Users/2007th/miniforge3/bin:/Users/2007th/miniforge3/condabin:/Library/Frameworks/Python.framework/Versions/3.9/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin:/opt/homebrew/bin/
(4)その下に、プログラムを実行したいタイミングとファイルのパスを記述しましょう。
# (分) (時) (日) (月) (曜日) (実行するコマンド) 30 0 * * * python /Users/2007th/Python_Item/python_cron/Portfolio.py >> /Users/2007th/Python_Item/python_cron/cron.log 2>&1
上記は「毎日0:30に/Users/2007th/Python_Item/python_cron/Portfolio.pyを実行する」という設定です。
また、>>以降で「/Users/2007th/Python_Item/python_cron/cron.logにログを出力する」という指定をしています。
(5)cronの編集が終わったら、「esc」キー→「:wq」でcron設定を保存できます。(保存しない場合は「:q」)
② : スリープの設定をする
これで毎日0:30にcronがPythonファイルを実行してくれますが、PCがスリープ状態だと動いてくれません。
そのため、決まった時刻にスリープ解除が入るように設定する必要があります。
macの場合、「システム環境設定」→「バッテリー」→「スケジュール」でスリープ&スリープ解除の時間を指定すれば大丈夫です。
Python自動化にオススメの参考書籍3選
①:シゴトがはかどる Python自動処理の教科書
今回、Pythonでプログラムを作るうえで参考にしたのが『シゴトがはかどる Python自動処理の教科書』です。
- メール
- SNS
- ブラウザ操作
- Excel
などなど、日常のあらゆるルーティンワークをPythonで自動化したいという人にオススメします。
本書をざっと眺めてみるだけでも、「もしかしてアレって自動化できるんじゃね??」という新たな気づきにつながるはず。
②:Python1年生 プログラミングのしくみ
プログラミング完全初心者の方には本書がオススメです。
初心者がとっつきづらいと感じる部分を、”ゆる分かりやすく”ヤギ博士が教えてくれます。
これ1冊で、Pythonの基礎の基礎は抑えられるはずです。
③:Python2年生 スクレイピングのしくみ
Python2年生では、WEBスクレイピングを学びます。
WEBスクレイピングとは、WEB上にあるさまざまな情報から必要な情報を抽出する技術です。
株価情報の取得なども、WEBスクレイピングのひとつと言えます。
まとめ:ルーチンワークの自動化で可処分時間を増やそう
今回は、Pythonで資産状況照会を自動化する方法をお伝えしました。
このブログは本の要約がメインですが、日常の単純作業を自動化して可処分時間を増やせると、読書により時間を使えますね。
エンジニアでなくてもプログラミングの知識は生活の役に立ちます。
興味のある方は、サンプルコードを使ってみてください。
今回は以上です。