Python seleniumと楽天RSSで簡単な日本株デイトレボットを作る①

デイトレ、楽しいですよね。

ただ、平日の9:00~15:00という時間制限のある中で、日中働いている人はなかなか手が出せないと思います。

なのでボットを自作して勝手にやってもらおう。そんな感じの記事です。

・ロードマップ

まず必要なもの

Pythonの実行環境、楽天証券の口座(楽天RSSを使うため)、ブラウザからアクセスできる証券会社の口座が必要です。

ファイル構成のイメージ

自動売買ボット

|--- メイン.py
|--- 1分足データ取得、保存.py
|--- ブラウザーコントローラー.py
|--- LINE通知
|--- テクニカル指標計算.py
|--- 1分足データ.csv

1つのファイルにまとめるとかなり長くなってしまうので、複数のファイルで処理ごとに分割して、そこから関数としてひっぱってメインのファイルにまとめていきます。

①1分足データの取得、保存

楽天RSSからPythonを使って1分ごとにデータを取得、csvファイル形式で保存します。今回は証券コード9984 ソフトバンクの1分足データをリアルタイムで取得して保存します。

②ブラウザーコントローラー

ブラウザーをごりごりに動かして買い注文を出したり、売り注文を出したりする部分を作ります。今回は普段自分が使っている松井証券のホームページをPythonのSeleniumモジュールで操作します。他の証券会社の口座でも動かし方は基本的に同じだと思うので、応用が利くと思います。ここが一番めんどくさいです。

③LINE通知ボット

ただ動かして注文を勝手に出すだけだと証券会社にログインするまで結果がわからないので、可視化のため注文毎にLINEで通知します。

④テクニカル指標の計算

①で保存したcsv形式の1分足データを読み込んで、テクニカル指標を計算します。計算結果を返してメインの部分の条件文のためのトリガーにします。

メインの部分のイメージ

画像1

こんな感じの条件文の処理を書いていって、1分毎にループします。なんか色々はみだしてるけどゆるして。

それでは①から順番に作っていきましょう。

①1分足データの取得、保存

今回はテクニカル指標を使って買いサインと売りサインを定義、条件文に従って注文を出すということにしているので、テクニカル指標算出の大本になるリアルタイムの現在価格のデータを一定の間隔で保存して、疑似的な株価チャートを作る必要があります。

幸いなことにPythonには有志の方が作成してくれたモジュールがあるのでそちらを使用していきます。

楽天マーケットスピードと、

楽天RSSをダウンロードして、

マーケットスピードにログイン、RSSも起動します。(楽天証券の口座が必要です。)

ちなみに楽天証券に口座を作っておくと日経テレコンが読めたりするのでおすすめです。

スクリーンショット (25)

スクリーンショット (27)

コマンドプロンプトを開いて、

pip install rakuten_rss

として楽天RSSモジュールをダウンロードします。

RSS接続中となっている状態では裏でDDE通信というものが行われていて、この楽天RSSモジュールはそのDDE通信にアクセスするモジュールのようです。なのでRSSはプログラムの実行中は常に接続状態である必要があります。

楽天RSSモジュールの使い方は以下の通り。

from rakuten_rss import rss
 
rss('引数1','引数2')

引数1には文字列で『4ケタの証券コード+ .T』ドットTは東証のTです。

引数2は以下の関数表を参考にしてください。

今回は『証券コード9984 ソフトバンク』の『現在値』を一定時間ごとに取得していきましょう。なので、

スクリーンショット (28)

こんな感じの引数を渡すと、戻り値で6845.00という文字列が返ってきました。

証券コードを変えたり、上の関数表を参考にして引数2をかえてやるといろんなデータがとれるので試しにやってみて下さい。

使いたかがだいぶわかってきたところで、pythonファイルを作っていきましょう。

リアルタイムの現在値データを取得して、csvファイルに保存するプログラムを作ります。

from rakuten_rss import rss
import datetime
import csv
import time
 
#データの取得、csvファイルへの保存

datas = []
code = '9984'
stock_code = code +'.T'

data_cols = ['現在値','出来高','売買代金','出来高加重平均']
 
datas.append(datetime.datetime.now().strftime('%Y/%m/%d %H:%M'))
 
for i in data_cols:
  datas.append(rss(stock_code,i))
  
for num,col in zip(range(len(data_cols)),data_cols):
  while datas[num +1] == 0:
    time.sleep(1)
    datas[num +1] = rss(stock_code,col)
    if datas[num +1] != 0:
      break
    else:
      pass
 
with open(str(code)+'_data.csv','a',newline='') as f:
  csv.writer(f,delimiter=',').writerow(datas)

datas = [ ] として空のリストを作成します。この空のリストにデータを追加していって、完成したリストをあとでcsvファイルに追記します。

code = '9984' stock_code = code +'.T'として楽天RSSモジュールに渡す引数1を指定します。最後に保存するファイル名でもこの変数を参照するので、.Tが入らないcode と楽天RSSモジュールの引数として渡す.T付きのやつで分けています。.Tのほうをそのまま使うと、ファイル名が 9984.T_data.csvになってカンマが複数個ファイル名に入ってしまうからです。

