2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SUIのDEX Bluefinで動かすbot

Last updated at Posted at 2024-02-25

SUIのDEX Bluefinで動かすbot

当方プログラミング初学者です。予期せぬエラーが出る可能性もある事、ご理解下さい。

Bluefinでもうbotを動かしていません。変数名やコードは汚いままですが、誰かの参考になればと思い公開しました。

公開に向けて見やすく若干の修正をしましたが、おかしい所がまだあるかと思います。

Bluefin uses USDC.e (bridged USDC) as the primary collateral for the positions on the exchange. This article explains the relationship between USD-denominated instruments and USDC.e margin on Bluefin and how the risk engine functions in the event of a USDC depeg from USD. Throughout the article, USDC is assumed to mean USDC.e.

注意
上記原文にある通り、USDC.eとUSDがデペグするリスク。又、取引所が閉鎖やハッキング等さまざまなリスクがあります。取引所固有の仕様を理解し、利用して下さい。

githubにインストール方法が記載されています。
ターミナル等でpipして下さい。

コードを実行する場合、全て自己責任でお願い致します。
本記事は教育目的での共有であり、投資を勧誘するものではありません。
利益が出るbotではありません。損失が出る事を理解して下さい。

以下コード

btc.py
from config import TEST_ACCT_KEY, TEST_NETWORK
from bluefin_v2_client import BluefinClient, Networks, MARKET_SYMBOLS, ORDER_STATUS
from pprint import pprint
import asyncio
import sys
import time
from rich import print
from config import TEST_ACCT_KEY, TEST_NETWORK
from bluefin_v2_client import (
    BluefinClient,
    Networks,
    MARKET_SYMBOLS,
    ORDER_SIDE,
    ORDER_TYPE,
    OrderSignatureRequest,
    ORDER_STATUS,
)

if sys.platform == "win32":
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())


async def calculate_order_prices(
    client: BluefinClient, multiplier: float
):
    # マーケットの最終価格を取得
    market_data = await client.get_market_data(MARKET_SYMBOLS.BTC)
    last_price_wei = int(market_data["lastPrice"])
    last_price_BTC = last_price_wei / 1e18
    last_price_BTC_rounded = round(last_price_BTC, 1)

    # 注文価格を計算
    order_price = round(last_price_BTC_rounded * multiplier, 1)
    return order_price


async def cancel_orders(client: BluefinClient, orders: list):
    for order_hash in orders:
        cancellation_request = client.create_signed_cancel_orders(
            MARKET_SYMBOLS.BTC, [order_hash]
        )
        cancel_resp = await client.post_cancel_order(cancellation_request)
        pprint({"msg": f"Cancelling order {order_hash}", "resp": cancel_resp})




async def check_position2(client: BluefinClient, symbol):
    # BluefinClientを使用してポジション情報を取得
    position = await client.get_user_position({"symbol": symbol})
    print(f"Position: {position}")
    # 初期化されたポジションデータ
    default_position_data = {"side": "NONE", "size": 0, "pnl": 0, "avg_entry_price": 0}
    # ポジション情報が存在する場合、実際のデータを使用
    if position:
        size = float(position.get("quantity", "0")) / 1e18
        unrealized_pnl = float(position.get("unrealizedProfit", "0")) / 1e18
        avg_entry_price = float(position.get("avgEntryPrice", "0")) / 1e18
        side = position.get("side", "NONE")  # レスポンスから直接 'side' の値を取得
        return {
            "side": side,
            "size": size,
            "pnl": unrealized_pnl,
            "avg_entry_price": avg_entry_price,
        }
    else:
        # ポジションが存在しない場合、初期化されたデータを返す
        return default_position_data


