社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

夏普比率交易策略:让 Python 量化交易更高效

数据科学实战 • 1 年前 • 481 次点击  

欢迎加入专注于财经数据与量化投研的【数据科学实战】知识星球!在这里,您将获取持续更新的《财经数据宝典》和《量化投研宝典》,这两部宝典相辅相成,为您在量化投研道路上提供明确指引。 我们提供了精选的国内外量化投研的 120+ 篇高质量文章,并每日更新最新研究成果,涵盖策略开发、因子分析、风险管理等核心领域。 无论您是量化投资新手还是经验丰富的研究者,星球社区都能帮您少走弯路,事半功倍,共同探索数据驱动的投资世界!

引言

加密货币市场以其高波动性而闻名,这既是机遇也是挑战。如何在这样的市场中建立一个有纪律的交易系统?本文将探讨一个基于夏普比率(Sharpe Ratio)的简单交易策略,该策略使用 Python、Backtrader 和 CCXT 库实现,可以帮助我们在比特币、以太坊等加密货币市场中做出更理性的交易决策。

策略核心思想

夏普比率是衡量风险调整后收益的重要指标。我们的策略基于以下简单逻辑:

  • 当短期夏普比率非常正面(如 > 2)时,市场表现强劲且稳定 → 生成做多信号
  • 当短期夏普比率非常负面(如 < -2)时,市场表现持续不佳 → 生成做空信号
  • 其他情况,保持观望

策略实现代码

首先,我们需要一个函数来计算滚动夏普比率并生成交易信号:

import numpy as np
import pandas as pd

def periods_per_year(timeframe: str) -> float:
    """根据时间框架计算年化系数"""
    n, u = int(timeframe[:-1]), timeframe[-1]
    if u == "d"return365.0 / n
    if u == "h"return365.0 * 24.0 / n
     if u == "m"return365.0 * 24.0 * 60.0 / n
    if u == "w"return52.0 / n
    raise ValueError(f"不支持的时间框架: {timeframe}")

def compute_sharpe_signals(df: pd.DataFrame, timeframe: str, window: int, 
                          upper: float=2.0, lower: float=-2.0)
:

    """计算滚动夏普比率并生成交易信号"""
    df = df.copy()
    df["ret"] = df["Close"].pct_change()  # 计算每个周期的收益率
    roll_mean = df["ret"].rolling(window).mean()
    roll_std = df["ret"].rolling(window).std()
    ann = np.sqrt(periods_per_year(timeframe))
    df["rolling_sharpe"] = (roll_mean / roll_std).replace([np.inf, -np.inf], np.nan)
    df["signal"] = 0
    df.loc[df["rolling_sharpe"] > upper, "signal"] = 1
    df.loc[df["rolling_sharpe"] < lower, "signal"] = -1
    df["signal_shifted"] = df["signal"].shift(1).fillna(0).astype(int)  # 今天决策,下一个周期行动
    return df.dropna()

风险管理设计

任何交易策略都需要风险管理。在我们的策略中,添加了以下保护措施:

  1. 止损:如果交易亏损超过 20%,立即退出
  2. 最大持有期限:最多持有 7 个交易周期(使用日线时为 7 天)
  3. 交易成本:考虑了手续费(0.04%)和滑点(0.05%)

这确保我们不仅追随信号,也在保护资金。

