#12 Python×ビットコイン自動売買 | クラスを作成してコードを読みやすくしよう!

  • URLをコピーしました!

こんにちは、はやたす(@hayatasuuu )です。

第12回目の本記事では、コードを読みやすくするためにクラスを作成していきます。

前回の記事 : #11 Python×ビットコイン自動売買 | Pythonを使ってビットコインを売却しよう!

これまで記事では、すべてのコードを1つのファイルに書いていました。

このように、1つのファイルですべてのコードを書くと非常に読みづらいです。

また複数のAPIにアクセスするとき、毎回URLを編集する必要が出てきます。

そこでクラスを活用することで、コインチェックAPIを扱いやすくしていきましょう。

クラスを苦手としている人は多いですが、これを機に慣れていきましょう!

目次

クラスを作成してコードを読みやすくしよう!

ここからは新しいファイルcoincheck.pyにクラスを作成していきます。

STEP① : ライブラリのインポート

まずはcoincheck.pyを開いて、main.pyで使っていたライブラリをインポートしましょう。

import hmac
import hashlib
import json
import time

import requests

上記のライブラリは、PrivateAPIの利用で必要になるんでしたね。

STEP② : __init__()の設定

ライブラリのインポートが完了したら、Coincheckという名前でクラスを作成していきましょう。

class Coincheck(object):
    pass

まずはインスタンスを生成したとき、どのメソッドでも共通で使う変数を設定するために__init__()を書いていきます。

具体的にいうと、API Keyのように「どんな操作をする上でも使う変数」を、以下のように__init__()で設定します。

class Coincheck(object):
    def __init__(self, access_key, secret_key):
        self.access_key = access_key
        self.secret_key = secret_key
        self.url = 'https://coincheck.com'

API Keyだけでなく、URLも設定しておきます。

このように設定すると、これまでと同じようにアクセス先のURLを簡単に変更できます。

STEP③ : 共通で使う内部メソッドの作成

今まで色々なAPIにアクセスして分かったと思いますが、基本的に変更されるのは「URL」と「パラメータ」だけです。

反対に以下の内容は同じものを使っています。

  • 署名
  • ヘッダーの作成
  • リクエスト部分

このような共通部分は、コードを一回書いておけば済むようにしたいです。

というわけで、以下のようにリクエスト用のメソッドを追加しましょう。

class Coincheck(object):
    def __init__(self, access_key, secret_key):
        self.access_key = access_key
        self.secret_key = secret_key
        self.url = 'https://coincheck.com'

    def _request(self, endpoint, params=None, method='GET'):
        nonce = str(int(time.time()))
        body = json.dumps(params) if params else ''

        message = nonce + endpoint + body
        signature = hmac.new(self.secret_key.encode(),
                             message.encode(),
                             hashlib.sha256).hexdigest()

        headers = {
            'ACCESS-KEY': self.access_key,
            'ACCESS-NONCE': nonce,
            'ACCESS-SIGNATURE': signature,
            'Content-Type': 'application/json'
        }

        if method == 'GET':
            r = requests.get(endpoint, headers=headers, params=params)
        else:
            r = requests.post(endpoint, headers=headers, data=body)
        return r.json()

上記のように_request()を準備しておくと、メソッドを呼び出すだけでAPIにアクセスできるので、認証用のコードを何度も書かずに済みます。

ちなみに_request()とアンダースコアを1つ付けているのは、このメソッドを内部的に使うことを想定しているからです。