async def buy_place_orders(client: BluefinClient, price: float, quantity: float):
    adjusted_leverage = 20
    signature_request = OrderSignatureRequest(
        symbol=MARKET_SYMBOLS.BTC,  # market symbol
        price=price,  # 使用する price 変数
        quantity=quantity,  # 使用する quantity 変数
        side=ORDER_SIDE.BUY,
        orderType=ORDER_TYPE.LIMIT,
        leverage=adjusted_leverage,
        expiration=int(
            (time.time() + 864000) * 1000
        ),  # expiry after 10 days, default expiry is a month
    )
    signed_order = client.create_signed_order(signature_request)
    resp = await client.post_signed_order(signed_order)
    pprint({"msg": "placing limit order", "resp": resp})
    return


async def sell_place_orders(client: BluefinClient, price: float, quantity: float):
    adjusted_leverage = 20
    signature_request = OrderSignatureRequest(
        symbol=MARKET_SYMBOLS.BTC,  # market symbol
        price=price,  # 使用する price 変数
        quantity=quantity,  # 使用する quantity 変数
        side=ORDER_SIDE.SELL,
        orderType=ORDER_TYPE.LIMIT,
        leverage=adjusted_leverage,
        expiration=int(
            (time.time() + 864000) * 1000
        ),  # expiry after 10 days, default expiry is a month
    )
    signed_order = client.create_signed_order(signature_request)
    resp = await client.post_signed_order(signed_order)
    pprint({"msg": "placing limit order", "resp": resp})
    return


async def main(client):
    global order_price, symbol
    multiplier = 0.9995
    size_multiplier = 0.001
    symbol = MARKET_SYMBOLS.BTC

    # クライアントを初期化
    client = BluefinClient(True, Networks[TEST_NETWORK], TEST_ACCT_KEY)
    await client.init(True)
    # オーダーのキャンセル
    orders = await client.get_orders(
        {
            "symbol": MARKET_SYMBOLS.BTC,
            "statuses": [ORDER_STATUS.OPEN, ORDER_STATUS.PENDING],
        }
    )
    order_hashes = [order["hash"] for order in orders]
    print("Cancelling orders:", order_hashes)
    await cancel_orders(client, order_hashes)
    # 注文価格の計算
    order_price = await calculate_order_prices(client, multiplier)
    print(f"Order Price 1: {order_price}")
    # ポジションの確認
    position_info = await check_position2(client, MARKET_SYMBOLS.BTC)
    # BUYポジションがある場合の処理
    if position_info["side"] == "BUY":
        sell_size = abs(position_info["size"])
        close_price_sell = order_price * 1.0001  # エントリー価格よりも1%高く設定
        close_price_sell = round(close_price_sell, 1)
        await sell_place_orders(client, close_price_sell, sell_size)
        print(f"sell_size 1: {sell_size}))")
    # SELLポジションがある場合の処理
    if position_info["side"] == "SELL":
        buy_size = abs(position_info["size"])
        print(f"buy_size 1: {buy_size}))")
        close_price = order_price * 0.99  # エントリー価格よりも1%低く設定
        close_price = round(close_price, 1)
        await buy_place_orders(client, close_price, buy_size)
        print(f" Price 1: {close_price}))")
    # ポジションがない場合の処理
    if position_info["side"] == "NONE":
        # ポジションがない場合の処理をここに記述
        buy_size = abs(size_multiplier)
        order_price1_ = order_price * 0.9996  # エントリー価格よりも1%低く設定
        order_price1_ = round(order_price1_, 1)
        await buy_place_orders(client, order_price1_, buy_size)
        print(f"Order Price 1: {order_price1_}))")
        pass
    else:
        print("No position info found")


async def main_loop():
    client = BluefinClient(True, Networks[TEST_NETWORK], TEST_ACCT_KEY)
    await client.init(True)

    try:
        while True:
            await main(client)
            await asyncio.sleep(6)
    except KeyboardInterrupt:
        print("Interrupted by user, exiting...")
    finally:
        await client.close()  # ここでクライアントセッションを閉じる


if __name__ == "__main__":
    asyncio.run(main_loop())


