Pythonを用いたバイナンス ジャパンの仮想通貨APIの使い方

バイナンス ジャパンのAPIを使って仮想通貨botを作りましょう。

この記事では、Pythonでバイナンス ジャパンのAPIを使う方法を説明します。
実際に動作するコードをお見せします。

前準備

Binance Japanに口座を開設する

まず、バイナンス ジャパンで口座開設をしましょう。

バイナンス ジャパンには「お友達紹介プログラム」があります。

ぜひ、1800円相当のBNBを受け取ってください。

以下のURLよりEメールアドレスもしくは電話番号で登録を行ってください。アカウント設定の画面で必ず紹介コードを入力してください。

・URL: 招待URL

・紹介コード: 116836794

・達成条件:初めて口座を開設されるお客さまで、紹介者から受け取った紹介コードを被紹介者が入力し、本人確認手続きを完了させ、口座開設を完了してください。

・特典:被紹介者の口座開設が完了した後、紹介者と被紹介者の両方のBinance Japan口座にそれぞれ1800円相当のBNBが30営業日以内に付与されます。

Binance JapanのAPI仕様書

バイナンス ジャパンのAPI仕様書です。

requestsモジュールの仕様書

APIコールで使用するrequestsの仕様書です。

必要なPythonモジュール

サンプルコードでimportするモジュールです。

import requests
import json
import time
from datetime import datetime
import hmac
import hashlib
import urllib.parse

API使用時の補足事項

symbolsパラメータで複数シンボルを指定するときの注意

複数シンボルを指定するときの文字列は[“BTCJPY”,”BNBJPY”]のように書く。

[“BTCJPY”, “BNBJPY”]のようにカンマのあとにスペースを入れてはいけない。

# 不正な文字列だと以下のエラーが返る。
{
    "code": -1100,
    "msg": "Illegal characters found in parameter 'symbols'; legal range is '^\\[(\"[A-Z0-9-_.]{1,20}\"(,\"[A-Z0-9-_.]{1,20}\"){0,}){0,1}\\]$'."
}
サンプルコード中のAPIキーはご自身のものに置き換える

変数apiKey変数secretKeyにはご自身のものを入れてください。

Market Data Endpoints

24hr Ticker Price Change Statistics

24時間統計情報を取得してみます。
https://binance-docs.github.io/apidocs/spot/en/#24hr-ticker-price-change-statistics

endPoint = 'https://api.binance.com'
path     = '/api/v3/ticker/24hr'
url = endPoint + path

# symbolsは["BTCJPY","BNBJPY"]のような文字列にする。スペース禁止。
symbols = ['BTCJPY', 'BNBJPY']
symbols = '","'.join(symbols)
symbols = '["' + symbols + '"]'

parameters = {
    'symbols': symbols,
    'type': 'MINI',
}

response = requests.get(url, params=parameters)
res = response.json()
print(json.dumps(res, indent=4))

レスポンスはこうなります。
typeパラメータをFULLにすると、もっと多くの情報を取得できます。

[
    {
        "symbol": "BNBJPY",
        "openPrice": "74198.00000000",
        "highPrice": "76230.00000000",
        "lowPrice": "71755.00000000",
        "lastPrice": "75537.00000000",
        "volume": "467.93380000",
        "quoteVolume": "34432964.20890000",
        "openTime": 1726002934743,
        "closeTime": 1726089334743,
        "firstId": 579058,
        "lastId": 580945,
        "count": 1888
    },
    {
        "symbol": "BTCJPY",
        "openPrice": "8205300.00000000",
        "highPrice": "8262873.00000000",
        "lowPrice": "7880000.00000000",
        "lastPrice": "8174929.00000000",
        "volume": "21.65736900",
        "quoteVolume": "174862160.11487200",
        "openTime": 1726004797097,
        "closeTime": 1726091197097,
        "firstId": 1940213,
        "lastId": 1949622,
        "count": 9410
    }
]

BTCJPYのopenTimeのUNIX時間を実時間に変換してみます。

t = datetime.fromtimestamp(1726004797097/1000)
print(t)
# 2024-09-11 06:46:37.097000

Trading Day Ticker

その日のTicker情報を取得します。
https://binance-docs.github.io/apidocs/spot/en/#trading-day-ticker

endPoint = 'https://api.binance.com'
path     = '/api/v3/ticker/tradingDay'
url = endPoint + path

# symbolsは["BTCJPY","BNBJPY"]のような文字列にする。スペース禁止。
symbols = ['BTCJPY', 'BNBJPY']
symbols = '","'.join(symbols)
symbols = '["' + symbols + '"]'

parameters = {
    'symbols': symbols,
    'type': 'MINI',
}

