私のauカブコム証券のkabuステーションで自動売買プログラムの説明(9) 現在の株価が損切り値に達していないかを監視(websocket.py) その2

スポンサーリンク

websocket.pyのソースコード

import sys
import websocket
import _thread
import pprint
import json
import settings
import rsi1570i_cancelorder
import datetime
import urllib.request
import board
import time

def on_message(ws, message):
    printWithTime('--- RECV MSG. --- ')
    content = json.loads(message)
    curPrice = content["CurrentPrice"]

    if(curPrice >= settings.orderPrice + settings.lossCutMargin):
        # キャンセルからの損切り注文
        cancelorder.cancelorder()
        ws.close()

def on_error(ws, error):
    if len(error) != 0:
        printWithTime('--- ERROR --- ')
        print(error)

def on_close(ws):
    printWithTime('--- DISCONNECTED --- ')


def on_open(ws):
    printWithTime('--- CONNECTED --- ')
    def run():
        while(True):

            # 指定時間sleep
            time.sleep(settings.intervalCloseCheck)

            url = 'http://localhost:' + settings.port + '/kabusapi/orders'
            params = { 'product': 0, }
            req = urllib.request.Request('{}?{}'.format(url, urllib.parse.urlencode(params)), method='GET')
            req.add_header('Content-Type', 'application/json')
            req.add_header('X-API-KEY', settings.token)

            try:
                with urllib.request.urlopen(req) as res:
                    content = json.loads(res.read())

                    # 注文情報を取得
                    lastOrder = content[len(content)-1]
                            
                    # 全約定の場合(売りが完了している場合)
                    if lastOrder['State'] == 5:

                        # まずはwebsoketを停止
                        printWithTime('closing...')
                        ws.close()
                        break
                    
                    # 手仕舞い時刻
                    nowtime = datetime.datetime.now()
                    if nowtime > settings.forceCloseTime:
                        # キャンセルからの損切り注文
                        rsi1570i_cancelorder.cancelorder()
                        ws.close()
                        break

            except urllib.error.HTTPError as e:
                print(e)
                content = json.loads(e.read())
                pprint.pprint(content)
            except Exception as e:
                print(e)



    _thread.start_new_thread(run, ())

def websocketA1():
    printWithTime('--- websocketA1 Start--- ')
    url = 'ws://localhost:' + settings.port + '/kabusapi/websocket'
    # websocket.enableTrace(True)
    ws = websocket.WebSocketApp(url,
                            on_message = on_message,
                            on_error = on_error,
                            on_close = on_close)
    ws.on_open = on_open
    ws.run_forever()

    printWithTime('--- websocketA1 End --- ')



def printWithTime(message):
    print(str(datetime.datetime.now()) + ' ' + message)

if __name__ == "__main__":
    import sys
    websocketA1()

前回説明した、kabuステーションのwebsoketのサンプルコードに、このトレードプログラムでやりたいことを当てはめたのが、上記のコードです。

80行目 def websocketA1():すべての入り口

kabuステーションのサンプルは、それだけで実行するモジュールなので、ソースコードの地の部分(関数外)に最初に動く処理が書かれていましたが、このモジュールは前の処理から数珠繋ぎ方式で呼ばれるため、プログラムの入り口を関数にしています。

以前は、1日何回もエントリしていたため、「ws.run_forever()」の次に、次のエントリへつなげる処理を書いていたのですが、今は最大1日1回しかエントリしていないため、この後は何もしていません。WebSoketが閉じると、プログラム自体が終了します。

逆に言えば、1日何回もエントリしたい人は、「ws.run_forever()」の次に、「board.board()」を呼びだし、最初に戻る処理を入れてください。

32行目 def on_open(ws):WebSoketで損切監視開始

このWebSoketのモジュールは、外側のWebSocket自体ではkabuステーションのサーバから、株価のリアルタイム通知を受けて損切り価格に達していないかの監視をしています。

同時にdef run(): 無限ループで10秒ことに利食い決済したかも監視

しかし、WebSocketが開始した「def on_open(ws):」の中で、「def run():」関数を定義し、「thread.start_new_thread(run, ())」で別スレッドでその関数を呼ぶことによって、同時に以下の条件を監視し、条件に合う場合はWebSocketを終了させる処理をしています。

  • 以前発注した利食い注文が決済されていないか
  • 予め設定してある手仕舞い時刻を過ぎていないか

kabuステーションのサンプルプログラムでは、ここで無限ループでコマンド入力を監視し、コマンド入力があればWebSocktをcloseする処理を入れていました

以前発注した利食い注文が決済されていないか

エントリ注文の約定価格確認と同じ方法で、利食い注文の注文情報を取得し、今度は注文ステータス(State)が約定済み(5)でないかを確認しています。

私のauカブコム証券のkabuステーションで自動売買プログラムの説明(5) エントリ注文が約定した価格を取得 (order_info.py)
order_info.pyのソースコードimport urllib.request import json import pprint import board2 import settings def orders...

約定済みの場合は利益確定済みのため、損切り処理もそれ以上の処理も必要ないため処理を終了します。

手仕舞い時刻に到達していないか

このトレードプログラムでは、損切り価格にも約定価格にも到達しない場合であっても、前場の終了の10分前の11:20には、成行で決済して手仕舞いするようにしています。

したがって、現在時刻が11:20を越えた時点で、数珠繋ぎ方式で利食い指値注文をキャンセルし、その後で成行決済注文を発注しています。

13行目 def on_message(ws, message):株価が通知されるたびに損切りチェック

kabuステーションのPUSH API(WebSoket)により、株価に変化があるたびにリアルタイムで「def on_message(ws, message):」が呼ばれます。

通知された情報から、現在の株価(CurrentPrice)を取り出し、グローバル変数格納モジュール(setting.py)から、エントリ約定価格と損切り価格幅を取り出し、計算して比較します。

現在の価格が損切り価格を超えている場合は、即座に数珠繋ぎ方式により、

利食い指値注文キャンセル→損切り成行注文

の順で呼び出します。

エントリ注文の後、利食い指値注文を発注せずに、このタイミングで株価をチェックし

・利食い価格に達していれば利食い成行発注
・損切り価格に達していれば損切り成行発注

とすれば、全体のプログラムが極めてシンプルになります。
(私は(今のところは)利食いを確実に指値で行いたいので上記の方式にはしていません)

コメント