Bot

仮想通貨botの開発を本格的に始めてみる#10(2023/9/9)

2023年9月9日

前回の内容に引き続き、仮想通貨botの開発状況をまとめていきます。

前回までの取り組みでccxtライブラリを使った注文方法を一通りマスターしました。

具体的には、価格情報の取得・ティッカー情報の取得・売買の注文を出す・注文情報を確認する・注文をキャンセルすることができるようになっています。

基礎を押さえたところで、いよいよこの記事を参考に「bot作り」に移っていきます。

売買ロジックを考える

ロジックを考える前に、初心者が覚えておきたいことをまとめておきます。

  • 安定した自動売買には、シンプルなロジックが必要。
  • シンプルなロジックが例外エラーを減らす。
  • エントリー・手仕舞いの条件」を明確な数字で定義できるかどうかを考える。

今回実装するロジックは「赤三兵」を使います。

赤三兵」についてよく分からなかったため、早速調べていきます。

三兵とは、陽線が3本連続した時を買いシグナル、陰線が3本連続した時を売りシグナルとするという戦略です。

赤三兵~酒田五法~酒田五法ローソク足チャート

どの時点でシグナルが出ているのかということも重要ですが、今回はそこは割愛します。(一般的には、底値圏で出た赤三兵と高値圏で出た黒三兵に注目するのが良いとされます)

ローソク足(1分)の情報を取得する

まずは、ローソク足の情報を取得するためのコードを書いていきます。

今回は「1分足」でデータを取得します。データの取得にはCryptowatchを使用します。

