【Python】pubnub と WebSocket で更にリアルタイムで情報を取得する
おはようございます。
えーと、SQLiteにデータ登録なんかしようと思ってたんですが、
どう実装すればいいか分からず別の方法で実装した、pubnub で ティッカー情報が更新される度に画面の情報も更新する方法が分かりましたのでやってみました。
プログラムは前回のものを流用します。
【Python】bitflyer の API を使って注文を送信する
スポンサーリンク
画面の修正
Main.html
ティッカー情報の配信を開始するボタンと停止するボタンを追加しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <div style="clear:both; padding-top:10px;"> <div class="entry_title"> <div class="pull_left">ティッカー情報</div> <div class="pull_right"> <input type="button"value="更新開始"onclick="startTicker();" /> <input type="button"value="更新停止"onclick="stopTicker();" /> </div> </div> <table id="tickerTable"> <tr class="header"> <th style="width:5%">種別</th> <th style="width:10%">時刻</th> <th style="width:5%">ID</th> <th style="width:5%">売値</th> <th style="width:5%">買値</th> <th style="width:10%">売り数量</th> <th style="width:10%">買い数量</th> <th style="width:10%">売り注文総数</th> <th style="width:10%">買い注文総数</th> <th style="width:10%">最終取引価格</th> <th style="width:10%">出来高</th> <th style="width:10%">価格単位出来高</th> </tr> </table> </div> |
プログラムの修正
APIの修正
BfApi.py
インポートするクラス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | importhashlib importhmac importjson importlogging importrequests importtime importurllib fromcommon.Constants importConstants frompubnub.callbacks importSubscribeCallback frompubnub.enums importPNStatusCategory frompubnub.pnconfiguration importPNConfiguration frompubnub.pubnub importSubscribeListener frompubnub.pubnub_tornado importPubNubTornado |
追加するメソッド、内部クラス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | defstart_pub_nub_ticker(self,cl,channels): """ ティッカー情報の配信を開始 :param cl: web_socket client :param channels: 配信するチャンネル :return: """ self.listener=self.MySubscriberCallback(cl) self.pub_nub.add_listener(self.listener) self.pub_nub.subscribe().channels(channels).execute() defstop_pub_nub_ticker(self,channels): """ ティッカー情報の配信を停止 :param channels: 停止するチャンネル :return: """ self.pub_nub.unsubscribe().channels(channels).execute() self.pub_nub.remove_listener(self.listener) classMySubscriberCallback(SubscribeCallback): """ Pubnub登録のコールバッククラス """ def__init__(self,clent): self.cl=clent defpresence(self,pubnub,presence): pass # handle incoming presence data defstatus(self,pubnub,status): ifstatus.category==PNStatusCategory.PNUnexpectedDisconnectCategory: pass # This event happens when radio / connectivity is lost elifstatus.category==PNStatusCategory.PNConnectedCategory: # Connect event. You can do stuff like publish, and know you'll get it. # Or just use the connected event to confirm you are subscribed for # UI / internal notifications, etc pass elifstatus.category==PNStatusCategory.PNReconnectedCategory: pass # Happens as part of our regular operation. This event happens when # radio / connectivity is lost, then regained. elifstatus.category==PNStatusCategory.PNDecryptionErrorCategory: pass # Handle message decryption error. Probably client configured to # encrypt messages and on live data feed it received plain text. defmessage(self,pubnub,message): """ 登録したチャンネルからメッセージを受信した際の処理 :param pubnub: :param message: :return: """ # WEBソケットを利用してクライアントに配信 forcinself.cl: c.write_message(message.message) |
メインクラスのグローバル変数を追加
BfTool.py
1 2 | cl=[] api_ticker=None |
WEBソケットの修正
BfTool.py
ひとまずは、既存のティッカー情報更新用メソッドはコメントアウトし、
新しい仕組みを追加しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | classSendWebSocket(WebSocketHandler): """ WEBソケット通信 1秒毎にティッカー情報を画面に配信します """ defopen(self): logging.info('SendWebSocket [open] IP :'+self.request.remote_ip) self.ioloop=tornado.ioloop.IOLoop.instance() # self.send_ticker() ifselfnotincl: cl.append(self) defon_message(self,message): logging.info("WebSocketHandler [on_message]") forclient incl: client.write_message(message) defon_close(self): logging.info("SendWebSocket [on_closed]") ifselfincl: cl.remove(self) defcheck_origin(self,origin): logging.info("SendWebSocket [check_origin]") returnTrue defsend_ticker(self): self.ioloop.add_timeout(time.time()+2,self.send_ticker) ifself.ws_connection: api=BfApi() data=api.call_pub_nub('lightning_ticker_FX_BTC_JPY') message=json.dumps(data) self.write_message(message) |
ティッカー情報配信の開始と停止メソッド追加
BfTool.py
画面から開始、停止ができるようにURLメソッドを追加しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | classStartTicker(RequestHandler): """ ティッカー情報の更新を開始 """ definitialize(self): logging.info("StartTicker [initialize]") defpost(self): logging.info("StartTicker [post]") globalapi_ticker api_ticker=BfApi() api_ticker.start_pub_nub_ticker(cl,['lightning_ticker_FX_BTC_JPY']) classStopTicker(RequestHandler): """ ティッカー情報の更新を停止 """ definitialize(self): logging.info("StopTicker [initialize]") defpost(self): logging.info("StopTicker [post]") globalapi_ticker ifapi_ticker: api_ticker.stop_pub_nub_ticker('lightning_ticker_FX_BTC_JPY') |
URLマッピングの追加
BfTool.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | app=tornado.web.Application([ (r"/",MainHandler), (r"/ws",SendWebSocket), (r"/balance",GetBalanceHandler), (r"/execution",GetExecutionHandler), (r"/childOrder",GetChildOrderHandler), (r"/sendOrder",SendChildOrderHandler), (r"/cancelOrder",CancelChildOrderHandler), (r"/startTicker",StartTicker), (r"/stopTicker",StopTicker) ], template_path=os.path.join(os.getcwd(),"templates"), static_path=os.path.join(os.getcwd(),"static"), js_path=os.path.join(os.getcwd(),"js"), ) |
画面処理の追加
script.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | /** * ティッカーの更新を開始 */ functionstartTicker(){ $.ajax({ url:"http://localhost:8080/startTicker", type:"POST", success:function(jsonResponse){ console.log(jsonResponse); }, error:function(){ } }); } /** * ティッカーの更新を停止 */ functionstopTicker(){ $.ajax({ url:"http://localhost:8080/stopTicker", type:"POST", success:function(jsonResponse){ console.log(jsonResponse); }, error:function(){ } }); } |
起動してみる
スクショじゃ分からないですが、すごい速さでティッカー情報が更新されていきます。
この速度では10件表示していてもすぐ流れて行ってしまうので、本来であれば最新のみ表示するとかで十分ですね。
あとは、自動取引のトリガーとすることが多いようです。
そのうち自動取引の条件なんかを画面で設定し、自動取引の開始・停止が出来るようにしたいですね。
ディスカッション
コメント一覧
まだ、コメントがありません