【再出発】貧乏だし文系だけどpythonで自動売買bot作りたい6日目

こんにちは!

貧乏文系がpythonで自動売買botを作りたい6日目!
今回は「ビットコインの価格データを直感的に理解できる形に変形する」をやっていきます。

前回は、「取得した価格データに個々にアクセスする」をして、ごちゃついたデータの中の各要素を取り出す方法を確認しました。

ちなみに、基本的に私がやっている内容は、リョータさんのブログで丁寧に説明されているもので、私がそれを参考にしているので、必然コードの書き方とかはクリソツになります。私は、ただ単にプログラミング初心者である私自身が自動売買botを作ろうとする様子を、出てきたエラーとかも含めてより細かく書きたいなあと思っているだけです。
強いて言えば、私が期待するのは、ちょっとプログラミングを理解している人なら素通りしがちなところを、なるべく私の失敗例とかも交えて記載することで、よりド初心者が理解しやすい形で書けるんじゃないかということ。
という訳で、より整理された内容で学びたい方は、リンク先のリョータさんのブログで学びましょう!笑

特に今回の内容は、上のサイトと同じコードを書くので、予め書いておきました(笑

ビットコインの価格データを直感的に理解できる形に変形する

さて、ビットコインの価格データを取得したら、テクニカル分析を加えるためにそのデータを操作しなければなりません。
各要素を抽出する方法は前回の記事で書きましたが、いかんせんUNIX時間が一体何日を指すのか、とかどれが始値でどれが終値だか分からないとか、データの識別が難しいという課題が残っています。

今回は、データを変形することでその課題を克服します。

先ず、今回の内容を実現するには、1つ学ばねばならない構文があります。
それはfor文という繰り返し処理です。

例えば、for文を理解するために、こんなコードを用意して実行してみます。

list = ["りんご", "ごりら", "らっぱ", "ぱんつ"]

for shiritori in list:
	print(shiritori)

結果

まず、1行目でlistと名付けたリストを用意して、そこに”りんご”から続く文字列をカンマ区切りで4つセットしています。

リスト辞書型やタプル等と並ぶ値の格納形式の一つ。[ ]の中に複数の値をカンマ区切りで格納する。

次に、3行目for文のところで、「for A in B:」という構文を使います。

for文繰り返し処理をしたい時に使う構文で「for A in B:」のように書き、繰り返し行いたい処理内容を次行以降に字下げして記載する。具体的な動き方としては、Bの値を1つずつ順番にAに代入して、その代入の度に字下げされた次行以降の処理を繰り返す。

載せたコードの3行目以下を具体化すると、

  1. 3行目:”りんご”を変数shiritoriに代入
  2. 4行目:shiritori(”りんご”が入ってる)を表示
  3. 3行目:”ごりら”を変数shiritoriに代入
  4. 4行目:shiritori(”ごりら”が入ってる)を表示
  5. 3行目:”らっぱ”を変数shiritoriに代入
  6. 4行目:shiritori(”らっぱ”が入ってる)を表示
  7. 3行目:”ぱんつ”を変数shiritoriに代入
  8. 4行目:shiritori(”ぱんつ”が入ってる)を表示

という動きになり、「list(B)の値を1つずつshiritori(A)に代入して、そのたびにshiritori(A)の値を表示する」ということが繰り返されています。
こうして得られた結果が、上に貼った画面です。

このfor文を使って、OHLC即ちローソク足データを見やすい形に整えていきます。

いきなり最終形を示すとこんな感じ。
新しいコードの記載には、青色背景のコメントを付けています。

import requests
# datetimeライブラリをインポート
import datetime

url = "https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc"
query = {"before": "1546268400", "periods": "86400"}

data = requests.get(url, params = query).json()

# データを整形
# priceというリストを用意
price = []

# ローソク足データを先頭から見やすい形に変形して、priceに格納していく繰り返し処理
for i in data["result"]["86400"]:
	price.append({"close_time" : i[0],
		"close_time_dt" : datetime.datetime.fromtimestamp(i[0]).strftime('%Y/%m/%d %H:%M'),
		"open_price" : i[1],
		"high_price" : i[2],
		"low_price" : i[3],
		"close_price": i[4] })

# 全ての整形が終わったpriceを表示
print(price)

 

順を追って書きます。

まず、3行目の「import datetime」ですが、ローソク足データの先頭にある”1545264000″のようなUNIX時間を日付時刻の形に直すためにdatetimeというライブラリをインポートしています。

次に、12行目の「price = []」ですが、整形した後のデータの格納先として、priceというリストを宣言しています。

そして最後、複雑なのですが、15行目~21行目までが、実際にローソク足データの整形を行っている処理になります。
こちらも具体的に何をやっているか書きます。

前回記事の復習にもなりますが、最初にデータを取ってきたときこんな形をしていました。

{‘result’:{‘期間’:[[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高],[前と同じ形式],…[前と同じ形式]]},’allowance’:{その他情報}}

データ整形をしたい対象はローソク足データのみなので、期間の部分や”allowance”キーに紐づいた情報は不要です。
なので、ローソク足データだけを抽出した「data[“result”][“86400”]」が処理のベースになります。

改めて、「data[“result”][“86400”]」を表示すると、下のようにローソク足データだけが取り出せています。
ここらへんの具合が分からない方は、最初にリンクを貼った前回記事をご参照ください。

文字で表すと、

[[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高],[前と同じ形式],…[前と同じ形式]]
というデータ構造になっています。

この時、

for i in data[“result”][“86400”]:
と繰り返し処理を書いてあげることで、”りんご”の例と同様に、変数iに順番にローソク足データが代入されていきます。

  1. 1個目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の塊をiに代入
  2. 字下げした処理が実行される
  3. 2個目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の塊をiに代入
  4. 字下げした処理が実行される
  5. 3個目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の塊をiに代入
  6. 字下げした処理が実行される
  7. 1-6までの処理が最後の塊を処理するまで繰り返される

という具合です。

で、ここからが字下げした繰り返し処理の中身ですが、まず、appendというメソッドを利用しています。

appendリストに値を追加したい時に利用するメソッド。「リスト名.append(追加したい値)」の形で使います。

追加したい値には、辞書型{}を用いています。
改行しているので分かりずらいですが、辞書型は{“キー名”:値}の形式で、{“キー名1”:値1, “キー名2”:値2}のように複数指定することが可能です。
コードでは、キーを6つ用意して、キーとそれに紐づく値をappendによってpriceに追加しています。

  1. 1つ目のキー:”close_time” ⇒ UNIX時間をそのまま追加
  2. 2つ目のキー:”close_time_dt” ⇒ UNIX時間を日付・時刻に変換して追加
  3. 3つ目のキー:”open_price” ⇒ 始値を追加
  4. 4つ目のキー:”high_price” ⇒ 高値を追加
  5. 5つ目のキー:”low_price” ⇒ 安値を追加
  6. 6つ目のキー:”close_price” ⇒ 終値を追加

ここであえて、値にキーを設定した上で、リストに追加しているのは、その方が後でデータを取り出しやすいからです。
これまでは、ローソク足データの並びを思い出して、3番目にある高値を取り出したければ「data[“result”][“86400”][0][2]」のように指定しなければならなかったのが、キーがあれば「data[“result”][“86400”][0][“high_price”]」のように並びを意識することなく直感的に欲しいデータを取り出すことができます。

また、2つ目のキーのところで

“close_time_dt” : datetime.datetime.fromtimestamp(i[0]).strftime(‘%Y/%m/%d %H:%M’)
という複雑な文字列が並んでいるので補記します。
fromtimestampはdatetimeライブラリのメソッドで、datetime.datetime.fromtimestamp(UNIX 時間)とすることで、UNIX時間を日付・時刻に直してくれます。
strftimeは、日付時刻.strftime(変換したい形式)とすることで、日付時刻を指定した形式に変換してくれる関数です。
この2つを組み合わせて、「UNIX時間⇒日付・時刻に変換⇒%Y/%m/%d %H:%M(YYYY/MM/DD HH:MM)形式に変換」ということをやっています。

さて、繰り返し処理の中身に話を戻しますが、
それぞれのキーについて、順にどんなことが行われるかを書きます。

まず変数iに先頭のローソク足の塊である「data[“result”][“86400”][0]」が代入されます。
data[“result”][“86400”][0]とは、1つ目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の塊です。
すなわち「i = 1つ目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]」となります。