eth.py
from config import TEST_ACCT_KEY, TEST_NETWORK
from bluefin_v2_client import BluefinClient, Networks, MARKET_SYMBOLS, ORDER_STATUS
from pprint import pprint
import asyncio
import sys
import time
from rich import print
from config import TEST_ACCT_KEY, TEST_NETWORK
from bluefin_v2_client import (
    BluefinClient,
    Networks,
    MARKET_SYMBOLS,
    ORDER_SIDE,
    ORDER_TYPE,
    OrderSignatureRequest,
    ORDER_STATUS,
)

if sys.platform == "win32":
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    
    
async def calculate_order_prices(client: BluefinClient, multiplier1: float, multiplier2: float):
    # マーケットの最終価格を取得
    market_data = await client.get_market_data(MARKET_SYMBOLS.ETH)
    last_price_wei = int(market_data["lastPrice"])
    last_price_ETH = last_price_wei / 1e18
    last_price_ETH_rounded = round(last_price_ETH, 1)
    
    # 注文価格を計算
    order_price1 = round(last_price_ETH_rounded * multiplier1, 1)
    order_price2 = round(last_price_ETH_rounded * multiplier2, 1)
    
    return order_price1, order_price2


async def cancel_orders(client: BluefinClient, orders: list):
    for order_hash in orders:
        cancellation_request = client.create_signed_cancel_orders(
            MARKET_SYMBOLS.ETH, [order_hash]
        )
        cancel_resp = await client.post_cancel_order(cancellation_request)
        pprint({"msg": f"Cancelling order {order_hash}", "resp": cancel_resp})


async def check_position2(client: BluefinClient, symbol):
    # BluefinClientを使用してポジション情報を取得
    position = await client.get_user_position({"symbol": symbol})
    print(f"Position: {position}")
    # 初期化されたポジションデータ
    default_position_data = {'side': 'NONE', 'size': 0, 'pnl': 0, 'avg_entry_price': 0}
    # ポジション情報が存在する場合、実際のデータを使用
    if position:
        size = float(position.get("quantity", "0")) / 1e18
        unrealized_pnl = float(position.get("unrealizedProfit", "0")) / 1e18
        avg_entry_price = float(position.get("avgEntryPrice", "0")) / 1e18
        side = position.get("side", "NONE")  # レスポンスから直接 'side' の値を取得
        return {'side': side, 'size': size, 'pnl': unrealized_pnl, 'avg_entry_price': avg_entry_price}
    else:
        # ポジションが存在しない場合、初期化されたデータを返す
        return default_position_data



async def buy_place_orders(client: BluefinClient, price: float, quantity: float):
    adjusted_leverage = 20
    signature_request = OrderSignatureRequest(
        symbol=MARKET_SYMBOLS.ETH,  # market symbol
        price=price,  # 使用する price 変数
        quantity=quantity,  # 使用する quantity 変数
        side=ORDER_SIDE.BUY,
        orderType=ORDER_TYPE.LIMIT,
        leverage=adjusted_leverage,
        expiration=int(
            (time.time() + 864000) * 1000
        ),  # expiry after 10 days, default expiry is a month
    )
    signed_order = client.create_signed_order(signature_request)
    resp = await client.post_signed_order(signed_order)
    pprint({"msg": "placing limit order", "resp": resp})
    return

async def sell_place_orders(client: BluefinClient, price: float, quantity: float):
    adjusted_leverage = 20
    signature_request = OrderSignatureRequest(
        symbol=MARKET_SYMBOLS.ETH,  # market symbol
        price=price,  # 使用する price 変数
        quantity=quantity,  # 使用する quantity 変数
        side=ORDER_SIDE.SELL,
        orderType=ORDER_TYPE.LIMIT,
        leverage=adjusted_leverage,
        expiration=int(
            (time.time() + 864000) * 1000
        ),  # expiry after 10 days, default expiry is a month
    )
    signed_order = client.create_signed_order(signature_request)
    resp = await client.post_signed_order(signed_order)
    pprint({"msg": "placing limit order", "resp": resp})
    return

