Bot トレードロジック

仮想通貨botの開発記録#86(2024/8/1)「発展的な取引ロジックの雛形まとめ①」

2024年8月1日

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

Yodaka

今回は5種類の発展的な取引ロジックの雛形をまとめました。

実際にbotで取引をしてみたいけれど、どんなコードを書いたら良いのか分からないという方の参考になると思います。

1.マーケットメイキングの最適化

Yodaka

スプレッド収益とポジションリスクのトレードオフを最適化することを狙うbotです。

マーケットメイキングの戦略では、効率的なスプレッド設定とポジションリスクの管理が非常に重要です。ここではPythonを使って、スプレッド収益とポジションリスクのトレードオフを最適化する基本的なマーケットメイキングのコードを示します。

必要なライブラリのインポート

import ccxt
import numpy as np
import time

取引所の設定と初期化

exchange = ccxt.binance({
    'apiKey': 'YOUR_API_KEY',
    'secret': 'YOUR_API_SECRET',
    'enableRateLimit': True
})
symbol = 'BTC/USDT'

スプレッドとリスクの管理

マーケットメイカーとしての主なタスクは、適切なスプレッドを設定し、取引量を管理して市場への影響を最小限に抑えることです。ここでは、動的にスプレッドを調整し、ポジションリスクを管理する方法を紹介します。

def calculate_optimal_spread(order_book, target_return=0.001, risk_aversion=0.01):
    """オーダーブックから最適なスプレッドを計算"""
    best_bid = order_book['bids'][0][0] if order_book['bids'] else None
    best_ask = order_book['asks'][0][0] if order_book['asks'] else None
    if best_bid and best_ask:
        mid_price = (best_bid + best_ask) / 2
        spread = best_ask - best_bid
        optimal_spread = spread * (target_return / risk_aversion)
        return max(spread, optimal_spread), mid_price
    else:
        return None, None

def manage_inventory(position_size, max_position):
    """ポジションサイズに基づいてリスクを管理"""
    if abs(position_size) > max_position:
        return -position_size  # ポジションのリバランス
    return 0

マーケットメイキングの実行

def market_making(exchange, symbol):
    """マーケットメイキングの実行"""
    position_size = 0  # 現在のポジションサイズ
    max_position = 1   # 最大ポジションサイズ(BTCで例示)

    while True:
        order_book = exchange.fetch_order_book(symbol)
        optimal_spread, mid_price = calculate_optimal_spread(order_book)
        
        if optimal_spread is not None:
            # 買い注文と売り注文をセット
            buy_price = mid_price - optimal_spread / 2
            sell_price = mid_price + optimal_spread / 2
            
            print(f"Placing buy order at: {buy_price}, sell order at: {sell_price}")
            # 以下のコードは実際には取引所に注文を出すコードに置き換える
            # exchange.create_limit_buy_order(symbol, amount, buy_price)
            # exchange.create_limit_sell_order(symbol, amount, sell_price)

            # ポジション管理
            adjustment = manage_inventory(position_size, max_position)
            if adjustment:
                print(f"Adjusting position by {adjustment} BTC")
                # 実際のポジション調整の取引を行う
            
        time.sleep(10)  # ループの待機時間(秒)

if __name__ == '__main__':
    market_making(exchange, symbol)

注意点

  • 市場条件の変化: 市場の状態が変化すると、最適なスプレッドやリスク管理戦略も変わります。市場を常に監視し、適応する必要があります。
  • API制限: 取引所のAPI使用制限を超えないように注意してください。
  • シミュレーションと実際の取引: 実際の資金を使う前に、シミュレーション環境で戦略をテストすることをお勧めします。

このスクリプトは、スプレッド収益とポジションリスクのトレードオフを最適化するマーケットメイキング戦略の基本的な構造を示していますが、実際の取引にはさらに詳細な調整が必要です。

2.注文戦略の組み合わせ

Yodaka

アグレッシブ注文とパッシブ注文を組み合わせて最適化することを狙うbotです。

注文戦略の組み合わせ、特にアグレッシブ(積極的)注文とパッシブ(受動的)注文のバランスを取ることは、市場の流動性と自身の取引目標に応じて最適化することが重要です。以下のPythonコードでは、アグレッシブ注文を使用して即時に市場にポジションを取り、パッシブ注文を使用してより良い価格で取引を行う戦略を実装します。