言い方を換えるとインスタンス.メソッド名()の形で使うことを想定していません。あくまでもクラス内で使っていくメソッドになります。(※とはいっても外からアクセスすることは可能です!

STEP④ : 各APIにアクセスするためのメソッドを作成

これまでの記事で、以下5つのAPIを紹介しました。

  • /api/ticker
  • /api/trades
  • /api/order_books
  • /api/exchange/orders
  • /api/accounts/balance

それぞれのAPIごとに、メソッドを作成していきましょう。

tickerメソッド

クラスに対して、以下のメソッドを追加します。

class Coincheck(object):
    """
    中略
    """

    def ticker(self):
        endpoint = self.url + '/api/ticker'
        return self._request(endpoint=endpoint)

これで先ほど作成しておいた_request()を活用してメソッドを作成できました。

それでは、いま作成したticker()を使ってみましょう。main.pyを以下のように編集します。

import configparser

from coincheck import Coincheck

conf = configparser.ConfigParser()
conf.read('config.ini')

ACCESS_KEY = conf['coincheck']['access_key']
SECRET_KEY = conf['coincheck']['secret_key']

coincheck = Coincheck(ACCESS_KEY, SECRET_KEY)
ticker = coincheck.ticker()
print(ticker)


クラスを使うときは「①インスタンスの生成」をして「②インスタンス名.メソッド名()」で呼び出すんでしたね。

上記のように編集できたらmain.pyを実行してみましょう。

create-coincheck-class-object1

そうするとティッカーを取得できています。

ビットコインの最新価格が5,867,997円で、気がついたら高い位置にいますね^^;

lastプロパティ

いま使っていた/api/tickerでは、複数あるKeyのなかでlastしか使っていませんでした。

今回の自動売買では他のKeyが不要なので、lastだけ取得できるように以下のプロパティを作成しましょう。

class Coincheck(object):
    """
    中略
    """

    @property
    def last(self):
        return self.ticker()['last']

これでlastプロパティを使えば、ビットコインの最新価格だけ取得できます。

以下のようにmain.pyを編集して、lastプロパティを使ってみましょう。

import configparser

from coincheck import Coincheck

conf = configparser.ConfigParser()
conf.read('config.ini')

ACCESS_KEY = conf['coincheck']['access_key']
SECRET_KEY = conf['coincheck']['secret_key']

coincheck = Coincheck(ACCESS_KEY, SECRET_KEY)
# ticker = coincheck.ticker()
# print(ticker)

print(coincheck.last)

create-coincheck-class-object2

ターミナルの出力を見ると、ビットコインの最新価格だけが取得できていることが分かります。

その他メソッドの作成

残りのAPIについても、同じ要領で作成してきます。

最終的にコード全体としては以下のようになります。

import hmac
import hashlib
import json
import time

import requests


class Coincheck(object):
    def __init__(self, access_key, secret_key):
        self.access_key = access_key
        self.secret_key = secret_key
        self.url = 'https://coincheck.com'

    def _request(self, endpoint, params=None, method='GET'):
        nonce = str(int(time.time()))
        body = json.dumps(params) if params else ''

        message = nonce + endpoint + body
        signature = hmac.new(self.secret_key.encode(),
                             message.encode(),
                             hashlib.sha256).hexdigest()

        headers = {
            'ACCESS-KEY': self.access_key,
            'ACCESS-NONCE': nonce,
            'ACCESS-SIGNATURE': signature,
            'Content-Type': 'application/json'
        }

        if method == 'GET':
            r = requests.get(endpoint, headers=headers, params=params)
        else:
            r = requests.post(endpoint, headers=headers, data=body)

        return r.json()

    def ticker(self):
        endpoint = self.url + '/api/ticker'
        return self._request(endpoint=endpoint)

    @property
    def last(self):
        return self.ticker()['last']

    def trades(self, params):
        endpoint = self.url + '/api/trades'
        return self._request(endpoint=endpoint, params=params)

    def order_books(self, params=None):
        endpoint = self.url + '/api/order_books'
        return self._request(endpoint=endpoint, params=params)

    def balance(self):
        endpoint = self.url + '/api/accounts/balance'
        return self._request(endpoint=endpoint)

    @property
    def position(self):
        balance = self.balance()
        return {k: v for k, v in balance.items()
                if isinstance(v, str) and float(v)}

    def order(self, params):
        endpoint = self.url + '/api/exchange/orders'
        return self._request(endpoint=endpoint, params=params, method='POST')


balance()メソッドは、自分が保有している通貨ごとのポジションが表示されます。

ゆえに、今回の自動売買と関係ないものが多く含まれるので、ticker()と同じようにしてpotisionプロパティを追加しました。

これで今まで使ってきたAPIを操作できるメソッドを持つ、Coincheck専用のクラスを作成できました。

まとめ : クラスを作成してコードを読みやすくしよう!

というわけで、この記事ではビットコインの自動売買で使うクラスを作成しました。

今回のようにクラスを作成すると、コードの見通しが良くなります。

これから自動売買のロジックを組んでいきますが、コードが錯綜していると、自分でプログラムを組んでいて訳が分からなくなってしまいます。

このチュートリアルに限らず、クラスや関数を上手く活用して、繰り返し使う処理はまとめるようにしましょう。

次回の記事では、実際に自動売買ロジックを組んでみたいと思います。

いよいよ本格的になっていくので、難しいと感じる部分があったら復習しながら学習するようにしてください。

あわせて読みたい
#13 Python×ビットコイン自動売買 | 自動売買に必要なロジックを作成してみよう! こんにちは、はやたす(@hayatasuuu )です。 第13回目の本記事では、自動売買で必要なロジックを作成していきます。 前回の記事 : #12 Python×ビットコイン自動売買 | ク...
SNSに投稿して読み返す
  • URLをコピーしました!
  • URLをコピーしました!
目次