async def main(client):
    global order_price1, order_price2, symbol
    multiplier1 = 0.9995
    multiplier2 = 0.995
    size_multiplier = 0.02
    symbol = MARKET_SYMBOLS.ETH

    # クライアントを初期化
    client = BluefinClient(True, Networks[TEST_NETWORK], TEST_ACCT_KEY)
    await client.init(True)
    # オーダーのキャンセル
    orders = await client.get_orders(
        {"symbol": MARKET_SYMBOLS.ETH, "statuses": [ORDER_STATUS.OPEN, ORDER_STATUS.PENDING]}
    )
    order_hashes = [order["hash"] for order in orders]
    print("Cancelling orders:", order_hashes)
    await cancel_orders(client, order_hashes)
# 注文価格の計算
    order_price1, order_price2 = await calculate_order_prices(client, multiplier1, multiplier2)
    print(f"Order Price 1: {order_price1}, Order Price 2: {order_price2}")
    # ポジションの確認
    position_info = await check_position2(client, MARKET_SYMBOLS.ETH)
    avg_entry_price = position_info['avg_entry_price']
    if position_info['side'] == "BUY":
        sell_size = abs(position_info['size'])
        close_price_sell = order_price2 * 1.01  # エントリー価格よりも1%高く設定
        close_price_sell = round(close_price_sell, 2)
        await sell_place_orders(client, close_price_sell, sell_size)
        print(f"sell_size 1: {sell_size}))")
    if position_info['side'] == "SELL":
        buy_size = abs(position_info['size'])
        print(f"buy_size 1: {buy_size}))")
        close_price = order_price1 * 0.9995  # エントリー価格よりも1%低く設定
        close_price = round(close_price, 2)
        await buy_place_orders(client, close_price, buy_size)
        print(f" Price 1: {close_price}))")
    if position_info['side'] == "NONE":
        # ポジションがない場合の処理をここに記述
        buy_size = abs(size_multiplier)
        order_price1_ = order_price1 * 0.9996  # エントリー価格よりも1%低く設定
        order_price1_ = round(order_price1_, 2)
        await buy_place_orders(client, order_price1_, buy_size)
        print(f"Order Price 1: {order_price1_}))")
        pass
    else:
        print("No position info found")
        
async def main_loop():
    client = BluefinClient(True, Networks[TEST_NETWORK], TEST_ACCT_KEY)
    await client.init(True)

    try:
        while True:
            await main(client)
            await asyncio.sleep(6)
    except KeyboardInterrupt:
        print("Interrupted by user, exiting...")
    finally:
        await client.close()  # ここでクライアントセッションを閉じる
if __name__ == "__main__":
    asyncio.run(main_loop())


sui.py
from config import TEST_ACCT_KEY, TEST_NETWORK
from bluefin_v2_client import BluefinClient, Networks, MARKET_SYMBOLS, ORDER_STATUS
from pprint import pprint
import asyncio
import sys
import time
from rich import print
from config import TEST_ACCT_KEY, TEST_NETWORK
from bluefin_v2_client import (
    BluefinClient,
    Networks,
    MARKET_SYMBOLS,
    ORDER_SIDE,
    ORDER_TYPE,
    OrderSignatureRequest,
    ORDER_STATUS,
)

if sys.platform == "win32":
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    
    
async def calculate_order_prices(client: BluefinClient, multiplier1: float, multiplier2: float):
    # マーケットの最終価格を取得
    market_data = await client.get_market_data(MARKET_SYMBOLS.SUI)
    last_price_wei = int(market_data["lastPrice"])
    last_price_SUI = last_price_wei / 1e18
    last_price_SUI_rounded = round(last_price_SUI, 1)
    
    # 注文価格を計算
    order_price1 = round(last_price_SUI_rounded * multiplier1, 1)
    order_price2 = round(last_price_SUI_rounded * multiplier2, 1)
    
    return order_price1, order_price2


async def cancel_orders(client: BluefinClient, orders: list):
    for order_hash in orders:
        cancellation_request = client.create_signed_cancel_orders(
            MARKET_SYMBOLS.SUI, [order_hash]
        )
        cancel_resp = await client.post_cancel_order(cancellation_request)
        pprint({"msg": f"Cancelling order {order_hash}", "resp": cancel_resp})

