リピート系トレードbotの作成方法を解説【仮想通貨のリピート系トレードbotをPythonで自作しよう④】

この記事には広告を含む場合があります。

記事内で紹介する商品を購入することで、当サイトに売り上げの一部が還元されることがあります。

リピート系トレードbotを作成するには、以下のように発注した注文の管理と注文が約定したかを確認する必要があります。

  • 指値注文を出した価格の管理
  • 指値注文の注文IDの管理
  • 決済注文の管理
  • 決済注文の注文IDの管理

そのため、裁量取引とは違い、注文の状況をCSVファイルで管理します。

今回は例としてビットコイン用のプログラムを作成します。ビットバンクの取扱銘柄は、38種類もあるのでリピート系トレードbotに適した仮想通貨の検証もしてみてください。

本記事では、注文リストのCSVファイルを作成するプログラムの紹介とリピート系トレードbotの作成方法について解説します。

リピート系トレードbotのフローチャート

リピート系トレードbotのフローチャートは次のようになります。

すごく単純に見えますが、リピート系トレードの動作を表現するとこのような感じになります。

この動作をプログラムで作成していきます。

注文リストのCSVファイル作成プログラム

まずは、リピート系トレードbotで使用するCSVファイルをプログラムで作成します。

Python
import csv


# 設定値
start_price = 11000000  # 開始値
end_price = 7000000     # 終了値
step = 30000            # 減少幅


# CSVファイルに書き込むデータを生成する関数
def generate_csv_data(start_price, end_price, step):
    data = [["price", "order", "stock", "buy_id", "sell_id"]]
    for price in range(start_price, end_price - 1, -step):
        data.append([price, 0, 0, None, None])
    return data


# データ生成
data = generate_csv_data(start_price, end_price, step)

# CSVファイルの作成
with open("bitcoin_order_list.csv", "w", newline="") as file:
    writer = csv.writer(file)
    writer.writerows(data)

print("CSVファイルが作成されました。")

リピート系トレードでは想定変動幅を設定します。このプログラムでは、start_priceend_priceがそれにあたります。ビットコインの直近の値幅から11,000,000円から7,000,000円としました。

stepは指値注文を出す間隔になります。間隔を狭くすると注文数が増えるので必要資金が多く必要となります。また、間隔が広すぎても注文が通りにくくなるので、バランスよく設定してください。

このプログラムを実行するとbitcoin_order_list.csvというファイルができます。このファイルをスプレッドシートで開くと下の表のようになっています。

各セルに注文の状態や注文IDを記録していきます。orderやstockの「0」は「注文なし」を意味します。後述しますが、「1」となれば「注文あり」です。

このbitcoin_order_list.csvは、次のリピート系トレードbotのプログラムと同じフォルダに保存してください。

リピート系トレードbotのサンプルコード

Python
import time
import requests
import json
import pandas as pd
import python_bitbankcc

flag = {
        'order': '',
        'list_number': 0,
        'order_price': '',
        'order_id': ''
        }

pair = 'btc_jpy'  # 取引通貨の設定
profitable_price = 40000  # 利確の価格設定
amount = '0.0001'  # 注文枚数の設定

API_KEY = 'YOUR_API_KEY'
API_SECRET = 'YOUR_SECRET'

config = {
    'auth_method': int(time.time() * 1000),
    'time_window': 5000,
}

pub = python_bitbankcc.public()
prv = python_bitbankcc.private(API_KEY, API_SECRET, config=config)


#  ティッカー情報を取得する関数
def get_ticker():
    value = pub.get_ticker(
        pair
    )

    return int(value['last'])


#  指値注文の有無の確認する関数
def order_confirmation():
    global flag, order_list

    try:
        last_price = get_ticker()
        print('最終約定価格:' + str(last_price) + '円')

        for i in range(1, len(order_list) - 1):
            if (order_list.iat[i, 0] >= last_price > order_list.iat[i + 1, 0] and
                    order_list.iat[i + 1, 1] == 0 and
                    order_list.iat[i + 1, 2] == 0):
                flag['order'] = True
                flag['list_number'] = i + 1
                flag['order_price'] = str(order_list.iat[i + 1, 0])

                break

    except python_bitbankcc.utils.BitbankClientError as e:
        print(f'BitbankClientError:{e}')


# 注文を出す関数
def order(order_price, side, number):
    global flag, order_list

    value = prv.order(
        pair,  # ペア
        order_price,  # 価格 (成行注文の場合は None にする)
        amount,  # 注文枚数
        side,  # 注文サイド (buy|sell)
        'limit',  # 注文タイプ (limit|market|stop|stop_limit)
        # 以降は任意の引数
        True  # post_only 注文、デフォは False, None も可能で Falseと同じ挙動

    )
    print(json.dumps(value))

    if side == 'buy':
        flag['order_id'] = value['order_id']
        order_list.iat[flag['list_number'], 3] = value['order_id']
        order_list.iat[flag['list_number'], 1] = 1

    elif side == 'sell':
        order_list.iat[number, 4] = value['order_id']
        order_list.iat[number, 2] = 1

    order_list.to_csv('bitcoin_order_list.csv', index=False)