解説

金融市場における「アグレッシブ注文(Aggressive Order)」と「パッシブ注文(Passive Order)」は、トレーダーの取引戦略や市場での役割を示す用語です。これらの注文の違いは、主に市場への即時の影響と、注文が市場価格に対してどのように設定されるかに基づいています。

アグレッシブ注文(Aggressive Orders)

アグレッシブ注文は、市場の流動性を「取る」(liquidity taker)注文とも呼ばれます。この種の注文は、即時に執行されることを目的としており、通常、現在の市場価格(買いの場合は最低の売り注文の価格、売りの場合は最高の買い注文の価格)に合わせて設定されます。

  • 特徴:
    • 市場価格で直ちに取引を完了させる。
    • スリッページ(注文が意図した価格と異なる価格で執行されること)のリスクが高い。
    • 市場の流動性を減少させる効果がある。
  • 使用例:
    • 急速に変動する市場で素早くポジションを取る場合。
    • 確実にポジションを確保または解消したい場合。

パッシブ注文(Passive Orders)

パッシブ注文は、市場の流動性を「与える」(liquidity provider)注文です。これらの注文は、市場価格から離れた価格で設定され、注文が執行されるのを待つため、即座には執行されません。

  • 特徴:
    • 指値注文(Limit Order)として設定され、特定の価格またはそれよりも良い条件でのみ取引が行われる。
    • スリッページのリスクが低い。
    • 市場に流動性を提供する効果がある。
  • 使用例:
    • 指定した価格で厳密に取引を行いたい場合。
    • 市場の一時的な価格変動を利用して利益を得る戦略。

市場での役割と戦略

アグレッシブ注文は、トレーダーが市場の動きに迅速に対応したい場合や、確実に取引を実行したい場合に適しています。一方、パッシブ注文は価格の制御が重要な場合や、市場の一時的な不均衡を利用したい場合に有効です。どちらの注文タイプも、トレーダーの市場に対するアプローチやリスク許容度、取引戦略によって選ばれます。

グレッシブ注文とパッシブ注文を組み合わせて利益を上げることは可能です。これらの注文タイプを上手く活用することで、市場の変動を利用し、リスクを管理しながら取引戦略を最適化できます。以下に、アグレッシブ注文とパッシブ注文を組み合わせて利益を上げるための一般的な戦略をいくつか紹介します。

戦略1: スケーリングインとスケーリングアウト

トレーダーは、ポジションを段階的に構築(スケーリングイン)または解消(スケーリングアウト)するために、パッシブ注文を利用することがあります。例えば、ある資産の価格が下がると予想される場合、パッシブ注文を使って安い価格で少量ずつ購入し、価格が再び上昇した時にアグレッシブ注文を使ってすぐに全量を売却することで利益を得ることができます。

戦略2: マーケットメイキング

マーケットメイキングは、買値と売値の間のスプレッドを利用して利益を得る戦略です。トレーダーはパッシブ注文を使って低い価格で購入し、高い価格で売却する注文を同時に出します。市場がこれらの注文に到達すると、スプレッドの差額が利益となります。市場の変動に応じて、アグレッシブ注文を使って即座にポジションを閉じることも可能です。

戦略3: トレンドフォローとリバウンド取引

トレンドフォロー戦略では、市場の主要な動きに追随するためにアグレッシブ注文を使用しますが、一定のポイントでリバウンド(価格の反転)が予想される場合、パッシブ注文を設定して、より有利な価格で取引を行うことができます。この戦略では、アグレッシブ注文で迅速に市場に参入し、パッシブ注文で利益を最大化するためのポジションを確保します。

戦略4: ボラティリティ取引

高いボラティリティの期間には、アグレッシブ注文を使って迅速に市場に参入・退出し、パッシブ注文を使って指定した価格でポジションを保持することが可能です。この方法では、価格の急激な変動を利用して、短期間で利益を上げることができます。

これらの戦略は、市場の動向を正確に理解し、適切なリスク管理を行うことが成功の鍵となります。また、各戦略のリスクとリターンを慎重に評価し、自身の取引スタイルや資本に適した方法を選択することが重要です。

必要なライブラリのインポート

