PythonとAWSを使って、仮想通貨自動トレード その1 後半

AWS

PythonをAWSを使った仮想通貨自動ドレードその1の後半編です。

前回は、Pythonのコードを書いて、ローカル環境(Macのterminal)などからbitbankAPIにビットコインの購入のリクエストをする手順を紹介しました。ただ、これだけだと買いたい時に毎回pythonを実行しなくてはいけないので、これを AWS Lambda と CloudWatchEvents を使って定時に購入するシステムを構築しましょう。

AWS Lambda とは? CloudWatch Eventsとは?

AWSのLambdaというサービスは、サーバレスでpythonなどのコードを実行してくれるサービスです。例えばEC2でpythonを実行しようとすると、最適なAMIを使ってEC2インスタンスを立てて、内部でpythonを使えるようにインストールして・・・と手間がかかってしまい、かつ常にEC2を立てっぱなしにしないといけないなど、料金面でも不利になります。また、セキュリティの確保なども必要になります。Lambdaはこういった手間・料金・セキュリティ等々でメリットがあります。

AWSのCloudWatchはざっくりいうと、様々なリソースを監視したり、最適化したりするサービスです。CloudWatchは色々とできることがあるためややこしいのですが、ここではCloudWatch Eventsを利用します。これは、「Amazon Web Services (AWS) リソースの変更を示すシステムイベントのほぼリアルタイムのストリームを提供します。」とありますが、何かしらのイベントが起きると、別のイベントを実行できるというようなサービスです。この時のイベントは、時間を決めることもできれば、EC2の状態変更や、S3にファイルが格納されることなど、様々な種類を指定できます。

LambdaとCloudWatch Eventsの設定

Lambdaにソースコードを格納する前に、LambdaとCloudWatch Eventsを設定しましょう。基本的にはAWSのコンソールをぽちぽちしていけば作成できます。Lambda側からCloudWatch Eventsの設定もできるため、基本はLambdaのサービスを設定していけばできます。

Lambdaのサービス画面から、関数の作成 → 一から作成を選択する。

関数名は自由につけることができます。ランタイムは記述する言語を選択します。執筆時現在ではPython3.6、3.7、3.8を選択できました。実行ロールは新しいロールを作成するのが良いと思います(のちのち設定を行います)。そのほかデフォルトのまま設定して、関数を作成します。

上部に「正常に作成されました」と表示されればOKです。ここから

  • トリガーの設定
  • 環境変数の設定
  • ソースコードのアップロード

を行います。

トリガーの設定

比較的簡単に設定できます。トリガーの追加を押し、必要事項を記入します。

ルール名とその説明は任意で大丈夫です。ルールタイプはスケジュール式を選択し、cronかrate式でトリガーを引くタイミングを設定します。

  • rate(1 day)・・・24時間おきにイベントが発生
  • cron(0 12 * * ? *)・・・毎日12時にイベントが発生

今回は4時間に一回トリガーを引くように設定します。

トリガーの有効化は、システムを全て構築してからの方がいいです。

環境変数の設定

Lambdaには環境変数を設定しておくことができます。ここにAPIキーと認証キーを保存するのが良いです。というのも、ソースコード内にキーを格納すると、そのコードが流出した際に悪用されてしまうためです。一方、環境変数で設定しておくと、AWS KMSというサービスを使ってこれらのAPIキーと認証キーを暗号化して保存しておくことができます。Lambdaが起動した時だけこれらを復号します。KMS内に保管されている暗号化キーを使って暗号化・復号しますが、この暗号化キーをこのLambdaしか使えないように設定することで、より強固なセキュリティーを確保できるという仕組みです。

暗号化キーの作成

設定していきましょう。まず、KMSに今回利用する暗号化キーを準備します。この際に、Lambdaの設定タブ内のアクセス権限内にある「実行ロール ロール名」に書かれた情報が必要になるので事前に確認してください。

サービスからKMSを選択し、キーの作成をしましょう。作成および利用にはお金がかかるため注意してください。

Pricing | AWS Key Management Service (KMS) | Amazon Web Services (AWS)
Pricing for AWS Key Management Service (KMS) | Amazon Web Services (AWS)

ステップ1:キーのタイプは対象、詳細オプションはデフォルトのまま(KMS)にします。

ステップ2:エイリアスはキーの名前を入力します。説明・タグは何に使っているかを記載・タグします(任意)。

ステップ3:キーの管理アクセス許可を定義します。これはどのIAMユーザあるいはIAMロールがこのキーを管理するかを設定します。AWSルートユーザでログインしている場合(本来はよくないですが)は特段チェックいらないと思われます。

ステップ4(重要):このキーを使用できる人を定義します。ここでは、Lambdaがここで作成するキーを使えるようにする必要があるため、Lambdaに与えられているロールにチェックをする必要があります。事前に確認した実行ロールにチェックを入れてください。これで、Lambdaがこのキーを使う権限を持つことができるようになります。

ステップ5:確認です。ここまでの設定があっているかを確認しましょう。これで、完了するとキーの作成が完了します。

Lambdaに環境変数を設定

作成したbitbank_autotrade_2という関数を開きましょう。この中の、設定→環境変数を押すと、環境変数(0)という画面になります。ここを編集していきます。

キーにはPythonコードで指定するタグの名前を、値には対応するものを格納します。今回はAPIキーと認証キーを追加します。ここでは、APIキーをpractice_api、認証キーをpractice_secretとしています。そのあと、暗号化の設定で「転送時の暗号化に使用するヘルパーの有効化」にチェックを入れ、「保管時に暗号化するAWS KMS キー」を「カスタマーマスターキーの使用」とし、先ほど作成した暗号化キーを選択します。

