DeworkHub|基于凯利公式的 BTC/USDT 量化交易策略

DeworkHub|基于凯利公式的 BTC/USDT 量化交易策略

凯利公式(Kelly Criterion)是由约翰·凯利(John Kelly)在 1956 年提出的一种资金管理方法,旨在最大化长期资金增长率。其核心思想是根据胜率和赔率动态调整每次投资的仓位。

凯利公式的数学表达式为:

f^{*}=\frac{bp-q}{b}

其中:

  • f^{*} :最优投资比例(仓位比例)

  • b :赔率(盈利金额与亏损金额的比值)

  • p :胜率(盈利概率)

  • q :败率(亏损概率), q=1-p

废话不多说,上代码:

import ccxt
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from datetime import datetime, timedelta

# 初始化 OKX 交易所
exchange = ccxt.okx()

# 设置参数
symbol = 'BTC/USDT'  # 交易对
initial_balance = 10000  # 初始资金 10,000 USDT
taker_fee = 0.0006  # 吃单费率 0.06%
maker_fee = 0.0002  # 挂单费率 0.02%
slippage = 0.0005  # 滑点 0.05%
stop_loss = 0.05  # 止损比例 5%
take_profit = 0.10  # 止盈比例 10%

# 获取过去一整年的 1 小时线数据
def fetch_ohlcv(symbol, timeframe='1h', days=365):
    since = exchange.parse8601((datetime.utcnow() - timedelta(days=days)).strftime('%Y-%m-%d %H:%M:%S'))
    ohlcv = []
    while True:
        data = exchange.fetch_ohlcv(symbol, timeframe=timeframe, since=since)
        if not data:
            break
        since = data[-1][0] + 1  # 下一批数据的起始时间
        ohlcv.extend(data)
        if len(data) < 100:  # 如果数据不足 100 条,说明已经获取完所有数据
            break
    df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
    df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
    return df

# 计算收益率
def calculate_returns(df):
    df['return'] = df['close'].pct_change()
    return df

# 计算胜率和赔率
def calculate_kelly_params(df):
    wins = df[df['return'] > 0]['return']
    losses = df[df['return'] < 0]['return']
    p = len(wins) / len(df)  # 胜率
    b = wins.mean() / abs(losses.mean())  # 赔率
    return p, b

# 凯利公式计算最优仓位
def kelly_criterion(p, b):
    return (b * p - (1 - p)) / b

# 策略逻辑
def run_strategy(symbol):
    df = fetch_ohlcv(symbol, timeframe='1h', days=365)  # 获取过去一整年的 1 小时线数据
    df = calculate_returns(df)
    p, b = calculate_kelly_params(df)
    f_star = kelly_criterion(p, b)  # 最优仓位比例

    balance = initial_balance
    asset_values = []  # 存储资产价值
    positions = []  # 存储仓位状态

    for i in range(1, len(df)):
        current_price = df['close'].iloc[i]
        return_rate = df['return'].iloc[i]

        # 动态调整仓位
        if i % 24 == 0:  # 每天重新计算一次仓位
            p, b = calculate_kelly_params(df.iloc[:i])
            f_star = kelly_criterion(p, b)

        # 计算仓位
        position_size = balance * f_star  # 根据凯利公式计算仓位

        # 模拟交易
        if return_rate > 0:  # 盈利
            pnl = position_size * return_rate * (1 - taker_fee - slippage)
        else:  # 亏损
            pnl = position_size * return_rate * (1 - taker_fee - slippage)

        # 止损和止盈
        if pnl < -balance * stop_loss:
            pnl = -balance * stop_loss
        elif pnl > balance * take_profit:
            pnl = balance * take_profit

        # 更新资金
        balance += pnl
        asset_values.append(balance)

    # 创建图表
    plt.figure(figsize=(18, 12))

    # 子图 1: 价格走势
    ax1 = plt.subplot(2, 1, 1)
    ax1.plot(df['timestamp'], df['close'], label='Price (USDT)', color='blue', alpha=0.8)
    ax1.set_ylabel('Price (USDT)', color='blue')
    ax1.tick_params(axis='y', labelcolor='blue')
    ax1.legend(loc='upper left')

    # 子图 2: 资产价值
    ax2 = plt.subplot(2, 1, 2)
    ax2.plot(df['timestamp'][1:], asset_values, label='Portfolio Value (USDT)', color='green', alpha=0.8)
    ax2.set_ylabel('Portfolio Value (USDT)', color='green')
    ax2.tick_params(axis='y', labelcolor='green')
    ax2.legend(loc='upper left')

    # 格式化日期
    for ax in [ax1, ax2]:
        ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M'))
        plt.setp(ax.xaxis.get_majorticklabels(), rotation=45)

    # 保存高分辨率图片
    plt.tight_layout()
    plt.savefig(f'{symbol.replace("/", "_")}_kelly_strategy.jpg', dpi=300, bbox_inches='tight')
    print(f"Chart saved as {symbol.replace('/', '_')}_kelly_strategy.jpg")
    plt.show()

# 运行策略
run_strategy(symbol)

可见凯利公式在投资过程中,稳中求进,是一种获取长期稳定回报的不错选择。