import ccxt
import time

取引所の設定と初期化

exchange = ccxt.binance({
    'apiKey': 'YOUR_API_KEY',
    'secret': 'YOUR_API_SECRET',
    'enableRateLimit': True
})
symbol = 'BTC/USDT'

アグレッシブ注文とパッシブ注文の実行関数

def execute_aggressive_order(exchange, symbol, amount, order_type):
    """アグレッシブ注文を実行"""
    if order_type == 'buy':
        order = exchange.create_market_buy_order(symbol, amount)
    else:
        order = exchange.create_market_sell_order(symbol, amount)
    print(f"Executed {order_type} aggressive order for {amount} {symbol}")
    return order

def execute_passive_order(exchange, symbol, amount, order_type, target_price):
    """パッシブ注文を設定"""
    if order_type == 'buy':
        order = exchange.create_limit_buy_order(symbol, amount, target_price)
    else:
        order = exchange.create_limit_sell_order(symbol, amount, target_price)
    print(f"Placed {order_type} passive order for {amount} {symbol} at {target_price}")
    return order

def optimal_order_strategy(exchange, symbol, amount, target_price):
    """最適な注文戦略を実行"""
    # 市場の現在価格を取得
    ticker = exchange.fetch_ticker(symbol)
    current_price = ticker['last']

    # 現在の価格が目標価格よりも良い場合はアグレッシブ注文を使用
    if (target_price >= current_price and amount > 0) or (target_price <= current_price and amount < 0):
        execute_aggressive_order(exchange, symbol, abs(amount), 'buy' if amount > 0 else 'sell')
    else:
        # 目標価格に到達するのを待つパッシブ注文
        execute_passive_order(exchange, symbol, abs(amount), 'buy' if amount > 0 else 'sell', target_price)

def main():
    # トレードパラメータ
    trade_amount = 0.01  # BTC
    target_buy_price = 9000  # 仮想のターゲット価格(USD)
    target_sell_price = 11000  # 仮想のターゲット価格(USD)

    # 買い注文戦略
    optimal_order_strategy(exchange, symbol, trade_amount, target_buy_price)
    # 売り注文戦略
    optimal_order_strategy(exchange, symbol, -trade_amount, target_sell_price)

    time.sleep(10)  # 短いスリープで戦略の結果を確認

if __name__ == '__main__':
    main()

注意点

  1. リアルタイム市場データ: 最新の市場データに基づいて戦略を実行するため、常に最新の価格情報が必要です。
  2. 手数料とスリッページ: 実際の取引コストを含める必要があります。特にアグレッシブ注文はスリッページの影響を受けやすいです。
  3. 市場の流動性: 対象とする銘柄の市場流動性が戦略の成功に大きく影響します。流動性が低い市場で大量注文を行うと、価格に大きな影響を与える可能性があります。
  4. レートリミット: 頻繁なAPI呼び出しは取引所のレートリミットに注意が必要です。

このコードは、アグレッシブ注文とパッシブ注文の戦略を組み合わせて最適化する基本的な方法を提供しますが、実際の取引ではより複雑な要因を考慮する必要があります。

3.クロスアセット最適化

Yodaka

株式、債券、為替、商品など複数の資産間で最適化することを狙うbotです。

クロスアセット最適化は、異なる資産クラス(株式、債券、為替、商品など)を含むポートフォリオのリスクとリターンのバランスを最適化することを目的としています。ここでは、Pythonを使って、これらの異なる資産間でのポートフォリオの最適化を実施する方法を示します。この例では、平均分散最適化(Markowitzポートフォリオ理論)を基にしています。

必要なライブラリのインポート

import numpy as np
import pandas as pd
from scipy.optimize import minimize
import matplotlib.pyplot as plt

データ取得と前処理

この例では、各資産クラスの過去の価格データを使用します。実際には、適切なデータソースからデータを取得する必要があります。

# ダミーデータの生成
np.random.seed(42)
dates = pd.date_range('20200101', periods=60)
assets = ['Stocks', 'Bonds', 'Forex', 'Commodities']
data = np.random.randn(60, 4) + 0.05  # 月次リターンデータをシミュレーション

# DataFrameに変換
df = pd.DataFrame(data, index=dates, columns=assets)