response = requests.get(url, params=parameters)
res = response.json()
print(json.dumps(res, indent=4))

レスポンスはこうなります。

[
    {
        "symbol": "BNBJPY",
        "openPrice": "73521.00000000",
        "highPrice": "76230.00000000",
        "lowPrice": "71755.00000000",
        "lastPrice": "75537.00000000",
        "volume": "395.20860000",
        "quoteVolume": "29043945.82830000",
        "openTime": 1726012800000,
        "closeTime": 1726099199999,
        "firstId": 579141,
        "lastId": 580945,
        "count": 1805
    },
    {
        "symbol": "BTCJPY",
        "openPrice": "8216247.00000000",
        "highPrice": "8262873.00000000",
        "lowPrice": "7880000.00000000",
        "lastPrice": "8174929.00000000",
        "volume": "21.04431200",
        "quoteVolume": "169819916.64230600",
        "openTime": 1726012800000,
        "closeTime": 1726099199999,
        "firstId": 1940496,
        "lastId": 1949622,
        "count": 9127
    }
]

BTCJPYのopenTimeのUNIX時間を実時間に変換してみます。
APIのtimeZoneパラメータはデフォルトなのでUTCになるのですが、9:00になっている理由がよくわかりません。
UTCとJSTの時差が9時間で、私のアカウントがBinace Japanだからでしょうか。
でも、endPointはBinance Globalのものなんですよね。シンボルにJPYが含まれるからですかね。
API仕様書からは読み取れませんでした。

t = datetime.fromtimestamp(1726012800000/1000)
print(t)
# 2024-09-11 09:00:00

24hour ticker と Trading day ticker のAPIの違いはあまりわかりませんでしたが、使いやすい方を使ってください。
LTPは同じ価格が返っていると思います。

Order Book

板情報を取得します。
https://binance-docs.github.io/apidocs/spot/en/#order-book

# 板情報取得
endPoint = 'https://api.binance.com'
path     = '/api/v3/depth'
url = endPoint + path

symbol = 'BTCJPY'
parameters = {
    'symbol': symbol,
    'limit': 2,
}

response = requests.get(url, params=parameters)
res = response.json()
print(json.dumps(res, indent=4))

このようなレスポンスが返ります。
板情報の数はlimitパラメータで決まります。
デフォルトは100で、最大値は5000です。

{
    "lastUpdateId": 181868260,
    "bids": [
        [
            "8276608.00000000",
            "0.02843500"
        ],
        [
            "8275774.00000000",
            "0.04176900"
        ]
    ],
    "asks": [
        [
            "8279483.00000000",
            "0.00834500"
        ],
        [
            "8279568.00000000",
            "0.02364800"
        ]
    ]
}

Kline

Kline情報を取得します。
https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data

BTCJPYの日足データを2つ取得してみます。

# KLine取得
endPoint = 'https://api.binance.com'
path     = '/api/v3/klines'
url = endPoint + path

parameters = {
    'symbol': 'BTCJPY',
    'interval': '1d', # 日足
    'limit': 2,
}

response = requests.get(url, params=parameters)
res = response.json()
print(json.dumps(res, indent=4))

レスポンスです。

[
    [
        1725926400000,
        "8183871.00000000",
        "8269121.00000000",
        "8074739.00000000",
        "8214810.00000000",
        "17.95516700",
        1726012799999,
        "146895069.95628100",
        8009,
        "8.79789100",
        "71977998.49504800",
        "0"
    ],
    [
        1726012800000,
        "8216247.00000000",
        "8262873.00000000",
        "7880000.00000000",
        "8176200.00000000",
        "21.11211300",
        1726099199999,
        "170373932.95085800",
        9160,
        "10.14012400",
        "81761256.46578200",
        "0"
    ]
]

取得した2つのKline open timeをUNIX時間から実時間に変換してみます。
ローソク足の長さは日足指定で、タイムゾーンはデフォルトのUTCにしています。
Kline open timeは9:00となっていました。UTCとJSTの時差が考慮された時刻になっていそうです。

t = datetime.fromtimestamp(1725926400000/1000)
print(t)
t = datetime.fromtimestamp(1726012800000/1000)
print(t)

# 2024-09-10 09:00:00
# 2024-09-11 09:00:00

Symbol Price Ticker

LTP(Last Traded Price:最終取引価格)を取得できます。
https://binance-docs.github.io/apidocs/spot/en/#symbol-price-ticker

# LTP取得
endPoint = 'https://api.binance.com'
path     = '/api/v3/ticker/price'
url = endPoint + path