# 注文情報を取得する関数
def get_order(order_id, number):
    global flag

    try:
        value = prv.get_order(
            pair,
            order_id
        )
        print(json.dumps(value))

        time.sleep(0.2)

    except python_bitbankcc.utils.BitbankClientError as e:
        print(f'BitbankClientError:{e}')

        if '50009' in str(e) is True:
            order_list.iat[number, 2] = 0
            order_list.iat[number, 4] = None

        elif '50026' in str(e) is True:
            order_list.iat[number, 2] = 0
            order_list.iat[number, 4] = None

    except requests.exceptions.ConnectionError as e:
        print(f'ConnectionError:{e}')

        return

    return value['status']


# 注文状況を確認する関数
def order_check():
    global flag, order_list

    order_list = pd.read_csv('bitcoin_order_list.csv')

    for i in range(len(order_list)):
        if order_list.iat[i, 1] == 1:
            stock_status = get_order(str(int(order_list.iat[i, 3])), None)

            if stock_status == 'UNFILLED' or stock_status == 'PARTIALLY_FILLED':
                order_list.iat[i, 1] = 1

            elif stock_status == 'FULLY_FILLED':
                order_list.iat[i, 1] = 0
                order_list.iat[i, 3] = None

                order(str(order_list.iat[i, 0] + profitable_price), 'sell', i)

        if order_list.iat[i, 2] == 1:
            stock_status = get_order(str(int(order_list.iat[i, 4])), i)

            if stock_status == 'UNFILLED' or stock_status == 'PARTIALLY_FILLED':
                order_list.iat[i, 2] = 1

            elif stock_status == 'FULLY_FILLED':
                order_list.iat[i, 2] = 0
                order_list.iat[i, 4] = None

    order_list.to_csv('bitcoin_order_list.csv', index=False)


order_list = pd.read_csv('bitcoin_order_list.csv')

while True:

    order_confirmation()

    if flag['order'] is True:
        order(flag['order_price'], 'buy', None)
        flag['order'] = False
        time.sleep(10)

    order_check()
    time.sleep(10)

ポイントの解説

上記のサンプルコードのポイントについて解説します。

ライブラリのインポート

Python
import time
import requests
import json
import pandas as pd
import python_bitbankcc

まずは必要なライブラリをインポートします。

最後のpython_bitbankccは、前回のビットバンクのAPIキーの発行方法とAPIの使い方を解説でインストール方法を解説しているので、まだインストールしていない場合はインストールをしてください。

設定項目

Python
flag = {
        'order': '',
        'list_number': 0,
        'order_price': '',
        'order_id': ''
        }

pair = 'btc_jpy'  # 取引通貨の設定
profitable_price = 40000  # 利確の価格設定
amount = '0.0001'  # 注文枚数の設定

API_KEY = 'YOUR_API_KEY'
API_SECRET = 'YOUR_SECRET'

config = {
    'auth_method': int(time.time() * 1000),
    'time_window': 5000,
}

pub = python_bitbankcc.public()
prv = python_bitbankcc.private(API_KEY, API_SECRET, config=config)

flagは、注文に必要な情報を一時的に記録するために使用します。

pairは、取り引きする通貨のペアを設定します。今回はビットコインを設定していますが、他の通貨に変更する場合は、公式の通貨ペアを確認してください。

profitable_priceには、購入価格からいくらで利確するかの価格を設定します。今回は40,000円としています。

amountは、購入する数量を設定します。0.0001BTCは、ビットコインの最小注文数量です。リスク許容度に応じて変更してください。

API_KEYAPI_SECRETは、前回のビットバンクのAPIキーの発行方法とAPIの使い方を解説で取得したAPIキーとシークレットを記述してください。

指値注文の有無の確認する関数

Python
#  指値注文の有無の確認する関数
def order_confirmation():
    global flag, order_list

    try:
        last_price = get_ticker()
        print('最終約定価格:' + str(last_price) + '円')

        for i in range(1, len(order_list) - 1):
            if (order_list.iat[i, 0] >= last_price > order_list.iat[i + 1, 0] and
                    order_list.iat[i + 1, 1] == 0 and
                    order_list.iat[i + 1, 2] == 0):
                flag['order'] = True
                flag['list_number'] = i + 1
                flag['order_price'] = str(order_list.iat[i + 1, 0])

                break

    except python_bitbankcc.utils.BitbankClientError as e:
        print(f'BitbankClientError:{e}')

イメージとしては、for文でスプレットシートを上から順番に確認して、最終約定価格の列が「注文なし」の「0」だった場合に、flag['order'] = Trueとして次の関数で注文が出るようにします。同時にflag['order_price'] = str(order_list.iat[i + 1, 0])で、指値注文を出す価格を記録します。

注文を出す関数

