今回はZaifのプライベートAPIのリクエストを実際に送信してみましょう。
Zaifには以下の4つのAPIがあります。
・現物公開
・現物取引
・先物公開
・レバレッジ取引
4つの中でも現物取引APIとレバレッジ取引APIは、実際の売買注文などもできるAPIにです。
※手動で注文を出さなくとも、プログラムが変わりに注文を出す事ができたら・・・とても便利。なんて事はみんな考えると思いますが、このAPIを使えばそれが可能になるのです。
現物取引とレバレッジ取引のAPIを使う場合は、「お作法」に則ってリクエストを送信します。
そして今回はそのリクエストも送れる「共通関数」を作成してみましょう。この関数を一度作成しておけば、後々とっても便利です。
今回は現物取引APIでリクエストを送信しますが、レバレッジの場合も基本は同じです。
■前提知識・条件
・Pythonの基本文法が分かる
・Zaifのアカウントを開設している
・ZaifのAPIキーを生成済み
コンテンツ
Zaifの現物取引APIへのリクエスト方法
APIにリスクエストする上で必要なポイントを絞って、順番にお伝えしますね。
※ZaifのAPIの仕様の詳細については以下をご参考にして下さい。最終的にはいつも仕様書を読まなければなりません。
①パラメータの設定
まずは実際にリクエストする際のパラメータを設定する必要があります。このパラメータというのは、APIに対してどの様な操作を依頼するのか?という情報をまとめたものと思えば大丈夫です。
Pythonで記述する場合、パラメータは辞書形式で設定します。
今回作成するリクエスト関数では引数としてパラメータを受け取る形にします。つまりパラメータ設定は関数の外側で行います。こうしておく事で様々なパラメータに応用できる関数になるのです。
ちなみに、辞書形式の値のサンプルは以下の様になります。辞書形式のデータがどうなっているのか?その概念だけでも掴んでおいて下さい。
■辞書形式のサンプルPythonコード
1 2 3 4 |
dict = {'key1':1,'key2':2,'key3':3,} print(dict['key1']) print(dict['key2']) print(dict['key3']) |
■実行結果
1 2 3 |
1 2 3 |
dictに辞書形式の値を設定して、辞書の各キー項目に対する値を出力しています。Pythonを使っていれば当然の様に使っているかもしれませんね。
nonceについて(つまずきポイント)
Zaifの取引APIリクエストを送信する場合は、パラメータの他にnonce値というものを付与してあげる必要があります。nonce値とは重複の防止や、順序の制御をするための値です。
このnonce値が一意でないと、リクエストは失敗してしまいます。
以下は101から始まるnonce値を付与した場合のリクエスト可否を簡単にまとめたものです。
■nonceとリクエスト可否
nonceの値 | リクエストの可否 |
101 | 〇 |
102 | 〇 |
101 | ✖ ※101は既に送信済み |
103 | 〇 |
time関数でnonce値を作成
nonce値はタイムスタンプなどを設定するのが一般的です。一意に値が求まりますし、どんなプログラミング言語でも、関数を使えば生成が楽です。
今回は、Pythonのtime関数を使って生成してみましょう。※場合によってはもっと凝った生成をする必要があります。
以下はtime関数を使って値を生成する例です。この値をそのまま or 少し加工してnonce値として設定してあげればOKです。
■Pythonコード
1 2 |
from time import time print(time()) |
■実行結果
1 |
1537632111.6162016 |
time値が取得できているのが分かります。
URLのエンコード
パラメータはURL送信形式にエンコードする必要があります。URL形式の場合は、「val1=値1&val2=値2&val3=値3」の様に「&」を使ってパラメータが繋がっていきます。
PythonにはURLエンコード用のライブラリ「urllib」があるのでそれを使います。
以下はPythonでURLエンコードする場合の例です。
■Pythonコード
1 2 3 4 5 6 7 8 9 10 11 12 |
from urllib.parse import urlencode from time import time params = { 'method': 'actiuve_orders', 'currency_pairs': 'btc_jpy', 'nonce': time() } encoded_params = urlencode(params) print(encoded_params) |
■実行結果
1 |
method=actiuve_orders¤cy_pairs=btc_jpy&nonce=1538278991.5156908 |
URL形式でエンコードできている事が分かるかと思います。
署名する
APIキー発行の時に一緒に作成したsecretを使い、メッセージ認証コード技術の一つである、HMAC-SHA256でパラメータの署名を行います。
これはプライベートAPIを使用する上ではつまずく点かもしれません。そして、急にHMACと言われても、初めての場合は若干意味が分からないかもしれません。HMACの詳細についてはこちらの記事で解説していますので、どの様な技術なのかについては参考にして下さい。
まずは署名の基本だけでも分かっておけば大丈夫です。ただ、署名は確実に行って下さい。
リクエストのヘッダーデータ作成
リクエストを送信する際はヘッダーデータを渡す必要があります。
ヘッダーデータの内容は、
・APIキー
・パラメータをsecretで署名した内容(ハッシュ値)
となります。
■ヘッダーデータ例(Pythonの場合)
1 2 3 4 |
headers = { 'key': API_key, 'sign': signature.hexdigest() } |
具体的な記述方法は後述するサンプルコードを参考にして下さい。
リクエスト送信
あとは、ヘッダーデータを付与してリクエスト送信します。
requestsライブラリを使ってPOSTでデータを送信すればOKです。
この時、POSTで送信するのは以下になります。
・現物取引のURI
・エンコードしたパラメータデータ
・作成したヘッダー
実際にサンプルのコードを書いて実行してみましょう!
リクエスト結果の確認
結果の確認は必須ではありませんが、リクエスト結果も確認をしておきましょう。
Zaifの場合、APIへのリクエストが正しく送信されると、結果として「status_code」に「200」という値が返却されます。この返却値を確認する事で、リクエストが正しいかどうかを判定できます。なので、status_codeが200以外だった場合は、その値を表示させてみましょう。
ちなみに、この結果ステータスというのはHTTPリクエストが正しく行われたかどうかの結果ですので、仮に必要資金が足りないなどの原因で注文が通らなかった場合も200が返却されます。
注文の内容が正しいかどうかについては、その他の返却値を確認して判断しましょう。
リクエストを行うプログラムを作ろう
これまでに解説した内容を基にしてサンプルのプログラムを作成しましょう。
zaifのAPIでは、残高やAPI権限、過去の取引情報などを取得するget_infoというAPIがあるのですが、ここではその軽量版であるget_info2というAPIへのリクエストをしてみます。
パイソン用のプログラムファイル「◯◯.py」を作成して、Anaconda Promptで実行します。
リクエストを行う共通関数も作成してみます。
処理の流れ
処理は前半で解説した通りの流れなのですが、おさらいをしてみましょう。
1.パラメータを設定する(リクエスト関数外でAPIやnonce値を設定する)
2.URLエンコードを行う
3.署名する
4.リクエスト用のヘッダを作る
5.リクエストを送信する
※1はリクエスト関数の外で行います。2~5はリクエスト関数の中で行います。
とりあえず実際のコードを見てみましょう。
サンプルコード
■Pythonコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import json import datetime from time import time import hmac import hashlib import requests from urllib.parse import urlencode def Zaif_Private_Req(params): API_key = 'APIキーを入力' secret = 'secretを入力' API_URL = "https://api.zaif.jp/tapi" encoded_params = urlencode(params) signature = hmac.new(bytearray(secret.encode('utf-8')), digestmod=hashlib.sha512) signature.update(encoded_params.encode('utf-8')) headers = { 'key': API_key, 'sign': signature.hexdigest() } response = requests.post('https://api.zaif.jp/tapi', data=encoded_params, headers=headers) if response.status_code != 200: raise Exception('return status code is {}'.format(response.status_code)) return response params = { 'method': 'get_info2', 'nonce': time() } response = Zaif_Private_Req(params) print(json.loads(response.text)) |
■実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
{ "success": 1, "return": { "funds": { "jpy": 5000, "btc": 0, "xem": 0, "mona": 0 }, "deposit": { "mona": 0, "xem": 0, "btc": 0, "jpy": 5000 }, "rights": { "info": 1, "trade": 1, "withdraw": 0, "personal_info": 0, "id_info": 0 }, "open_orders": 0, "server_time": 1538279895 } } |
■解説
細かい内容は本記事の前半部分を参照して下さい。ここでは内容を簡単にまとめます。
まず、パラメータ(get_info2というメソッド名やnonce値)を設定してリクエスト用関数に渡しています。
関数の中ではパラメータをURLエンコードして、secretで署名します。
APIキーとsecretで署名したデータからヘッダーデータを作ります。
そして、URI、エンコードしたデータ、ヘッダーデータを引数としてPOSTすればOKという流れです。
実際にリクエストをしたら念のためステータス結果を確認しています。ステータスが200以外の場合はraiseで例外処理を行っています。
また、結果の方を見てみると、success値が1となっているため、正しく情報が取得できている事が分かります。
この時、テスト的に日本円5000円だけを入金している状態なので、’funds’を見ると、’JPY’:5000.0と表示されている事も分かります。
その他にもAPIキーの権限も表示されます。infoとtradeだけが1となっていますので、この2つだけに権限が与えられている事が分かります。
get_infoの戻り値の詳細についてはzaifのAPIの仕様書も確認をしてみてくださいね。
まとめ
さて、ZaifのプライベートAPIにリクエストをしてみました。リクエスト送信だけを行う関数も作成をしましたので、今後結構使えるのではないかと思います。
今回はちょっとした情報を取得しただけでしたが、次は注文を行うリクエストを送信してみましょう。