data_cols = ['現在値','出来高...] として、楽天RSSモジュールに渡す引数2を指定します。現在値だけでなく、いろんなデータも一緒に取得してcsvに保存してみます。

datas.append( ) としてカッコ内を空リスト datas に追加します。最初に追加するデータは日付データです。datetime.datetime.now()で現在の時刻を取得、そのままメソッドチェーンで.strftime( )とすることで、datetime型で取得した現在時刻を文字列型に変換します。カッコ内 '%Y/%m/%d %H:%M' は文字列フォーマットの指定です。Year/month/day Hour:Minute で変換するので、2021/7/30 12:34みたいなかたちになります。

for i in data_cols: とすることで、変数 i にさっき指定したdata_cols内の文字列をひとつづつ参照するようにします。

forループ内 datas.append(rss(stock_code,i)) とすることで、変数 i にdata_cols内の文字列がひとつづつ参照され、rss('9984.T','現在値')、rss('9984.T','出来高')、rss('9984.T',....のように各データを楽天RSSモジュールで順番に取得して、おなじリストに追加していきます。

このRSSのデータ取得は失敗することがよくあって、その次の処理はデータがうまく取れなかった時の取り直しです。

for num,cols in zip(range(len(data_cols),data_cols):  としています。zip( )内から見ていきましょう。pythonの組み込み関数zipは複数のリスト型データを同時に参照します。zip(リスト1,リスト2)のように指定します。

リスト1はrange(len(data_cols))となっているので、data_colsと同じ長さの数字のリストです。(厳密にはrange関数なのでリスト型ではありません。ですが働きは同じです。)data_colsは取りたいデータのリストでした。中身は ['現在値'、'出来高'、'売買代金'、'出来高加重平均'] でしたね。なので、range(len( ))で変換されて、リスト1は[0,1,2,3,]ですね。

リスト2はdata_colsそのものです。このリスト1とリスト2のデータを上から順番にひとつづつ参照して、変数num と変数colsに挿入してforループを回していきます。なので、ループ1回目ではリスト1からnum=0、リスト2からcols='現在値' が渡されます。2回目はnum=1 col='出来高'になりますね。

この一個上のforループの時データの取得にミスがあると、datasの追加したデータが『0』になっているので、データが『0』になっている時データを再取得する処理を書いていきます。

while datas[num +1] == 0: とすることで、先ほど作成したリストdatasの変数num +1番目を参照します。リストの1番目は現在時刻のデータなので、楽天RSSモジュールで取得に失敗して数値が『0』になる可能性がある箇所はdatasリスト内の2番目以降です。なのでnum +1で1番目の時刻のデータをスキップしています。num +1番目のデータが『0』すなわち取得に失敗していたとき while True となり、その下の処理に進みます。

time.sleep(1) として、1秒のディレイをかけています。

datas[num +1] = rss(stock_code,cols) として、num +1番目のデータを再取得します。変数num と変数cols にはzipで指定したリスト1,とリスト2が入っていましたね。

if datas[num +1] != 0: とすることで、データが『0』でないときにその下の処理が呼ばれます。breakなのでwhileループが一旦終了して、for ループが2番目に進むしくみです。

else: データがまだ『0』のときその下の処理が呼ばれます。passなのでwhileループの最初に戻ります。なので、またデータが『0』なら再取得です。

forループを全て抜けると次の処理に進みます。全て抜けたときには全部のデータがちゃんと揃っている状態になっていると思います。

スクリーンショット (87)_LI

with open(str(code) +'_data.csv', 'a', newline='') as f:として、証券コード+_data.csvというファイルを追記モード('a')で開きます。指定した名前のファイルがなければ現在の作業ディレクトリに勝手に作成されます。

csv.writer(f, delimiter=',').writerow(datas)として、さっき開いたcsvファイルに取得したリストdatasを書き込みます。

スクリーンショット (30)

こんな感じのcsvファイルができました。

基本的な部分はこれで出来ましたね。少しだけファイルをいじって関数の形にします。

def add_datas(code):
  
  now = datetime.datetime.now()
  
  zenba_start = datetime.datetime(year=now.year,
                                  month=now.month,
                                  day=now.day,
                                  hour=9,
                                  minute=0)
                                  
  zenba_end = datetime.datetime(year=now.year,
                                month=now.month,
                                day=now.day,
                                hour=11,
                                minute=31)
                                
  goba_start = datetime.datetime(year=now.year,
                                 month=now.month,
                                 day=now.day,
                                 hour=12,
                                 minute=30)
                                 
  goba_end = datetime.datetime(year=now.year,
                               month=now.month,
                               day=now.day,
                               hour=15,
                               minute=1)
                               
  if zenba_start <= now <= zenba_end or goba_start <= now <= goba_end:
   
   #データの取得、csvファイルへの保存
    code = code
   
  else:
   pass

def add_1min_datas( ): とすることで、関数の形にします。引数にcodeも指定して、code='9984'だった部分をcode=codeとすることで引数のcodeが参照され、他の会社のデータも取れるようになりました。

他のファイルからimport文でとりこめば、add_datas(コード)で今やってきた処理が1行で実行されます。

また、前場と後場の時間を定義して、if文でその時間内にしか動作しないようにすることで、取引が行われていない時間帯にどんどんデータを追記してしまう問題を回避しています。

いま書いたコードは好きなadd_onemin_datas.pyみたいな感じで保存しましょう。これで、ほかの.pyファイルに

from add_onemin_datas import add_datas

と一文書けば使えるようになりますね。

パート1はここでお終いです。次はパート2のブラウザーコントローラの作成にチャレンジしてみて下さいね。

現在のファイル構成!

自動売買ボット

|--- メイン.py(空のpyファイル)
|--- add_onemin_datas.py 
|        |--- add_datas(今回作った関数)
|
|--- 9984_data.csv(1分足データファイル)

この記事が気に入ったらサポートをしてみませんか?