async def check_position2(client: BluefinClient, symbol):
    # BluefinClientを使用してポジション情報を取得
    position = await client.get_user_position({"symbol": symbol})
    print(f"Position: {position}")
    # 初期化されたポジションデータ
    default_position_data = {'side': 'NONE', 'size': 0, 'pnl': 0, 'avg_entry_price': 0}
    # ポジション情報が存在する場合、実際のデータを使用
    if position:
        size = float(position.get("quantity", "0")) / 1e18
        unrealized_pnl = float(position.get("unrealizedProfit", "0")) / 1e18
        avg_entry_price = float(position.get("avgEntryPrice", "0")) / 1e18
        side = position.get("side", "NONE")  # レスポンスから直接 'side' の値を取得
        return {'side': side, 'size': size, 'pnl': unrealized_pnl, 'avg_entry_price': avg_entry_price}
    else:
        # ポジションが存在しない場合、初期化されたデータを返す
        return default_position_data



async def buy_place_orders(client: BluefinClient, price: float, quantity: float):
    adjusted_leverage = 10
    signature_request = OrderSignatureRequest(
        symbol=MARKET_SYMBOLS.SUI,  # market symbol
        price=price,  # 使用する price 変数
        quantity=quantity,  # 使用する quantity 変数
        side=ORDER_SIDE.BUY,
        orderType=ORDER_TYPE.LIMIT,
        leverage=adjusted_leverage,
        expiration=int(
            (time.time() + 864000) * 1000
        ),  # expiry after 10 days, default expiry is a month
    )
    signed_order = client.create_signed_order(signature_request)
    resp = await client.post_signed_order(signed_order)
    pprint({"msg": "placing limit order", "resp": resp})
    return

async def sell_place_orders(client: BluefinClient, price: float, quantity: float):
    adjusted_leverage = 10
    signature_request = OrderSignatureRequest(
        symbol=MARKET_SYMBOLS.SUI,  # market symbol
        price=price,  # 使用する price 変数
        quantity=quantity,  # 使用する quantity 変数
        side=ORDER_SIDE.SELL,
        orderType=ORDER_TYPE.LIMIT,
        leverage=adjusted_leverage,
        expiration=int(
            (time.time() + 864000) * 1000
        ),  # expiry after 10 days, default expiry is a month
    )
    signed_order = client.create_signed_order(signature_request)
    resp = await client.post_signed_order(signed_order)
    pprint({"msg": "placing limit order", "resp": resp})
    return

async def main(client):
    global order_price1, order_price2, symbol
    multiplier1 = 0.9995
    multiplier2 = 0.9
    size_multiplier = 10
    symbol = MARKET_SYMBOLS.SUI

    # クライアントを初期化
    client = BluefinClient(True, Networks[TEST_NETWORK], TEST_ACCT_KEY)
    await client.init(True)
    # オーダーのキャンセル
    orders = await client.get_orders(
        {"symbol": MARKET_SYMBOLS.SUI, "statuses": [ORDER_STATUS.OPEN, ORDER_STATUS.PENDING]}
    )
    order_hashes = [order["hash"] for order in orders]
    print("Cancelling orders:", order_hashes)
    await cancel_orders(client, order_hashes)
# 注文価格の計算
    order_price1, order_price2 = await calculate_order_prices(client, multiplier1, multiplier2)
    print(f"Order Price 1: {order_price1}, Order Price 2: {order_price2}")
    # ポジションの確認
    position_info = await check_position2(client, MARKET_SYMBOLS.SUI)
    avg_entry_price = position_info['avg_entry_price']
    if position_info['side'] == "BUY":
        sell_size = abs(position_info['size'])
        close_price_sell = order_price2 * 1.0001  # エントリー価格よりも1%高く設定
        close_price_sell = round(close_price_sell, 4)
        await sell_place_orders(client, close_price_sell, sell_size)
        print(f"sell_size 1: {sell_size}))")
    if position_info['side'] == "SELL":
        buy_size = abs(position_info['size'])
        print(f"buy_size 1: {buy_size}))")
        close_price = order_price1 * 0.9995  # エントリー価格よりも1%低く設定
        close_price = round(close_price, 4)
        await buy_place_orders(client, close_price, buy_size)
        print(f" Price 1: {close_price}))")
    if position_info['side'] == "NONE":
        # ポジションがない場合の処理をここに記述
        buy_size = abs(size_multiplier)
        order_price1_ = order_price1 * 0.9994  # エントリー価格よりも1%低く設定
        order_price1_ = round(order_price1_, 4)
        await buy_place_orders(client, order_price1_, buy_size)
        print(f"Order Price 1: {order_price1_}))")
        pass
    else:
        print("No position info found")
        