# symbolsは["BTCJPY","BNBJPY"]のような文字列にする。スペース禁止。
symbols = ['BTCJPY', 'BNBJPY']
symbols = '","'.join(symbols)
symbols = '["' + symbols + '"]'
parameters = {
    'symbols': symbols,
}

response = requests.get(url, params=parameters)
res = response.json()
print(json.dumps(res, indent=4))

レスポンスです。

[
    {
        "symbol": "BNBJPY",
        "price": "76719.00000000"
    },
    {
        "symbol": "BTCJPY",
        "price": "8266926.00000000"
    }
]

Wallet Endpoints

システムのステータス取得

システムの稼働状態を取得します。
https://binance-docs.github.io/apidocs/spot/en/#system-status-system

# システムのステータス取得
endPoint = 'https://api.binance.com'
path     = '/sapi/v1/system/status'
url = endPoint + path

response = requests.get(url)
res = response.json()
print(json.dumps(res, indent=4))

レスポンスです。

{
    "status": 0,
    "msg": "normal"
}

User Asset

資産残高を取得します。
https://binance-docs.github.io/apidocs/spot/en/#user-asset-user_data

# 資産残高の取得
endPoint = 'https://api.binance.com'
path     = '/sapi/v3/asset/getUserAsset'
url = endPoint + path

timestamp = int(time.time() * 1000)
parameters = {
    'timestamp': timestamp,
    'needBtcValuation': True,
}

text = urllib.parse.urlencode(parameters)
sign = hmac.new(secretKey.encode('utf-8'), text.encode('utf-8'), hashlib.sha256).hexdigest()
parameters.update({'signature': sign})

headers = {
    "X-MBX-APIKEY": apiKey,
}

response = requests.post(url, headers=headers, data=parameters)
res = response.json()
print(json.dumps(res, indent=4))

サンプルコード中のapiKeyとsecretKeyはご自身のものに置き換えてください。

レスポンスです。

[
    {
        "asset": "BNB",
        "free": "0",
        "locked": "0",
        "freeze": "0",
        "withdrawing": "0",
        "ipoable": "0",
        "btcValuation": "0"
    },
    {
        "asset": "BTC",
        "free": "0",
        "locked": "0",
        "freeze": "0",
        "withdrawing": "0",
        "ipoable": "0",
        "btcValuation": "0"
    },
    {
        "asset": "JPY",
        "free": "0",
        "locked": "0",
        "freeze": "0",
        "withdrawing": "0",
        "ipoable": "0",
        "btcValuation": "0"
    }
]

Spot Trading Endpoints

New Order

新規注文方法です。
https://binance-docs.github.io/apidocs/spot/en/#new-order-trade

現物取引でビットコインを800万円で0.001サイズほど指値で買い注文するサンプルコードです。

# 新規注文
endPoint  = 'https://api.binance.com'
path      = '/api/v3/order'
url = endPoint + path

timestamp = int(time.time() * 1000)

parameters = {
    'timestamp': timestamp,
    'symbol': 'BTCJPY',
    'side': 'BUY',
    'type': 'LIMIT',
    'price': 8000000,
    'quantity': 0.001,
    'timeInForce': 'GTC',
}

text = urllib.parse.urlencode(parameters)
sign = hmac.new(secretKey.encode('utf-8'), text.encode('utf-8'), hashlib.sha256).hexdigest()
parameters.update({'signature': sign})

headers = {
    "X-MBX-APIKEY": apiKey,
}

response = requests.post(url, headers=headers, data=parameters)
res = response.json()
print(json.dumps(res, indent=4))

いくつか省略しますが、以下のようなレスポンスが返ります。
数字9桁の注文ID(orderId)が発行され、注文キャンセルする場合はこれを使います。

{
    "symbol": "BTCJPY",
    "orderId": nnnnnnnnn,
    "orderListId": -1,
    "price": "8000000.00000000",
    "origQty": "0.00100000",
    "executedQty": "0.00000000",
    "cummulativeQuoteQty": "0.00000000",
    "status": "NEW",
    "timeInForce": "GTC",
    "type": "LIMIT",
    "side": "BUY",
}

必須パラメータが抜けていたら、以下のようなエラーが返ります。

{
    "code": -1102,
    "msg": "Mandatory parameter 'timeInForce' was not sent, was empty/null, or malformed."
}

All Orders

注文一覧を取得します。
https://binance-docs.github.io/apidocs/spot/en/#all-orders-user_data

現物取引の注文一覧を取得するサンプルコードです。
ビットコインの注文一覧を1つ取得しています。
一覧の数はlimitパラメータで設定でき、デフォルトは500で最大値は1000になっています。

# 注文一覧の取得
endPoint  = 'https://api.binance.com'
path      = '/api/v3/allOrders'
url = endPoint + path