このiのデータが繰り返し処理に流れていくと以下のような処理が行われます。

1つ目のキー

“close_time” : i[0]

⇒”close_time” : 1つ目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の0番目のデータ

⇒”close_time” : UNIX時間

2つ目のキー

“close_time_dt” : datetime.datetime.fromtimestamp(i[0]).strftime(‘%Y/%m/%d %H:%M’)

⇒”close_time_dt” : datetime.datetime.fromtimestamp(1つ目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の0番目のデータ).strftime(‘%Y/%m/%d %H:%M’)

⇒”close_time_dt” : datetime.datetime.fromtimestamp(UNIX時間).strftime(‘%Y/%m/%d %H:%M’)

⇒”close_time_dt” : UNIX時間をYYYY/MM/DD HH:MM形式に変換したもの

3つ目のキー

“open_price” : i[1]

⇒”open_price” : 1つ目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の1番目のデータ

⇒”open_price” : 始値

4つ目のキー

“high_price” : i[2]

⇒”high_price” : 1つ目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の2番目のデータ

⇒”high_price” : 高値

5つ目のキー

“low_price” : i[3]

⇒”low_price” : 1つ目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の3番目のデータ

⇒”low_price” : 安値

6つ目のキー

“close_price”: i[4]

⇒”close_price” : 1つ目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の4番目のデータ