# リターンと共分散の計算
returns = df.pct_change().dropna()
mean_returns = returns.mean()
cov_matrix = returns.cov()

ポートフォリオのリスクとリターンの計算

def portfolio_performance(weights, mean_returns, cov_matrix):
    returns = np.sum(mean_returns * weights) * 252
    std_dev = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights))) * np.sqrt(252)
    return std_dev, returns

最適化関数

ここでは、シャープレシオ(リターン/リスク)を最大化するような重みを見つけます。

def negative_sharpe_ratio(weights, mean_returns, cov_matrix, risk_free_rate=0.01):
    p_var, p_ret = portfolio_performance(weights, mean_returns, cov_matrix)
    return -(p_ret - risk_free_rate) / p_var

def optimize_portfolio(mean_returns, cov_matrix, risk_free_rate=0.01):
    num_assets = len(mean_returns)
    args = (mean_returns, cov_matrix, risk_free_rate)
    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bounds = tuple((0, 1) for asset in range(num_assets))
    initial_guess = num_assets * [1. / num_assets,]
    result = minimize(negative_sharpe_ratio, initial_guess, args=args,
                      method='SLSQP', bounds=bounds, constraints=constraints)
    return result

最適化の実行と結果の表示

optimal_portfolio = optimize_portfolio(mean_returns, cov_matrix)
optimal_weights = optimal_portfolio.x
print("Optimal weights:", optimal_weights)

# ポートフォリオのリスクとリターンを計算
p_std, p_ret = portfolio_performance(optimal_weights, mean_returns, cov_matrix)
print("Expected annual return: {:.2%}".format(p_ret))
print("Annual volatility/risk: {:.2%}".format(p_std))

注意点

  • データの品質と範囲: 適切な期間と品質のデータを使用することが重要です。データが不十分だと最適化の結果が現実の市場条件を反映しない可能性があります。
  • リスク評価: リスクは様々な方法で評価されるため、用途に応じたリスク評価方法を選択する必要があります。
  • 市場の変動: 市場状況は常に変化するため、ポートフォリオの定期的な見直しと再最適化が必要です。

このスクリプトはクロスアセットのポートフォリオを最適化する一例ですが、実際の運用ではより詳細なデータ分析やリスク管理が求められます。

4.ポートフォリオ執行

Yodaka

大口の注文を最適な方法で分割執行するbotです。

大口注文を効率的に実行するためには、注文を適切に分割し、市場への影響を最小限に抑える方法を採用する必要があります。以下のPythonコードは、指定された総注文量を複数の小さな注文に分割して実行するための戦略を示しています。この戦略では、注文の実行タイミングを調整して市場価格への影響を抑えます。

必要なライブラリのインポート

import ccxt
import time

取引所の設定と初期化

exchange = ccxt.binance({
    'apiKey': 'YOUR_API_KEY',
    'secret': 'YOUR_API_SECRET',
    'enableRateLimit': True
})
symbol = 'BTC/USDT'

大口注文の分割と実行

この関数は大口注文を小さな注文に分割し、市場の流動性に応じてそれぞれの注文を時間差を持って執行します。

def execute_large_order(exchange, symbol, total_quantity, order_size, interval):
    """
    大口注文を小さな注文に分割して実行する。
    :param exchange: 取引所オブジェクト
    :param symbol: 取引する通貨ペア
    :param total_quantity: 総注文量
    :param order_size: 各注文のサイズ
    :param interval: 注文間の時間間隔(秒)
    """
    num_orders = int(total_quantity / order_size)
    remaining_quantity = total_quantity

    for i in range(num_orders):
        if remaining_quantity < order_size:
            order_size = remaining_quantity  # 残量が注文サイズ未満の場合
        print(f"Placing order {i+1}/{num_orders} for {order_size} {symbol}")
        # exchange.create_market_buy_order(symbol, order_size)
        remaining_quantity -= order_size
        if remaining_quantity <= 0:
            break
        time.sleep(interval)

    if remaining_quantity > 0:
        print(f"Placing final order for {remaining_quantity} {symbol}")
        # exchange.create_market_buy_order(symbol, remaining_quantity)

def main():
    total_order_quantity = 10.0  # 総BTC量
    individual_order_size = 1.0  # 各注文のBTC量
    time_interval = 60  # 注文間隔(秒)

    execute_large_order(exchange, symbol, total_order_quantity, individual_order_size, time_interval)