timestamp = int(time.time() * 1000)

parameters = {
    'timestamp': timestamp,
    'symbol': 'BTCJPY',
    'limit': 1,
}

text = urllib.parse.urlencode(parameters)
sign = hmac.new(secretKey.encode('utf-8'), text.encode('utf-8'), hashlib.sha256).hexdigest()
parameters.update({'signature': sign})

headers = {
    "X-MBX-APIKEY": apiKey,
}

response = requests.get(url, headers=headers, params=parameters)
res = response.json()
print(json.dumps(res, indent=4))

いくつか省略しますが、以下のようなレスポンスが返ります。

[
    {
        "symbol": "BTCJPY",
        "orderId": nnnnnnnnn,
        "orderListId": -1,
        "price": "8000000.00000000",
        "origQty": "0.00100000",
        "executedQty": "0.00000000",
        "cummulativeQuoteQty": "0.00000000",
        "status": "NEW",
        "timeInForce": "GTC",
        "type": "LIMIT",
        "side": "BUY",
        "stopPrice": "0.00000000",
        "icebergQty": "0.00000000",
        "isWorking": true,
    }
]

Cancel Order

注文キャンセル方法です。
https://binance-docs.github.io/apidocs/spot/en/#cancel-order-trade

上の例の注文時に発行された注文IDはを使って、キャンセルしてみます。

    # 注文キャンセル
    endPoint  = 'https://api.binance.com'
    path      = '/api/v3/order'
    url = endPoint + path

    timestamp = int(time.time() * 1000)

    parameters = {
        'timestamp': timestamp,
        'symbol': 'BTCJPY',
        'orderId': order_id,
    }

    text = urllib.parse.urlencode(parameters)
    sign = hmac.new(secretKey.encode('utf-8'), text.encode('utf-8'), hashlib.sha256).hexdigest()
    parameters.update({'signature': sign})

    headers = {
        "X-MBX-APIKEY": apiKey,
    }

    response = requests.delete(url, headers=headers, params=parameters)
    res = response.json()
    print(json.dumps(res, indent=4))

変数order_idに数字9桁の注文IDを入れてください。

いくつか省略しますが、以下のようなレスポンスが返ります。

{
    "symbol": "BTCJPY",
    "orderId": nnnnnnnnn,
    "orderListId": -1,
    "price": "8000000.00000000",
    "origQty": "0.00100000",
    "executedQty": "0.00000000",
    "cummulativeQuoteQty": "0.00000000",
    "status": "CANCELED",
    "timeInForce": "GTC",
    "type": "LIMIT",
    "side": "BUY",
}

注文キャンセル後に注文一覧を見ると、status=CANCELEDになっています。

[
    {
        "symbol": "BTCJPY",
        "orderId": nnnnnnnnn,
        "orderListId": -1,
        "price": "8000000.00000000",
        "origQty": "0.00100000",
        "executedQty": "0.00000000",
        "cummulativeQuoteQty": "0.00000000",
        "status": "CANCELED",
        "timeInForce": "GTC",
        "type": "LIMIT",
        "side": "BUY",
        "stopPrice": "0.00000000",
        "icebergQty": "0.00000000",
        "isWorking": true,
    }
]

Spot Account Endpoints

Account Trade List

取引履歴を取得します。
https://binance-docs.github.io/apidocs/spot/en/#account-trade-list-user_data

現物取引の取引履歴を取得するサンプルコードです。
ビットコインの取引履歴を1つ取得してみます。
履歴の数はlimitパラメータで指定でき、デフォルト500で最大1000です。

# 取引履歴の取得
endPoint  = 'https://api.binance.com'
path      = '/api/v3/myTrades'
url = endPoint + path

timestamp = int(time.time() * 1000)

parameters = {
    'timestamp': timestamp,
    'symbol': 'BTCJPY',
    'limit': 1,
}

text = urllib.parse.urlencode(parameters)
sign = hmac.new(secretKey.encode('utf-8'), text.encode('utf-8'), hashlib.sha256).hexdigest()
parameters.update({'signature': sign})

headers = {
    "X-MBX-APIKEY": apiKey,
}

response = requests.get(url, headers=headers, params=parameters)
res = response.json()
print(json.dumps(res, indent=4))

以下のようなレスポンスが返ります。

[
    {
        "symbol": "BTCJPY",
        "id": nnnnnnn,
        "orderId": nnnnnnnnn,
        "orderListId": -1,
        "price": "8245000.00000000",
        "qty": "0.00013200",
        "quoteQty": "1088.34000000",
        "commission": "0.00001043",
        "commissionAsset": "BNB",
        "isBuyer": false,
        "isMaker": true,
        "isBestMatch": true
    }
]