⇒”close_price” : 終値

これら変換された値が、appendメソッドによってpriceに追加されます。
「i = 1つ目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の塊」の処理が終われば、今度は「i = 2つ目の[UNIX時間,始値,高値,安値,終値,BTCベースの出来高,JPYベースの出来高]の塊」の処理が続き、最後のローソク足データの塊まで全てpriceに追加されます。

すると最終的にpriceは以下のようなデータ構造になります。

ローソク足のデータが分かりやすい名称のキーに紐づいて、整理された形でpriceというリストに格納されているのが分かります。

ちなみに、BTCベースの出来高やJPYベースの出来高も同じ要領でキーに紐づけてpriceに格納することができますので、出来高情報も使いたいという方は、キーを追加してみると良いと思います。

改めて今回出来上がったコードを再掲します。

import requests
import datetime

url = "https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc"
query = {"before": "1546268400", "periods": "86400"}

data = requests.get(url, params = query).json()

price = []

for i in data["result"]["86400"]:
	price.append({"close_time" : i[0],
		"close_time_dt" : datetime.datetime.fromtimestamp(i[0]).strftime('%Y/%m/%d %H:%M'),
		"open_price" : i[1],
		"high_price" : i[2],
		"low_price" : i[3],
		"close_price": i[4] })

print(price)

 

さてさて、どこまで文系の人の役に立つ内容になったか自信が無いですが、一旦、データを取り出しやすい形に整形することが出来ました。

今後は、例えば2番目のローソク足データの高値が欲しい!となれば、price[1][“high_price”]と指定するだけで取り出せるようになりました。
データの操作性が上がったので、自動売買botのコーディングがしやすくなったとも言えます。

次回は、これら整形したデータをファイルに落とすということを実装したいと思います。

差し支えなければ、twitterをフォローして頂けますと嬉しいです。

それでは~。

%d人のブロガーが「いいね」をつけました。