ここで、各環境変数の右側に暗号化というボタンができるため、これをクリックします。そして、AWS KMS キーとして先ほど作成したキーを選択して暗号化をクリックすると、入力した値を暗号化することができます。Lambdaにはこの状態で環境変数が保存されます。逆にLambda実行時には復号する必要があるということです。その処理はアップロードするソースコード内に記載することになります。

ソースコードのアップロード

ソースコードのアップロードをします。Lambdaに実行するソースコードを共有する方法として、

  • Lambdaの画面に直書き
  • zipファイルに固めてアップロード

の2つの方法がありますが、後者になることが多いと思います。また、サイズが大きい場合はS3を経由する必要があります。

zipファイルは、lambda_function.pyというPythonのスクリプトと、それを実行するために必要なモジュールを一緒にて生成します。lambda_function.py には、lambda_handlerという関数を記載し、Lambdaが起動するとこの関数を実行する設定にデフォルトでなっています(変更可)。

lambda_function.pyの記載例を書きます。

import python_bitbankcc
import json
import os
import boto3
import os

from base64 import b64decode

# 暗号化された環境変数を復号する
ENCRYPTED = os.environ['API_KEY']
api_key = boto3.client('kms').decrypt(
    CiphertextBlob=b64decode(ENCRYPTED),
    EncryptionContext={'LambdaFunctionName': os.environ['AWS_LAMBDA_FUNCTION_NAME']}
)['Plaintext'].decode('utf-8')

ENCRYPTED = os.environ['API_SECRET']
api_secret = boto3.client('kms').decrypt(
    CiphertextBlob=b64decode(ENCRYPTED),
    EncryptionContext={'LambdaFunctionName': os.environ['AWS_LAMBDA_FUNCTION_NAME']}
)['Plaintext'].decode('utf-8')


def lambda_handler(event, context):

    # インスタンスの作成
    prv = python_bitbankcc.private(api_key, api_secret) 

    # 購入の実施
    order_result = prv.order( 
    pair = 'btc_jpy', # ペア
    amount = '0.0001', # 注文枚数
    side = 'buy', # 注文サイド
    type = 'market' # 注文タイプ
    )
    
    return json.dumps(order_result)

半分から下は、前半でご紹介したものそのままですね。半分から上については暗号化された環境変数を復号する処理ですが、これはほぼ定型文なので詳細は省略します。ENCRYPTEDにLambdaの環境変数を暗号化されたまま格納して、それをKMSに保管された暗号化キーを用いて復号しています。

この lambda_function.py とインポートしている各モジュールをzipしてS3に配置し、それをLambdaのコードの「アップロード元」で選択するとソースコードをアップロードできます。必要なモジュールはlambda_function.pyでインポートしているモジュールとそれに付随するモジュールです。おそらく「-info」というファイルはなくても動く可能性があります。

本来は「仮想環境を作成 → pipでlambda_function内のモジュールをインポート → インポートされているモジュールを引っ張り出して、lambda_function.pyと一緒にzipファイルを作成する」といった手順で作成するのがよいです。この手順はまたどこかでご紹介できたらと。仮想環境を利用すると、何もないまっさらな仮想環境内に必要なモジュールだけをインストールできるので必要最低限のモジュールだけをzipすることができます。仮想環境なんてわからないよ!って方は、上記のモジュールをmacbookのどこかにあるフォルダから探してからzipする必要があります。ない場合はそもそもpipなどでインストールが必要です。

モジュールの場所は、例えばmacのterminal上で

python
>>> import requests
>>> print(requests.__file__)
/Users/〇〇/.pyenv/versions/anaconda3-5.3.0/lib/python3.6/site-packages/requests/__init__.py

とコマンドすると、requestsモジュールが格納されている場所が出力されます。他のモジュールも同じ場所に格納されているので、仮想環境が使えない場合は、必要なモジュールだけをコピーしてきて、zipしてください。基本は全てsite-packagesというフォルダ内にあると思います。

(追記)仮想環境の作り方の記事を作成しました。参考にしてください。

テストとトリガーの有効化

これでLambdaの設定が完了しました。まだトリガーを有効にしていないと思うので、Lambdaは起動しません。トリガーをオンにする前にテストしてみましょう。

Lambdaのテストと言うタブからテストできます。今回は、何も設定することなく「呼び出し」ボタンを押してみましょう。すると、Lambdaが実行され、実行結果が出てきます。緑色で成功となっていればOKです。bitbankの取引所をみてみましょう。注文した分だけ正しく購入されていると思います。

テストに成功したら、設定したCloud Watch Eventsを有効化しましょう。関数の概要からEventBridge (CloudWatch Events)を選択し、オンにするルールのトリガーにチェックをいれ、有効化ボタンから有効化しましょう。これで指定したルール通りに購入が行われます。

正しく動いているかはCloudWatchLogsから確認できます。細かい確認方法はまた別の回で実施しようと思います。

まとめ

今回はPythonとAWSで、仮想通貨の自動売買をするシステムを構築してみました。思ったよりも難しかったのですが、これでシステムができたので、どういうルールで売買するかをLambda関数のコードに順次記載していくことで、理想としている自動売買ができるようになります。

Lambdaはサーバレスで実行できるので便利です。ただ、これから機械学習を使って購入判定を実施しようと考えていたので、Lambda上でGPUが使えるのかは気になりました(まぁ推論なのでCPUでも計算できそうですが)。

次回以降は、購入判定のルールを作成したり、Flutterなどを使ってデフォルトのbitbankアプリにはない注文方法ができるアプリの作成などを考えていけたらと思っています。

コメント

タイトルとURLをコピーしました