- 更新日: 2020年01月17日
- 公開日: 2020年01月05日
無料で作れて無料で運用できるPythonのDIYアプリに挑戦-ビットコインの価格変動を教えてくれるメールアプリ
株価や為替(FX)、仮想通貨の価格変動が気になって、仕事が手につかないという方も多いのではないでしょうか?
株価や為替は、証券会社からのアラート機能を使って通知させれば、ある程度把握できますが、仮想通貨についてはどうでしょうか? CoinCheck など一部の取引所はアラート機能を装備していますが、世界最大の取引所 BitMEX にはアラート機能はありません。
今回は 「DIYアプリ」 ということで、 BitMEX に対応した "価格変動通知アプリ" を作成してみたいと思います。 もちろん作成したコードは公開しますので、ご参考ください。
一人でも多くの方が、ビットコイン価格をあまり気にせず、仕事に集中できれば幸いと思います。
【本稿で参考になること】
・ Python で API を使う方法
・ JSONデータから必要な部分だけ抽出する方法
・ 関数の作り方と使い方
・ 時間の操作方法
・ Python でメールを送る方法
・ BitMEX の API の使い方(REST API)
無料で作れて無料で運用できるPythonのDIYアプリに挑戦-ビットコインの価格変動を教えてくれるメールアプリ
【Python DIYアプリ事例】 ビットコイン価格の変動を教えてくれるDIYアプリ
【DIYアプリの動作環境】
・ サーバー: Pythonanywhere(無料*)
・ メール機能: SendGrid(無料)
・ 価格データ: BitMEX API(無料)
完全無料で Python DIY アプリが動き、定期的にビットコイン価格の変動をメールでお知らせしてくれます。メールアドレスや銘柄、チェック間隔を変えるだけで Python の知識がなくても Python DIY アプリを動かせるでしょう。
制作過程を参考にすることで応用したり他のデータ通知に活かしたりできますので、要所要所ピックアップしてプログラムの様子をご紹介していきます。
最終的な運用環境は Pythonanywhere ではなく、 Oracle Cloud Always Free に。
・ 上記動画のコード/ GitHub
今すぐコードをみる
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
import requests
import json
import datetime
from pytz import timezone
import time
sended = 0
def send_mail():
global message, sended_time, sended
message = Mail(
from_email='oshimamasara@yahoo.co.jp',
to_emails='oshimamasara@gmail.com',
subject='MyBotからのお知らせ 変動率: ' + str(percent),
html_content='本文なし')
try:
sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
response = sg.send(message)
print(response.status_code)
print(response.body)
print(response.headers)
sended_time = str(now_time.minute)
sended = sended + 1
except Exception as e:
print(e.message)
def btc_data():
global symbol,percent, price_now
response = requests.get("https://www.bitmex.com/api/v1/instrument")
data = json.loads(response.text)
symbol = data[88]["symbol"]
percent = data[88]["lastChangePcnt"]
price_now = data[88]["midPrice"]
if percent < -0.003 or percent > 0.003:
if sended > 0 :
#print("ifif___")
#print(type(minute))
#print(type(sended_time))
if minute == sended_time:
print("送信したばっか...")
else:
send_mail()
else:
send_mail()
#print("else___")
#print(sended_time)
else:
pass
def print_data():
global minute
btc_data()
month = str(now_time.month)
day = str(now_time.day)
hour = str(now_time.hour)
minute = str(now_time.minute)
print("TIME: " + month + "月" + day + "日 " + hour + "時" + minute + "分")
print(symbol + " : "+ str(price_now))
print("変動率: " + repr(percent))
i = 0
sleep_time = 10
while True:
try:
print("\n チェックスタート " + str(i) + "回目")
now_time = datetime.datetime.now(timezone('Asia/Tokyo'))
print_data()
print("メール送信回数::: " + str(sended))
time.sleep(sleep_time)
i = i + 1
except:
print("チェックエラー")
time.sleep(sleep_time)
i = i + 1
Python DIYアプリの設計方法
今回は 「ビットコインの価格」 が一定以上変動したらメール送信、という処理を検討しました。図で書くと以下のようなイメージに。
価格チェックの更新頻度は、 BitMEX の API 規定によって予め上限があり、 1分間に 60回までのアクセス*。 今回は 10秒毎にデータをチェックする仕様でプログラムを設定してみました。しかし、上図の流れでは、価格を確認する 10秒毎にメールも送られてきます。 受信箱が DIYアプリからのメールだらけになりますので、この事態は避ける必要がありそうです。
「最初は価格が一定以上変わったら メール送信」(上図 左) でしたが、 「価格が一定以上変わって、直克時間も経過していたら メール送信」(上図 右) にすることで、 メールの連発を防げます。特に今回はメール送信に SendGrid というサービスを利用しようと思っていますので、メール送信数に気を付ける必要があります。
SendGrid: 無料利用枠のあるメールサービスで 1日 100回までの送信数となっている
プログラミングのことを知っている方なら上図を眺めていて、なんとなく「 if文や ループで処理するのかな」とイメージできると思います。それでは実際に API からビットコインの価格変動率を取得したり、チェック機能をプログラムしたりして DIYアプリを作っていきましょう。
尚プログラムの実行環境については、最初は Pythonanywhere で動かしていましたが、無料プランの場合、コンソールでプログラムを動かしっぱなしにできないことが判明。 現在 VPS サーバー並に無料利用できる Oracle Cloud にデプロイしてみました。
BitMEXのAPI
BitMEX のビットコイン価格を Python で知る方法は、 標準の API 以外に CCXT というライブラリ、それから BtiMEX製の Python ライブラリを使う方法があります。
それぞれ特徴はありますが、 標準 API の場合は pip install
で新規ライブラリを追加しなくても実行できますので「分かりやすいかな...」と思ってこちらを選択しました。
まずは BitMEX 標準 API を使って、ビットコイン価格並びに価格変動率を取得してみましょう。
BitMEX の API ということですが、公式サイトを見ても情報量が多く、分わかりにくいです。 Google 検索で 「bitmex api price」 などで検索してみましょう(上図参照)。
https://www.bitmex.com/api/explorer/
すると上図のようなトレーディング・プラットフォームに関する API のページが。試しに ベース URL にアクセスしてみます。
Base URI: https://www.bitmex.com/api/v1
すると上図右のように BitMEX API からレスポンスを得ることに成功。この Web ページに "価格取得" できる API の URL がありそうなので、各項目を確認していきます。
いくつかリンクしているところがありますので辿ってみると、 "Download Swagger JSON" については、今回の API が Swagger 形式でまとめられていることが確認できます(上図参照)。
Swagger: APIを作成する時に使うフレームワーク
次に "API Endpoints" の項目を確認すると "Instrument" の項目説明に 「Contracts」 とか 「History」 とか取引情報に関する記述が。試しに先ほどの Base URL に "Instrument" を付けてみると,,,
BitMEX の銘柄毎の情報を取得できました。ここを掘り下げれば ビットコイン価格 を確認できそうです。
とりあえずブラウザ上で Ctrl + f
した結果が上図。ビットコイン価格を示す XBTUSD だけでも 103 項目の情報がリストアップされています。こちらの https://www.bitmex.com/api/v1/Instrument
で表示されている JSON データは、今の市場状況を示しますので、こちらを Python で読み込んでデータ取得したいと思います。
BitMEXのAPIから必要なデータ(価格)を抽出する
今回 BitMEX の API は、 Python モジュールの "Requests" を使って読み込みテスト。
上図のコード
import requests
response = requests.get("https://www.bitmex.com/api/v1/instrument")
print(type(response.text))
print(response.text)
import json
data = json.loads(response.text)
print(type(data))
len(data)
data[0]
ポイントは、 API URL の https://www.bitmex.com/api/v1/Instrument
で取得した JSON データが辞書型ではなく "配列型" ということ。 2番目のプログラムで <class 'list'>
と出力されていることが確認できます。
そしてその配列データには 100個の銘柄情報が入っており、 data[順番]
とすることで各銘柄の情報を確認可能。この data[]
の中に ビットコイン(XBTUSD) に関する情報もあると思いますので、 data[]
内に ビットコイン情報があるか、チェックしていきます。
上図のコード
type(data[0])
data[0].keys()
symbol_name = [d.get('symbol') for d in data]
print(symbol_name)
print(type(symbol_name))
len(symbol_name)
"XBTUSD" in symbol_name
symbol_name.index("XBTUSD")
まず各銘柄情報をもつ data[]
、データ型を確認すると "辞書型" であることが確認できます(上図最初のコード)。次に辞書型 data[]
の キー を確認すると、銘柄を示す symbol
が(上図2番目コード)。
次は symbol
の一覧を表示して XBTUSD があることを確認したいと思います。
辞書型内の特定のキー要素を取得する方法として、 "for文" の活用があるでしょう。上図 3番目コードのように
symbol_name = [d.get('symbol') for d in data]
とすることで、 辞書型 data[]
内の キー "symbol" についての要素一覧を取得することができます。
そして取得した symbol リストの要素数を確認すると 100、また その中に XBTUSD
があるかどうか確認すると True (上図下から2番目コード)。 何番目に XBTUSD
があるか確認すると、 88番目であることが確認できます(上図最下部コード)。
上図のコード
symbol_name.index("XBTUSD")
data[88]["symbol"]
data[88]["midPrice"]
data[88]["lastChangePcnt"]
100こ中 88番目にビットコイン(XBTUSD)のデータがあることが確認できましたので、 data[88]
とすれば情報を入手できそう。 辞書型 data[88]
内のキー情報を取得するには
data[88][キー]
とすれば OK(上図参照)。 BitMEX のライブのビットコイン情報が取得できましたので、あとはこれを "変数" にして操作していけばアプリを作れそうですね。ちなみに価格の変動率は lastChangePcnt
というキーでデータ取得可能、単位は % ですね。
価格変動チェック・プログラム
先ほどまでの工程でビットコイン価格はチェックできましたので、次は 「もし〇〇より高かったら、△△」 「もし□□より低かったら◇◇」 というチェック機能をプログラムしたいと思います。(上図の部分)
上図のコード
import datetime
now_time = datetime.datetime.now()
symbol = data[88]["symbol"]
percent = data[88]["lastChangePcnt"]
price_now = data[88]["midPrice"]
print(now_time)
from pytz import timezone
now_time = datetime.datetime.now(timezone('Asia/Tokyo'))
print(now_time)
def bitmex_data():
print("TIME: " + str(now_time.month) + "月" + str(now_time.day) + "日 " + str(now_time.hour) + "時" + str(now_time.minute) + "分")
print(symbol + " : "+ str(price_now))
print("変動率: " + repr(percent))
bitmex_data()
まずは先ほど取得できたビットコインに関する情報を "変数"化(上図一番上のコード)。取得するデータが "いつ" のものか確認する必要があるのですが、 BitMEX API の 時刻基準 はイギリス。日本時刻を取得するためにモジュール datetime
と pytz
を使用。
datetime.now()
で現在時刻を取得し、 timezone('Asia/Tokyo')
で日本時間に変換しています。
そして BitMEX API から取得するビットコイン情報を、関数 bitmex_data()
に収録(上図最下段コード)。関数管理することで、プログラムが管理しやすくなります。これでプログラム実行時点でのビットコイン価格や変動率を取得できました。
上図のコード
if percent < -0.003 or percent > 0.003:
print("価格変動あり")
bitmex_data()
else:
print("価格は大きく上下していない、大丈夫、仕事に集中してください\n")
bitmex_data()
def btc_check():
if percent < -0.003 or percent > 0.003:
print("価格変動あり")
bitmex_data()
else:
print("価格は大きく上下していない、大丈夫、仕事に集中してください\n")
bitmex_data()
btc_check()
次は価格変動率の値によって処理を振り分けるプログラム。今回はプログラムの反応を見やすくするために、価格変動(lastChangePcnt
)が 0.3% 以上変わった時に処理を実行、としました(上図上段のプログラム)。とりあえずは 0.3% 以上価格が変わった時に print文 としていますが、ここに "メール送信" 機能を装備すれば、価格変動を検知して、メールを送ってくれるプログラムとなります。ひとまずこのチェックプログラムも 関数 btc_check()
に収録。
次は "メール送信機能" ですが、こちらは Google Colab の環境では実行しにくいので、 Pythonanywhere にテスト環境を移します。
ここまでの Python コード/ Google Colab
Pythonでメール送信
Pythonでメールを送る方法はいくつかありますが、恐らく一番簡単でセキュアな方法は "SendGrid" というメールサービスを利用する方法。 SendGrid は、無料で月 100通までメール送信でき、 Gmail や Yahoo!メール のアカウント情報を入力しなくても使えるので Good です。
メール送信については下記動画を参考にしてみてください。
SendGrid のメール送信コードを扱いやすくするために、関数 send_mail()
にまとめておきます(上図参照)。尚、メールアドレスはご自身のアドレスに変更ください。
上図のコードをみる
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
def send_mail():
message = Mail(
from_email='〇〇@yahoo.co.jp',
to_emails='〇〇@gmail.com',
subject='MyBotからのお知らせ 変動率: ',
html_content='本文なし')
try:
sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
response = sg.send(message)
print(response.status_code)
print(response.body)
print(response.headers)
# 今の時間
# メール送信した回数
except Exception as e:
print(e.message)
send_mail()
ビットコイン価格に応じてメール送信
上図のコードをみる
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
import requests
import json
import datetime
from pytz import timezone
import time
now_time = datetime.datetime.now(timezone('Asia/Tokyo'))
print(now_time)
def send_mail():
message = Mail(
from_email='〇〇@yahoo.co.jp',
to_emails='〇〇@gmail.com',
subject='MyBotからのお知らせ 変動率: ',
html_content='本文なし')
try:
sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
response = sg.send(message)
print(response.status_code)
print(response.body)
print(response.headers)
except Exception as e:
print(e.message)
def btc_data():
response = requests.get("https://www.bitmex.com/api/v1/instrument")
data = json.loads(response.text)
symbol = data[88]["symbol"]
percent = data[88]["lastChangePcnt"]
price_now = data[88]["midPrice"]
#if percent < -0.1 or percent > 0.1:
if percent < -0.05 or percent > 0.05:
send_mail()
else:
pass
btc_data()
ここまでの過程で、 Python を使って 「ビットコイン価格の確認」 と 「メール送信」 を行えるようになりました。次は "ビットコイン価格が一定範囲を超えたらメール" という条件分岐の処理を実行したいと思います。
上図のコードでは、最初に -10% 以下もしくは 10% を超えたら "メール送信" 。次に -5% もしくは 5% を超えたら "メール送信" という 2つの設定でテスト。
現在のビットコイン変動率は -5.75% なので、最初の条件 「-10% もしくは 10% 超え」 の条件には当てはまらないために "メール送信なし" という結果に(条件式 44行目)。次に 「-5% もしくは 5% 超え」 の条件式で実行すると、 send_mail()
が実行されてメールが送信されました。
条件式の値を変えると、好みの条件でメール送信できることが確認できます。
一定時間毎にメールを送るプログラム
さてメールを送ることはできましたが、 「前回メールを送ってから一定時間経過したかどうか」 をチェックするためには、 "メール送信した時間" と "今の時間" を比較する必要があります。
時間の確認、比較方法は色々あると思いますが、今回はシンプルに 「メール送信から 1分 経過していたら、またメール送信」 としました。プログラムを変更すれば 30分ごと、 1時間ごと等に変更できるでしょう。
さて実際のプログラムを考えた時、 「前回メールを送ってから...」 とありますが、プログラムを実行したばかりの段階では 「前回のメール」 そのものがありません。なので下図のように 「初回メール送信の場合」 と 「2回目以降のメール送信の場合」 で処理を分ける必要があります。
これらをプログラムに書き込んでみると以下のようになりました。
上図のコードをみる
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
import requests
import json
import datetime
from pytz import timezone
import time
sended = 0
now_time = datetime.datetime.now(timezone('Asia/Tokyo'))
print(now_time)
def send_mail():
global sended_time, sended
message = Mail(
from_email='〇〇@yahoo.co.jp',
to_emails='〇〇@gmail.com',
subject='MyBotからのお知らせ 変動率: ',
html_content='本文なし')
try:
sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
response = sg.send(message)
print(response.status_code)
print(response.body)
print(response.headers)
now_minute = str(now_time.minute)
sended_time = now_minute
sended = sended + 1
except Exception as e:
print(e.message)
def btc_data():
response = requests.get("https://www.bitmex.com/api/v1/instrument")
data = json.loads(response.text)
symbol = data[88]["symbol"]
percent = data[88]["lastChangePcnt"]
price_now = data[88]["midPrice"]
if percent < -0.05 or percent > 0.05:
if sended > 0 :
check_minute = str(now_time.minute)
if check_minute == sended_time:
print("送信したばっかり...")
else:
send_mail()
else:
send_mail()
else:
pass
print("send_mail()")
send_mail()
print("何分に送った? " + str(sended_time) + "分")
print("\n btc_data()")
btc_data()
メールの送信回数を変数 sended
に設定し、プログラム実行直後は sended = 0
なので 「メール送信初回」 の処理。そしてメールを送る関数 send_mail()
の中に "メール送信カウンター" として、メール送信実行する度に sended
に +1 。
メールの送信回数をもつ sended
を他の関数内でも使えるように global変数 として設定(上図左の 18行目)。それから送信時の時間も sended_time
に収録。これでメールを送った回数とメール送信の時刻を扱えるようになります。
あとはビットコイン価格によって処理を振り分けたプログラムに、 「メール送信回数」 と 「送信時刻」 による条件文を加えれば OK ということ。上図右の
- 46行目で 価格変動のチェック
- 47行目で メール送信回数のチェック
- 49行目で 前回のメール送信から一定時間経っているかチェック
となっています。
上図右の 59行目で メール送信を実行。 63行目で再度 「価格チェック」 を行いますが、 59行目でメールを送ったばかりなので "メール送信は なし " となっていますね。
これで一通りの "価格チェック&メール送信" 機能はプログラムできましたので、あとは常時チェックしてもらうようにループ内で実行します。
無限ループで常時価格チェック&メール送信
ビットコインの価格チェックからはじまったプログラム、上図のように 「メール送信」 したあとはまた最初からプログラムを繰り返し実行してくれれば 「チェック・アプリ」 として機能しますね。 この処理プロセスをプログラムで書くと以下のように。
上図のコードをみる
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
import requests
import json
import datetime
from pytz import timezone
import time
sended = 0
def send_mail():
global message, sended_time, sended
message = Mail(
from_email='〇〇@yahoo.co.jp',
to_emails='〇〇@gmail.com',
subject='MyBot BTC 変動率: ' + str(percent),
html_content='本文なし')
try:
sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
response = sg.send(message)
print(response.status_code)
print(response.body)
print(response.headers)
sended_time = str(now_time.minute)
sended = sended + 1
except Exception as e:
print(e.message)
def btc_data():
global symbol,percent, price_now
response = requests.get("https://www.bitmex.com/api/v1/instrument")
data = json.loads(response.text)
symbol = data[88]["symbol"]
percent = data[88]["lastChangePcnt"]
price_now = data[88]["midPrice"]
if percent < -0.05 or percent > 0.05:
if sended > 0 :
if minute == sended_time:
print("送信したばっか...")
else:
send_mail()
else:
send_mail()
else:
pass
def print_data():
global minute
btc_data()
month = str(now_time.month)
day = str(now_time.day)
hour = str(now_time.hour)
minute = str(now_time.minute)
print("TIME: " + month + "月" + day + "日 " + hour + "時" + minute + "分")
print(symbol + " : "+ str(price_now))
print("変動率: " + repr(percent))
i = 0
sleep_time = 10
while True:
try:
print("\n チェックスタート " + str(i) + "回目")
now_time = datetime.datetime.now(timezone('Asia/Tokyo'))
print_data()
print("メール送信回数::: " + str(sended))
time.sleep(sleep_time)
i = i + 1
except:
print("チェックエラー")
time.sleep(sleep_time)
i = i + 1
新たに 関数 print_data()
を設けてプログラムの実行状況を把握できるように処理しました。無限ループ処理については 66行目から 78行目で処理。 10秒毎に価格変動率をチェックし、 1分毎にメール送信、これを繰り返すプログラム内容となっています。
コマンドでプログラムを止めない限り、メール送信回数のリミットに達しない限り、ビットコイン価格が条件に当てはまれば、永遠にメールが送られてきます。
SendGrid の Free Plane は、 100回/月 までの送信回数です。ご注意ください。
DIYのPythonアプリを無料で実行し続ける方法
今回作成した Python プログラムを Oracle Server にセットして動かしている様子
ここまで自分のパソコンで Python プログラムを実行し、無限ループまで成功できましたが、パソコンの電源を切れば "無限ループ" 、つまり DIYアプリ が止まります。この問題を解決する手段としては、サーバーでのプログラム実行、となるのですが AWS や Googleクラウドには無料利用に制限があり、あまり実用的ではありません。
検索した結果、 Pythonanywhere という Webサービスもあったのですが、 12時間ほどコマンドでプログラムを実行しっぱなしにすると、自動的にコマンドが落ちています。どうも有料プランにしないと "常時コマンドRUN" はできない様子。
Pythonanywhere での "デーモン化" テストは未実施。
諦めずに検索した結果、 Oracle Cloud が 2019年9月に 「Always Free」 というプランをリリースしていました。こちら、 VPSサーバー なみのことを無料で利用できちゃいます、凄いです。 Oracle Cloud への設定方法まで記述すると長くなりますので、割愛させて頂きました。
尚、サーバーの起動方法については下記動画が参考になると思います。
Oracle Cloud に SSH で接続し、今回ご紹介した Pythonプログラムを実行すると、下記のように永遠とビットコイン価格をチェックし、必要に応じてメールしてくれる DIY アプリが無料でできました。
1分毎に価格をチェックし、 1時間毎にメールを送る設定。
【Oracleサーバーで常時 Python プログラムを実行し続けるコマンド】
nohup python3 -u 〇〇.py > ./mail_log.log 2>&1 &
【Pythonプログラムを止める手順】
ps -ef
実行中の Pythonプログラムの PID ナンバーを確認
kill 番号 PID
まとめ
今回はビットコイン価格の変動を教えてくれる DIY アプリでしたが、株や為替、天気や道路情報など応用すれば色々なことの "自動通知" に使うことができるでしょう。
"Python でアプリ" 、 "API" というとハードルが高いように感じるかもしれませんが、今回のプログラム、はPython の関数までしか使っていません。クラスを使用せず 1つのファイルでアプリを作成しました。そして SendGrid や Oracle Cloud などの無料環境を使って、上手く運用。必要なのは "Pythonの基礎スキル" と "アイディア" ということが確認できますね。
「Pythonの参考書買ったけど、自分のパソコンに Python インストールできない」という方や、「なんとなくアプリのアイディアはあるけど、具体的にどうすればいいかわからない」 という方は、プログラミングスクールで Python の基礎をサクサク習得してみませんか?
CodeCamp には 『Pythonの基礎レッスン』と 『エンジニア志望者向けのPythonレッスン』いうコースがあります。完全オンラインで効率的に習得する Python 学習をあなたも試してみませんか?
「オンラインレッスンでちゃんと身に付くの?」「どんな先生がどんなレッスンをするの?」なんて疑問や不安があるようでしたら、CodeCampの無料体験レッスンを受講してみてはいかがでしょうか。
200名以上いる講師陣から自分に合いそうな講師を選び、都合の良い日時を選んで、プログラミング学習が体験できます。 無料体験レッスンでCodeCamp の価値をご体感ください。
ご興味のある方は、公式ページ よりチェックしてみてください。
昨今のプログラミング需要の高まりを受けて、無料体験枠が少ない時もあります。予め、ご了承ください。
- この記事を書いた人
- オシママサラ