class SharpeSignalStrategy(bt.Strategy):
    """基于夏普比率的交易策略"""
    params = dict(hold_bars=7, stop_loss_pct=0.20, invest_pct=1.0, printlog=False)
    
    def __init__(self):
        self.sig = self.datas[0].signal_shifted
        self.entry_bar = None
        self.entry_price = None
        self.stop_order = None
    
    def place_stop(self, side: str):
        """设置止损单"""
        # 取消旧的止损单,然后相对于入场价格设置新的止损
        if self.stop_order:
            self.cancel(self.stop_order)
            self.stop_order = None
        if side == 'long':
            price = self.entry_price * (1 - self.p.stop_loss_pct)
            self.stop_order = self.sell(exectype=bt.Order.Stop, price=price)
        else:
            price = self.entry_price * (1 + self.p.stop_loss_pct)
            self.stop_order = self.buy(exectype=bt.Order.Stop, price=price)
    
    def notify_order(self, order):
        """订单状态更新"""
        if order.status == order.Completed:
            self.entry_price = order.executed.price
            self.entry_bar = len(self)
            self.place_stop('long'if order.isbuy() else'short')
    
    def next(self):
        """每个交易周期的策略逻辑"""
        s = int(self.sig[0])
        price = float(self.data.close[0])
        
        # 达到最大持有期限时退出
        if self.position and self.entry_bar isnotNone:
            if (len(self) - self.entry_bar) >= self.p.hold_bars:
                self.close()
                if self.stop_order: 
                    self.cancel(self.stop_order)
                    self.stop_order = None
                self.entry_bar = None
                self.entry_price = None
                return
        
        # 空仓时入场
        ifnot self.position and s != 0:
            notional = self.broker.getvalue() * self.p.invest_pct
            size = max(int(notional // price), 1)
            self.buy(size=size) if s == 1else self.sell(size=size)

数据获取

我们使用 CCXT 库从币安获取 USDC 交易对的历史数据:

import ccxt, time
from datetime import datetime, timezone
import  pandas as pd

def timeframe_to_ms(tf: str) -> int:
    """将时间框架转换为毫秒"""
    n, u = int(tf[:-1]), tf[-1]
    return n * {"m"60_000, "h"3_600_000, "d"86_400_000, "w"604_800_000}[u]

def fetch_ohlcv_paginated(exchange, symbol, timeframe, since_ms, until_ms=None, 
                         limit=1000, pause=1.0)
:

    """分页获取 OHLCV 数据"""
    out, cursor, tf_ms = [], since_ms, timeframe_to_ms(timeframe)
    until_ms = min(until_ms, int(time.time() * 1000))
    
    while cursor < until_ms:
        for attempt in range(5):
            try:
                batch = exchange.fetch_ohlcv(symbol, timeframe=timeframe, 
                                           since=cursor, limit=limit)
                break
            except (ccxt.NetworkError, ccxt.ExchangeError):
                time.sleep(pause * (attempt + 1))
        else:
            break
            
        ifnot batch: break
        out.extend([r for r in batch if r[0] < until_ms])
        cursor = batch[-1][0] + tf_ms
        time.sleep(pause)
        
        if len(batch) < limit and cursor + tf_ms >= until_ms: break
    return out

def get_ccxt_dataframe(symbol="ETH/USDC", timeframe="1d", start_date="2020-01-01"
                      end_date=None)
:

    """获取并处理 CCXT 数据为 DataFrame"""
    ex = ccxt.binance({"enableRateLimit"True"options": {"defaultType""spot"}})
    ex.load_markets()
    assert symbol in ex.markets, f"{symbol} 不在币安现货市场中"
    
    end_dt = datetime.now(timezone.utc) if end_date isNoneelse datetime.fromisoformat(end_date)
    start_dt = datetime.fromisoformat(start_date).replace(tzinfo=timezone.utc)
    
    raw = fetch_ohlcv_paginated(ex, symbol, timeframe, int(start_dt.timestamp() * 1000), 
                               int(end_dt.timestamp() * 1000))
    df = pd.DataFrame(raw, columns=["datetime","Open","High","Low","Close","Volume"])
    df["datetime"] = pd.to_datetime(df["datetime"], unit="ms", utc=True)
    return df.set_index("datetime")

回测示例

下面是一个实际的回测示例参数:

run_backtest(
    symbol="BTC/USDC",
    timeframe="1d",
    start_date="2021-01-01",
    end_date="2023-01-01",
    window=30,
    upper_threshold=2.0,
    lower_threshold=-2.0,
    hold_days=7,
    stop_loss_pct=0.20,
)

在测试中,我们可以得到以下结果:

最终组合价值:185,329.35
策略总回报率:61.70%
买入并持有回报率:-41.32%
夏普比率:0.8086785623645067
最大回撤:34.2717594145437%

策略变体尝试

我们可以调整策略参数来适应不同的市场条件:

# 日内交易实验:更多信号,不同的年化系数
run_backtest(
    symbol="ETH/USDC"
    timeframe="15m"
    start_date="2022-01-01",
    window=96,  # 约等于 15 分钟周期的 1 天
    upper_threshold=2.0
    lower_threshold=-2.0
    hold_days=3
    stop_loss_pct=0.15
)

# 更严格的过滤器:更少的交易,更高的确信度
run_backtest(
    symbol="BTC/USDC"
    timeframe="1d"
    start_date="2020-01-01",
    window=45
    upper_threshold=2.5
    lower_threshold=-2.5
    hold_days=5
    stop_loss_pct=0.25
)

策略观察与分析

通过对回测结果的分析,我们可以得出以下观察:

  1. 由于夏普比率 > 2 或 < -2 的情况并不常见,所以该策略交易频率较低
  2. 当确实发生交易时,策略能够捕捉到强劲的趋势表现
  3. 止损机制有效地切断了亏损交易
  4. 与简单的买入持有相比,该策略可能减少了回撤,但在强劲的牛市中可能表现不佳
  5. 这符合预期:基于夏普的过滤器更注重风险控制,而非最大化原始收益

策略局限性与未来改进方向

本策略仍有以下局限性:

  1. 阈值选择较为主观:我们选择了 ±2.0,但这些值可以并且应该经过调整
  2. 回顾窗口很重要:30 天只是一种选择,更短或更长的窗口表现会不同
  3. 尚未准备好实盘:这是研究回测,不是生产代码。实盘交易需要订单簿数据、执行逻辑和稳健测试
  4. 尚无仓位管理逻辑:目前每次交易都是全仓,基于风险的仓位管理可能改善结果

可能的扩展方向:

  • 尝试日内数据(15 分钟 K 线)而非日线
  • 将夏普比率与其他信号(动量、波动率等)结合
  • 应用前向优化以减少过拟合
  • 增加动态止损策略

总结

本文展示了如何将夏普比率——一个经典的风险调整性能指标——转化为加密货币市场中的简单交易信号。结果并不神奇,但这正是重点:在早期研究中,实验比优化更重要。通过在 Backtrader 中使用币安数据构建类似的小型原型,我们可以快速测试想法,从结果中学习,并决定哪些方向值得深入探索。

对于 Python 量化交易爱好者来说,这种方法提供了一个良好的起点,帮助你建立自己的交易系统。记住,成功的量化交易不仅仅是复杂的算法,更在于纪律、风险管理和持续的学习与改进。

参考文章

加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取本文完整研究解析、代码实现细节。

财经数据与量化投研知识社区

核心权益如下:

  1. 赠送《财经数据宝典》完整文档,汇集多年财经数据维护经验
  2. 赠送《量化投研宝典》完整文档,汇集多年量化投研领域经验
  3. 赠送《PyBroker-入门及实战》视频课程,手把手学习量化策略开发
  4. 每日分享高质量量化投研文章(已更新120+篇)、代码和相关资料
  5. 定期更新高频财经数据
  6. 参与年度不少于 10 次专属直播与录播课程
  7. 与核心开发者直接交流,解决实际问题
  8. 获取专业微信群交流机会和课程折扣

星球已有丰富内容积累,包括量化投研论文、财经高频数据、 PyBroker 视频教程、定期直播、数据分享和答疑解难。适合对量化投研和财经数据分析有兴趣的学习者及从业者。欢迎加入我们!

好文推荐

1. 用 Python 打造股票预测系统:Transformer 模型教程(一)

2. 用 Python 打造股票预测系统:Transformer 模型教程(二)

3. 用 Python 打造股票预测系统:Transformer 模型教程(三)

4. 用 Python 打造股票预测系统:Transformer 模型教程(完结)

5. 揭秘隐马尔可夫模型:因子投资的制胜武器

6. YOLO 也能预测股市涨跌?计算机视觉在股票市场预测中的应用

7. 金融 AI 助手:FinGPT 让你轻松掌握市场分析

8. 量化交易秘籍:为什么专业交易员都在用对数收益率?

9. Python 量化投资利器:Ridge、Lasso 和 Elastic Net 回归详解

10. 掌握金融波动率模型:完整 Python 实现指南

好书推荐

《Python编程:从入门到实践(第3版)》是一本广受欢迎的 Python 入门经典教材,由经验丰富的程序员 Eric Matthes 编写。该书采用循序渐进的教学方式,从基础语法讲解到实战项目开发,内容编排合理,实例丰富,语言通俗易懂。全书配有大量练习题和完整项目实战,包括数据可视化、网络爬虫、Web 应用开发等,让读者在实践中掌握编程技巧。第3版还增加了 f-string、海龟绘图等最新的 Python 特性内容。这本书不仅适合零基础读者入门学习,也非常适合想系统掌握 Python 的编程爱好者以及数据分析、人工智能等领域的学习者。它不仅教授编程知识,更注重培养读者的编程思维,是一本非常值得投资的 Python 学习指南。


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/185937