Python
# 注文を出す関数
def order(order_price, side, number):
    global flag, order_list

    value = prv.order(
        pair,  # ペア
        order_price,  # 価格 (成行注文の場合は None にする)
        amount,  # 注文枚数
        side,  # 注文サイド (buy|sell)
        'limit',  # 注文タイプ (limit|market|stop|stop_limit)
        # 以降は任意の引数
        True  # post_only 注文、デフォは False, None も可能で Falseと同じ挙動

    )
    print(json.dumps(value))

    if side == 'buy':
        flag['order_id'] = value['order_id']
        order_list.iat[flag['list_number'], 3] = value['order_id']
        order_list.iat[flag['list_number'], 1] = 1

    elif side == 'sell':
        order_list.iat[number, 4] = value['order_id']
        order_list.iat[number, 2] = 1

    order_list.to_csv('bitcoin_order_list.csv', index=False)

注文に必要なパラメーターを設定して指値注文を出します。

買い注文の場合は、order列に「注文あり」の「1」の記入と、buy_id列にorder_idの記録を行います。

売り注文(決済注文)の場合は、stock列に「注文あり」の「1」の記入と、sell_id列にorder_idの記録を行います。

最後にbitcoin_order_list.csvを更新します。

注文情報を取得する関数

Python
# 注文情報を取得する関数
def get_order(order_id, number):
    global flag

    try:
        value = prv.get_order(
            pair,
            order_id
        )
        print(json.dumps(value))

        time.sleep(0.2)

    except python_bitbankcc.utils.BitbankClientError as e:
        print(f'BitbankClientError:{e}')

        if '50009' in str(e) is True:
            order_list.iat[number, 2] = 0
            order_list.iat[number, 4] = None

        elif '50026' in str(e) is True:
            order_list.iat[number, 2] = 0
            order_list.iat[number, 4] = None

    except requests.exceptions.ConnectionError as e:
        print(f'ConnectionError:{e}')

        return

    return value['status']

この関数で発注した注文の状態を確認をします。主な状態を次の表に示します。

注文ステータス意味
INACTIVE非アクティブ
UNFILLED注文中
PARTIALLY_FILLED注文中(一部約定)
FULLY_FILLED約定済み
CANCELED_UNFILLED取消済
CANCELED_PARTIALLY_FILLED取消済(一部約定)

例外処理でブラウザやアプリで誤って注文をキャンセルしてしまった場合でも、プログラムが停止しないようにしています。その他のエラーが発生した場合は、公式のエラーコード一覧から内容を確認して、対処をお願いします。

注文状況を確認する関数

Python
# 注文状況を確認する関数
def order_check():
    global flag, order_list

    order_list = pd.read_csv('bitcoin_order_list.csv')

    for i in range(len(order_list)):
        if order_list.iat[i, 1] == 1:
            stock_status = get_order(str(int(order_list.iat[i, 3])), None)

            if stock_status == 'UNFILLED' or stock_status == 'PARTIALLY_FILLED':
                order_list.iat[i, 1] = 1

            elif stock_status == 'FULLY_FILLED':
                order_list.iat[i, 1] = 0
                order_list.iat[i, 3] = None

                order(str(order_list.iat[i, 0] + profitable_price), 'sell', i)

        if order_list.iat[i, 2] == 1:
            stock_status = get_order(str(int(order_list.iat[i, 4])), i)

            if stock_status == 'UNFILLED' or stock_status == 'PARTIALLY_FILLED':
                order_list.iat[i, 2] = 1

            elif stock_status == 'FULLY_FILLED':
                order_list.iat[i, 2] = 0
                order_list.iat[i, 4] = None

    order_list.to_csv('bitcoin_order_list.csv', index=False)

order_listをfor文で確認をして、注文があれば先程の注文情報を取得する関数で注文ステータスを取得します。

注文が約定していれば、決済注文を出してorder_listの情報を更新します。

決済注文も同様に注文ステータスを取得して、約定していればorder_listの情報を更新します。

メイン処理

Python
order_list = pd.read_csv('bitcoin_order_list.csv')

while True:

    order_confirmation()

    if flag['order'] is True:
        order(flag['order_price'], 'buy', None)
        flag['order'] = False
        time.sleep(10)

    order_check()
    time.sleep(10)

初めにpd.read_csv('bitcoin_order_list.csv')で注文リストを読み出します。途中でプログラムが止まった場合などは、現在の注文状況と注文リストの内容が合うように調整してください。

そしてwhile文で、注文状況を確認して買い注文と決済注文を出す動作を10秒おきに繰り返します。

おわりに

以上でリピート系トレードbotの作成方法の解説は終了です。

リピート系トレードbotは発注した注文の管理が必要なので少し難しく感じるかもしれませんが、プログラムで行っていることはシンプルで、注文を淡々と繰り返す動作になっています。

リピート系トレードはメイカー注文を淡々と繰り返すということで、マイナス手数料を導入しているビットバンクとの相性がいいです。

ビットバンクで口座を開設して、リピート系トレードbotを始めてみてはどうでしょうか。

ビットバンク
bitbank

国内暗号資産取引量No.1

  • 第三者機関に国内No.1と認められた堅牢なセキュリティ対策
  • 高性能APIでシステムトレードが可能
  • メイカー注文による報酬金の獲得が可能