実行するのは以下のコード。(コードを書くときに#を入れることで、メモを残しておくことができます)

import requests
from datetime import datetime

#CryptowatchnoのAPIで1分足を取得

response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc?periods=60")
response = response.json()#json形式に変換

#最後から2番目のローソク足を取り出す

data = response["result"]["60"][-2]

#ローソク足から日時・始値・終値を取り出す
#日時をdatetime型に変換する

close_time = datetime.fromtimestamp(data[0]).strftime('%Y/%m/%d %H:%M')
open_price = data[1]
close_price = data[4]

#取得したデータを書き出す

print( " 時間: " + close_time
+ " 始値: " + str(open_price)
+ " 終値: " + str(close_price))

まずはrequestsモジュールを使って、サイトからデータを取得します。

3行目のresponse = requests.get()で情報獲得元のURLを指定しています。

4行目は、取得したJSON形式のデータをPythonで使えるように変換する(パースする)設定をしています。

5行目は、取り出すデータの指定です。1分足なので60(秒)ごとのデータを取得。
最後から2番目のデータを指定するので[-2]を設定。なぜ、[-1]で一番最後のデータを取得しないのかというと、一番最後のデータはマーケットにおいて価格変動の最中であり、未確定の情報だからです。

6行目は、取得した日時(先頭にある=[0])をdatetime型に変換し、pythonで扱えるようにしています。

7,8行目は、始値(2番目=[1])と終値(5番目=[4])をそれぞれopen_priceとclose_priceとして定義しています。

9行目で、これらをprintで書き出す指示を出せば、1分のローソク足データの取得のコードが完成です。

PythonのRequestsモジュールの使い方パース(parse)とは?from ~~ import〜〜おさらいPython requestsを理解して活用しようJSONデータをパースするとは?

while文で処理をループさせる

ここからは、設定した指示をループさせるコード書いていきます。

今回活躍するのが「while文」です。

コードは以下の通り。

import requests
from datetime import datetime
import time

while True:

response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc?periods=60")
response = response.json()

data = response["result"]["60"][-2]

close_time = datetime.fromtimestamp(data[0]).strftime('%Y/%m/%d %H:%M')
open_price = data[1]
close_price = data[4]

print( " 時間: " + close_time
+ " 始値: " + str(open_price)
+ " 終値: " + str(close_price))

time.sleep(10)

変更点は赤字の部分です。

まず、import timeでsleep()という関数を使えるようにしています。
コードの一番最後にsleep()を付け加えることでwhile文でループさせる処理の間隔(今回は10秒)を指定することができるようになります。

while True:は、「これより下に書かれた処理を無限に繰り返せ」という指示コマンドのようなものです。

注意点はwhileの対象に指定したいコードの前にはインデント(空白)が必要なことです。

私は初めのうちは空白を設定しなかったため、コードが実行できず原因を調べることになりました。

エラーの原因はインデントが揃っていなかったことでした。

そのため、インデントを揃えることでコードを実行することができました。

修正後のコードで10秒ごとのデータを取得することができるようになりました。

if文で条件判定をする

ここからは、ローソク足の価格データを1分ごとに表示されるように設定する方法を学んでいきます。

そのために必要なのが 「if文」です。

やりたいことは、前回取得した価格データの時刻と今回取得した価格データの時刻が違う場合のみprint()を実行するという指示を出すことです。

つまり、「ローソク足のデータを取得する」「取得したデータの時刻を比較する」「時刻が異なる場合はprint()で書き出す」

書いたコードは以下の通り。

import requests
from datetime import datetime
import time

response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc?periods=60")
response = response.json()

last_data = response["result"]["60"][-2]
last_time = datetime.fromtimestamp(last_data[0]).strftime('%Y/%m/%d %H:%M')
time.sleep(10)

while True:

response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc?periods=60")
response = response.json()

data = response["result"]["60"][-2]

close_time = datetime.fromtimestamp(data[0]).strftime('%Y/%m/%d %H:%M')
open_price = data[1]
close_price = data[4]

if close_time != last_time:
   print( " 時間: " + close_time
    + " 始値: " + str(open_price)
    + " 終値: " + str(close_price))

   last_time = close_time

time.sleep(10)

まずはこの部分の解説。

last_data = response["result"]["60"][-2]
last_time = datetime.fromtimestamp(last_data[0]).strftime('%Y/%m/%d %H:%M')
time.sleep(10)

ここでlast_timeを定義しています。

そして、以下のコードでclose_timeとlast_timeを比較できるようにします。

if close_time != last_time:
 print( " 時間: " + close_time
  + " 始値: " + str(open_price)
  + " 終値: " + str(close_price))

「if close_time != last_time: 」で「!」が入っているのは「等しくない」という条件付けです。

この場合は、「close_timeがlast_timeではない場合、〜〜を実行しなさい」という指示を出すことになります。

【Python】if文の使い方と条件分岐をサンプルコードで解説!

ところがここにきて問題発生。

さっきまで実行できていたコードが突然実行不可能に...!

Cryptowatchのサイトにアクセスしても、「エラー:アカウント作ってください」とのメッセージが出るようになってしまいました。

原因を調べてみると、CryptowatchのAPIにはクレジットが設定されているようです。

本日はそれを使い切ってしまったようで、価格取得ができなくなってしまいました。

【参考情報】CryptowatchのAPIを叩いて仮想通貨(暗号資産)のヒストリカルデータを取得

24時間経つと回復するようなので、本日の学習はここで一区切りですね。

【2023/9/10追記】

上記のコードを実行して、1分毎のローソク足を取得することができました。

まとめ

Cryptowatch以外にも価格を取得できるサイトやAPIを探してみようと思います。

クレジット制限でデータ取得ができなくなってしまうようでは、高頻度botなどの戦略には使えません。

「これがダメなら別の方法を考える」という思考も板についてきたように感じます。

ここまで、連日仮想通貨botの開発に取り組んでいるため、「調べればなんとかなるだろう」くらいの気楽さも備わってきました。

また、インデント(空白)を揃えて指示の適用範囲を指定するということはよく覚えておきたいです。

インデントが揃っていないと正しく起動しないという点は、コードを書き換えるときやエラーが起きている時に発見しやすいというメリットにつながるので、pythonの良さでもありますね。

また、コードを書いているときに「この部分は今回必要ないな」とか「なぜこのコードがここに書いてあるのだろうか」という疑問を見過ごさずに考えるようにもなりました。

日々の継続って大事だなと実感。

次回は、処理を「関数」にまとめることを学んでいきます。

-Bot