if __name__ == '__main__':
    main()

注意点

  • 市場影響: 注文サイズとインターバルは市場の流動性に応じて適切に設定する必要があります。注文が大きすぎると市場価格に影響を与える可能性があります。
  • レートリミットとAPI制限: APIの呼び出しにはレートリミットがありますので、連続して注文を出す際には注意が必要です。
  • 価格の変動: 実行中に市場価格が変動する可能性があります。リスク管理として、価格の変動に対応する戦略も考慮することが重要です。

このコードは、大口注文を効率的かつ効果的に市場に投入する方法を提供しますが、実際のトレーディング環境ではさらに複雑な要因が介入するため、詳細なテストと調整が必要です。

5.インターナルクロス

Yodaka

同一取引所内での自己クロス取引を活用するタイプのbotです。

注意

インターナルクロス戦略は、同一取引所内で複数の口座間での取引を利用して、有利な価格で取引を行う戦略です。ただし、この種の取引は多くの取引所で禁止されており、特にフロントランニングやウォッシュトレードに関連する行為は違法あるいは規制の対象となることが多いです。そのため、この戦略を実装する前には、取引所の規約や地域の法規制を十分に確認し、合法的に運用できる方法を採用することが重要です。

しかし、教育的な目的であり、実際の取引ではなくシミュレーションの範囲内でインターナルクロスの概念を理解するために、以下にコード例を示します。この例では、同一取引所内での注文が互いに利益をもたらす可能性がある状況を想定しています。

必要なライブラリのインポート

import ccxt
import time

取引所の設定と初期化

exchange = ccxt.binance({
    'apiKey': 'YOUR_API_KEY',
    'secret': 'YOUR_API_SECRET',
    'enableRateLimit': True
})
symbol = 'BTC/USDT'

インターナルクロスのシミュレーション

def internal_cross_simulation(exchange, symbol, account_one_order, account_two_order):
    """
    二つの異なる注文を同一取引所内で実行するシミュレーション
    account_one_order: {'type': 'buy', 'amount': 0.01, 'price': 9500}
    account_two_order: {'type': 'sell', 'amount': 0.01, 'price': 9550}
    """
    # アカウント1の注文をシミュレーション
    if account_one_order['type'] == 'buy':
        print(f"Account One is buying {account_one_order['amount']} {symbol} at {account_one_order['price']}")
        # 実際の注文例
        # exchange.create_limit_buy_order(symbol, account_one_order['amount'], account_one_order['price'])

    # アカウント2の注文をシミュレーション
    if account_two_order['type'] == 'sell':
        print(f"Account Two is selling {account_two_order['amount']} {symbol} at {account_two_order['price']}")
        # 実際の注文例
        # exchange.create_limit_sell_order(symbol, account_two_order['amount'], account_two_order['price'])

def main():
    account_one_order = {'type': 'buy', 'amount': 0.01, 'price': 9500}
    account_two_order = {'type': 'sell', 'amount': 0.01, 'price': 9550}

    internal_cross_simulation(exchange, symbol, account_one_order, account_two_order)

if __name__ == '__main__':
    main()

注意点と実装上の考慮事項

  • 法的な遵守: 自己取引やウォッシュトレードは多くの市場で違法です。このコードは教育目的であり、実際の市場運用には適用しないでください
  • 市場への影響: 仮に合法的な状況でこの戦略を利用する場合でも、市場への影響と倫理的な側面を考慮する必要があります。
  • 取引所のポリシー: 取引所によってはこの種の取引が厳しく制限されている場合があります。実施前には取引所の規約を再確認してください。

このコードはあくまでプログラミングの学習と理解を深めるためのものであり、実際の取引に使用する場合は多くの法的、倫理的問題を考慮する必要があります。

まとめ

今回は5種類の発展的なロジックの雛形をまとめました。

botで収益を上げるためには、基本的なロジックを理解して細かい部分を詰めたり、ロジック同士の組み合わせを実装することが重要です。

また、発展的なロジックの概念を理解すると基本的なロジックをより深く理解することにもつながります。

Yodaka

今後もこの調子でbot開発の状況をまとめていきます。

-Bot, トレードロジック