Bot

仮想通貨botの開発を本格的に始めてみる#35(2023/11/24)「サーキットブレーカーbotの開発②」

2023年11月24日

前回の記事に引き続き、今回も仮想通貨botの開発状況をまとめていきます。

前回の記事で作ったBotの問題点を解消したコードを作りました。

簡単に言うと「価格が20%以上変動したタイミングを見て注文を出す」ように条件付けしています。

また、「すでに注文を出している時には新たに注文を出さない」ようにしています。

サーキットブレーカーBot2

ChatGPTに出した指示は以下の3つ。

Yodaka

上記のコードでは、現在の価格に反応して注文を発生させてしまうのではないか。 価格が20%変動した時に買い注文や売り注文を出すコードにするにはどうすれば良いか。

Yodaka

「price_change_ratioが20%以上の時」に条件変更しなさい。

Yodaka

上記のコードで買い注文か売り注文を持っている時は、新たに買いと売りの注文を出さないようにしたい。どうすれば良いか。

作成されたのが以下のコードです。

import ccxt
import datetime
import time

# APIキーとAPIシークレットを直接設定
api_key = 'Your API KEY'
api_secret = 'Your API SECRET'

bitflyer = ccxt.bitflyer({
    'apiKey': api_key,
    'secret': api_secret,
})

symbol = 'FX_BTC_JPY'

def get_current_price():
    ticker = bitflyer.fetch_ticker(symbol)
    return ticker['last']

def close_order(order_id):
    try:
        bitflyer.cancel_order(order_id, symbol)
        print(f"注文 {order_id} が手仕舞いされました。")
    except ccxt.NetworkError as e:
        print(f"手仕舞いエラー(ネットワークエラー): {str(e)}")
    except ccxt.ExchangeError as e:
        print(f"手仕舞いエラー(取引所エラー): {str(e)}")
    except Exception as e:
        print(f"手仕舞いエラー(その他のエラー): {str(e)}")

# メインのループ処理
buy_order = None
sell_order = None

while True:
    try:
        closest_diff = 1000000000
        closest_num = 0

        # 現在のUNIXタイムスタンプを取得
        current_time = datetime.datetime.now().timestamp()

        # 10分前のUNIXタイムスタンプを計算
        ten_minutes_ago = current_time - 600

        # 約定履歴を取得
        trades = bitflyer.fetch_trades(symbol, limit=500)
        for i in range(len(trades)):
            time_diff = (trades[i]["timestamp"] - ten_minutes_ago * 1000) / 1000
            if abs(time_diff) < closest_diff:
                closest_diff = abs(time_diff)
                closest_num = i

        past_price = trades[closest_num]["price"]

        current_price = get_current_price()

        # 注文を作成する条件: 過去の価格と現在の価格が20%以上の変動率を超えた場合に注文を作成する
        price_change_ratio = (current_price - past_price) / past_price
        if abs(price_change_ratio) > 0.2:  # 例: 価格変動率が20%以上の場合

            # 既に買い注文が存在しない場合に注文を作成
            if buy_order is None:
                buy_price = int(current_price * 0.8)
                buy_order = bitflyer.create_order(symbol, "limit", "buy", 0.01, buy_price)
                print("買い注文が発注されました.")

            # 既に売り注文が存在しない場合に注文を作成
            if sell_order is None:
                sell_price = int(current_price * 1.2)
                sell_order = bitflyer.create_order(symbol, "limit", "sell", 0.01, sell_price)
                print("売り注文が発注されました.")

            while True:
                time.sleep(5)  # 注文が発注されてから手仕舞いを試みるまでの待機時間
                current_price = get_current_price()

                # 利益率が一定の閾値を超えた場合に手仕舞いを試みる
                if (current_price - past_price) / past_price > 0.15:  # 例: 利益率がX%以上の場合
                    close_order(buy_order['id'])
                    close_order(sell_order['id'])
                    break  # 手仕舞いが成功したらループを抜ける

    except ccxt.NetworkError as e:
        print(f"ネットワークエラーが発生しました: {str(e)}")
        time.sleep(5)
    except ccxt.ExchangeError as e:
        print(f"取引所エラーが発生しました: {str(e)}")

        # 取引所エラーの場合、エラーメッセージを表示
        print(f"取引所エラーメッセージ: {e}")

        time.sleep(5)
    except Exception as e:
        print(f"予期せぬエラーが発生しました: {str(e)}")
        time.sleep(5)

このコードを実行しても、現在の相場では直ちに注文が出ることはありませんでした。

ひとまず、条件分岐については成功したと言って良いでしょう。

ただ、実際に稼働させる際は、変動率20%まで粘らなくても良いのかもしれません。

設定してある数値price_change_ratioを19%程度に設定しておくことで、早めの注文を出すということもできそうです。

また、手仕舞いの条件も20%全てが戻った時ではなく、15%に設定して利益を出しやすくしています。

サーキットブレーカーは発生タイミングが読めないため、手仕舞いまで確実にBotに行わせるのが良いと思います。

この辺りはリスク要因にもなるため、慎重に試していこうと思います。

まとめ

注文を出す時と手仕舞いの条件分岐を設定しました。

実際に稼働させて、効果を検証していきます。

この調子でコツコツと学習を進めていきます。

-Bot