async def main_loop():
    client = BluefinClient(True, Networks[TEST_NETWORK], TEST_ACCT_KEY)
    await client.init(True)

    try:
        while True:
            await main(client)
            await asyncio.sleep(6)
    except KeyboardInterrupt:
        print("Interrupted by user, exiting...")
    finally:
        await client.close()  # ここでクライアントセッションを閉じる
if __name__ == "__main__":
    asyncio.run(main_loop())



main.py

import argparse
import subprocess
import time
from threading import Thread

stop_threads = False  # スレッドを終了させるフラグ

def monitor_program(cmd, check_interval):
    global stop_threads
    while not stop_threads:
        print(f"Starting {cmd}")
        proc = subprocess.Popen(cmd, shell=True)
        while proc.poll() is None and not stop_threads:  # プロセスが実行中かつ停止フラグが立っていない間ループ
            time.sleep(check_interval)
        if not stop_threads:
            print(f"{cmd} stopped unexpectedly. Restarting...")
        proc.terminate()  # プロセスを終了

def main(check_interval=60):
    global stop_threads
    cmds = [
        f'C:/Users/Local/Programs/Python/Python39/python.exe btc.py', #BTC
        f'C:/Users/Local/Programs/Python/Python39/python.exe eth.py', #ETH
        f'C:/Users/Local/Programs/Python/Python39/python.exe sui.py', #SUI
        #f'C:/Users/Local/Programs/Python/Python39/python.exe sol.py' #SOL
    ]
    threads = [Thread(target=monitor_program, args=(cmd, check_interval)) for cmd in cmds]
    for t in threads:
        t.start()
    try:
        while any(t.is_alive() for t in threads):
            time.sleep(0.1)
    except KeyboardInterrupt:
        print("\nKeyboardInterrupt detected. Stopping all threads...")
        stop_threads = True
        for t in threads:
            t.join()  # スレッドの終了を待つ
        print("All threads have been stopped. Exiting program.")

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-ci', '--check_interval', type=int, default=10)  # 監視間隔をデフォルトで10秒に設定
    args = parser.parse_args()
    main(args.check_interval)
config.py
TEST_ACCT_KEY = "この中にウォレットの秘密鍵"  # public key 
TEST_NETWORK = "SUI_PROD"

githubでDLしたbluefin-v2-client-pythonフォルダに各プログラムをコピペしてください。
一つの通貨だけで動かしたい時はcmdsの各プログラムをコメントアウトして起動出来ます。
botを動かしたい時はコマンドプロンプトでbluefin-v2-client-pythonに移動後
python main.pyを入力する事で起動できます。

python main.py

f'C:/Users/Local/Programs/Python/Python39/python.exe btc.py',
上記部分の
f'C:/Users/Local/Programs/Python/Python39/python.exe
この部分には仮想環境、またはローカルのPythonインストール先を指定してください。

ロジックは現在価格に0.99等かけた価格に買い指値を出し、1.001等かけた売り注文を出します。各自で好きな指値位置に微調整した方が良いです。コードが悪いorAPIの反映に遅延する事があり(自分のPCが原因かも)想定ポジションより多く持つ事があるので、少ない注文量にしてください。

Sui Walletの秘密鍵は作成時にしか見れない様なので注意してください。

基本的な動作確認しか出来ていません。何か分からない事があれば聞いて下さい。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?