百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 文章教程 > 正文

亲测!QuantStats一键生成量化报告,比手动快百倍

yund56 2025-03-02 19:33 30 浏览

一、QuantStats 极简入门,量化小白的福音

它能做什么?

  • 3 行代码生成专业报告:夏普比率、最大回撤等 30 + 关键指标,一键生成,轻松掌握投资策略的核心表现。
  • 可视化对比:策略与基准的收益曲线、月度热力图直观呈现,策略优劣一目了然,让分析决策更高效。
  • 自动化分析:复权、日期对齐等复杂操作统统自动完成,大大节省时间和精力,量化分析变得轻松简单。

为什么新手必学?

传统量化分析需要编写成百上千行代码,对于非专业程序员出身的投资者来说,难度极大。而 QuantStats 却能将代码量压缩至 10 行以内 ,极大降低了量化分析的门槛,让更多人能够轻松开启量化投资之旅。

二、环境精准配置,避开 50% 的错误

第 1 步:安装 Miniconda(环境隔离)

  • 访问 Miniconda 官网,找到 Python 3.9 版本进行下载。
  • 安装时,一定要记得勾选 Add to PATH,这一步很关键,否则后续可能会遇到各种环境配置问题。

第 2 步:创建独立环境

bash

conda create -n quant python=3.9 -y  
conda activate quant  

?验证方式:当你看到命令行开头显示 (quant) ,就说明你的独立环境已经成功激活啦。

第 3 步:安装指定版本依赖

bash

# 卸载旧版本(防冲突)  
pip uninstall -y pandas numpy quantstats akshare  

# 精准安装(2025年稳定组合)  
pip install pandas==2.2.3 quantstats==0.0.64 akshare==5.0.2  

?验证命令:

python

import pandas as pd  
print(pd.__version__)  

运行上述代码后,必须输出 2.2.3,才说明安装正确。

三、全流程代码及报错修复,从数据获取到报告生成

1. 数据获取(含自动重试)

python

import akshare as ak  

def fetch_data(symbol, is_index=False):  
    """获取股票/指数数据(自动处理接口错误)"""  
    try:  
        if is_index:  
            df = ak.stock_zh_index_daily_em(symbol=symbol)  
            df = df.rename(columns={'date': 'date', 'close': 'close'})  
        else:  
            df = ak.stock_zh_a_hist(symbol=symbol, period="daily", adjust="hfq")  
            df = df.rename(columns={'日期': 'date', '收盘': 'close'})  
        return df  
    except Exception as e:  
        print(f"数据获取失败:{str(e)},请检查网络或代码")  
        exit()  

新手注意:

  • 股票代码需带市场后缀(如.SS),不过 AKShare 的 A 股接口比较特殊,不需要添加后缀。
  • 如果数据获取失败,可以尝试更换数据源:

python

# 使用Yahoo数据(需梯子)  
import yfinance as yf  
df = yf.download('601398.SS', start='2020-01-01')  

2. 数据预处理(解决 RangeIndex 报错)

python

def process_data(stock_df, index_df):  
    # 转换日期格式(防御性编程)  
    for df in [stock_df, index_df]:  
        df['date'] = pd.to_datetime(df['date'], errors='coerce')  
        df.dropna(subset=['date'], inplace=True)  
    
    # 合并数据并设置时间索引(关键!)  
    merged = pd.merge(stock_df, index_df, on='date', suffixes=('_stock', '_index'))  
    merged = merged.set_index('date').sort_index()  
    
    # 终极校验  
    assert isinstance(merged.index, pd.DatetimeIndex), "时间索引必须为DatetimeIndex!"  
    return merged  

?验证方法:

python

print("索引类型:", type(merged.index))  

运行结果应输出 pandas.core.indexes.datetimes.DatetimeIndex'> ,表示索引类型正确。

3. 生成报告(解决 ME 报错)

python

def generate_report(merged):  
    # 计算收益率(限制涨跌幅防异常值)  
    merged['return_stock'] = merged['close_stock'].pct_change().clip(-0.3, 0.3)  
    merged['return_index'] = merged['close_index'].pct_change().clip(-0.3, 0.3)  
    merged.dropna(inplace=True)  
    
    # 必须修改QuantStats源码(见下方)  
    qs.reports.html(  
        returns=merged['return_stock'],  
        benchmark=merged['return_index'],  
        output='report.html',  
        title='策略分析报告'  
    )  

四、必做操作:解决 ME 报错的源码修改

步骤详解

  1. 找到 QuantStats 安装路径:
# Windows示例  
C:\Users\你的用户名\.conda\envs\quant\Lib\site-packages\quantstats\_plotting\core.py  
  1. 修改第 294 行(文本对比):

diff

- returns = returns.sum(axis=0)  
+ returns = returns.sum()  # 删除axis=0参数  
  1. 保存修改后的文件,然后重启 Python 内核,让修改生效。

五、常见报错全解(附解决方案),遇到问题不再抓瞎

报错信息

原因分析

解决方案

Invalid frequency: ME

Pandas 版本≥2.0 后别名变更

修改 QuantStats 源码或降级 Pandas

numpy operations are not valid...

错误使用 Numpy 函数

改用 Pandas 原生聚合如.sum ()

RangeIndex 时间索引错误

未正确设置 DatetimeIndex

执行 df.set_index ('date') 并校验类型

AttributeError: module..._FREQUENCIES

QuantStats 版本不兼容

升级 QuantStats 至 0.0.64 + 或手动添加映射

六、完整代码模板(复制即用),轻松搭建量化分析框架

python

# -*- coding: utf-8 -*-
# 作者:itsok
# 功能:QuantStats 全流程稳健版(增强错误处理+自动化重试)

import time
import pandas as pd
import quantstats as qs
from functools import wraps


# ---- 新增代码:全局频率适配 ----
if hasattr(pd, 'infer_freq'):
    pd.infer_freq = lambda x: pd.infer_freq(x).replace("ME", "M")

# 劫持QuantStats内部频率推断逻辑
def patched_infer_freq(index):
    freq = pd.infer_freq(index)
    return freq.replace("ME", "M") if freq else "D"

# ------------------- 第0步:环境检查 -------------------
def check_environment():
    """检查依赖库是否安装"""
    try:
        import akshare as ak
        return ak
    except ImportError:
        raise ImportError("请先安装依赖库:pip install -r requirements.txt")

# ------------------- 第1步:配置重试机制 -------------------
def retry(max_retries=3, delay=5):
    """通用重试装饰器"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for i in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    print(f"?? 第{i+1}次尝试失败: {str(e)}")
                    if i < max_retries - 1:
                        print(f" {delay}秒后重试...")
                        time.sleep(delay)
            raise RuntimeError(f"操作失败,已达最大重试次数{max_retries}次")
        return wrapper
    return decorator

# ------------------- 第2步:数据获取模块 -------------------
@retry(max_retries=5, delay=10)
def fetch_stock_data(symbol: str) -> pd.DataFrame:
    """
    获取股票数据(带自动重试)
    
    参数:
        symbol: 股票代码 (例: "601398")
    """
    print("? 正在获取股票数据...")
    df = ak.stock_zh_a_hist(
        symbol=symbol,
        period="daily",
        start_date="20200101",
        end_date="20250223",
        adjust="hfq"
    )
    if df.empty:
        raise ValueError("获取的股票数据为空,请检查代码或日期范围")
    return df

@retry(max_retries=5, delay=10)
def fetch_benchmark_data(symbol: str) -> pd.DataFrame:
    """
    获取基准指数数据(带自动重试)
    
    参数:
        symbol: 指数代码 (例: "sh000300")
    """
    print("? 正在获取基准数据...")
    df = ak.stock_zh_index_daily_em(symbol=symbol)
    if df.empty:
        raise ValueError("获取的基准数据为空,请检查代码")
    return df

# ------------------- 第3步:数据预处理 -------------------
def preprocess_data(stock: pd.DataFrame, benchmark: pd.DataFrame) -> pd.DataFrame:
    """
    数据预处理管道
    
    返回:
        merged_data: 处理后的合并数据
    """
    print(" 数据预处理中...")
    
    # 重命名列(防御性编程)
    stock = stock.rename(columns={'日期': 'date', '收盘': 'close'})
    benchmark = benchmark.rename(columns={'date': 'date', 'close': 'benchmark_close'})
    
    # 转换日期类型(强制校验)
    for df in [stock, benchmark]:
        df['date'] = pd.to_datetime(df['date'], errors='coerce')
        if df['date'].isnull().any():
            invalid_dates = df[df['date'].isnull()]['date'].index.tolist()
            raise ValueError("日期格式转换失败,存在无效日期")
    
    # 合并数据集(自动对齐日期)
    merged = pd.merge(
        stock[['date', 'close']],
        benchmark[['date', 'benchmark_close']],
        on='date',
        how='inner',
        validate='one_to_one'
    )
	# 二次校验日期格式
    if not pd.api.types.is_datetime64_any_dtype(merged['date']):
        raise TypeError("合并后的date列仍非时间类型")
    
    # 设置时间索引(核心修复)
    merged = merged.set_index('date').sort_index()
    
    # 有效性检查
    if merged.empty:
        raise ValueError("合并后的数据为空,请检查日期范围是否重叠")
    
    # 计算收益率(带边界检查)
    merged['strategy_return'] = merged['close'].pct_change()
    merged['benchmark_return'] = merged['benchmark_close'].pct_change()
	
    
    # 清理无效数据
    cleaned = merged.dropna(subset=['strategy_return', 'benchmark_return'])
    if len(cleaned) < 10:
        raise ValueError("有效数据不足,至少需要10个交易日数据")
    
    assert isinstance(cleaned.index, pd.DatetimeIndex), "索引必须为DatetimeIndex"
    return cleaned

# ------------------- 第4步:报告生成 -------------------

def generate_report(strategy_ret: pd.Series, benchmark_ret: pd.Series):
    # ---- 新增代码:全局替换ME为M ----
    import quantstats.utils as qs_utils
    from pandas.tseries.frequencies import to_offset
    
    # ----------------------------
    
    print(" 生成分析报告中...")
    report_path = "quant_analysis_report.html"
    qs.reports.html(
        returns=strategy_ret,
        benchmark=benchmark_ret,
        output=report_path,
        title='Industrial Bank vs CSI 300 Analysis',
        download_filename=report_path
    )
    print(f"? 报告已生成:{report_path}")
# ------------------- 主执行流程 -------------------
if __name__ == "__main__":
    try:
        # 初始化环境
        ak = check_environment()
        qs.extend_pandas()
        
        # 数据获取
        stock_df = fetch_stock_data("601398")
        print(f"?? 股票数据获取成功,共{len(stock_df)}条记录")
        
        benchmark_df = fetch_benchmark_data("sh000300")
        print(f"?? 基准数据获取成功,共{len(benchmark_df)}条记录")
        
        # 数据处理
        processed_data = preprocess_data(stock_df, benchmark_df)
        print(f"?? 数据预处理完成,有效交易日:{len(processed_data)}天")
        
        # 报告生成
        generate_report(
            processed_data['strategy_return'],
            processed_data['benchmark_return']
        )
        
    except Exception as e:
        print(f"? 发生严重错误: {str(e)}")
        print("建议排查步骤:")
        print("1. 检查网络连接")
        print("2. 验证股票/指数代码有效性")
        print("3. 查看requirements.txt版本是否匹配")

七、终极验证清单,确保量化分析顺利进行

  1. 检查 Pandas 版本是否为 2.2.3,这是与当前配置最适配的版本。
  2. 确认 QuantStats 源码已按照上述方法修改(core.py 第 294 行),否则可能会持续报错。
  3. 验证数据索引类型为 DatetimeIndex,这是保证后续分析准确的关键。
  4. 报告路径不要包含中文,避免出现乱码问题,影响报告的正常查看。
  5. 最终效果

相关推荐

SM小分队Girls on Top,女神战队少了f(x)?

这次由SM娱乐公司在冬季即将开演的smtown里,将公司的所有女团成员集结成了一个小分队project。第一位这是全面ACE的大姐成员权宝儿(BoA),出道二十年,在日本单人销量过千万,韩国国内200...

韩国女团 aespa 首场 VR 演唱会或暗示 Quest 3 将于 10 月推出

AmazeVR宣布将在十月份举办一场现场VR音乐会,观众将佩戴MetaQuest3进行体验。韩国女团aespa于2020年11月出道,此后在日本推出了三张金唱片,在韩国推出了...

韩网热议!女团aespa成员Giselle在长腿爱豆中真的是legend

身高163的Giselle,长腿傲人,身材比例绝了...

假唱而被骂爆的女团:IVE、NewJeans、aespa上榜

在韩国,其实K-pop偶像并不被认为是真正的歌手,因为偶像们必须兼备舞蹈能力、也经常透过对嘴来完成舞台。由于科技的日渐发达,也有许多网友会利用消音软体来验证K-pop偶像到底有没有开麦唱歌,导致假唱这...

新女团Aespa登时尚大片 四个少女四种style

来源:环球网

韩国女团aespa新歌MV曝光 画面梦幻造型超美

12月20日,韩国女团aespa翻唱曲《DreamsComeTrue》MV公开,视频中,她们的造型超美!WINTER背后长出一双梦幻般的翅膀。柳智敏笑容甜美。宁艺卓皮肤白皙。GISELLE五官精致...

女网友向拳头维权,自称是萨勒芬妮的原型?某韩国女团抄袭KDA

女英雄萨勒芬妮(Seraphine)是拳头在2020年推出的第五位新英雄,在还没有正式上线时就备受lsp玩家的关注,因为她实在是太可爱了。和其他新英雄不同的是,萨勒芬妮在没上线时就被拳头当成虚拟偶像来...

人气TOP女团是?INS粉丝数见分晓;TWICE成员为何在演唱会落泪?

现在的人气TOP女团是?INS粉丝数见分晓!现在爱豆和粉丝之间的交流方法变得多种多样,但是Instagram依然是主要的交流手段。很多粉丝根据粉丝数评价偶像的人气,拥有数百、数千万粉丝的组合作为全球偶...

韩国女团MVaespa Drama MV_韩国女团穿超短裙子跳舞

WelcometoDrama.Pleasefollow4ruleswhilewatchingtheDrama.·1)Lookbackimmediatelywhenyoufe...

aespa师妹团今年将出道! SM职员亲口曝「新女团风格、人数」

记者刘宛欣/综合报导南韩造星工厂SM娱乐曾打造出东方神起、SUPERJUNIOR、少女时代、SHINee、EXO等传奇团体,近年推出的aespa、RIIZE更是双双成为新生代一线团体,深受大众与粉丝...

南韩最活跃的女团aespa,新专辑《Girls》即将发布,盘点昔日经典

女团aespa歌曲盘点,新专辑《Girls》即将发布,期待大火。明天也就是2022年的7月8号,aespa新专辑《Girls》即将发行。这是继首张专辑《Savage》之后,时隔19个月的第二张专辑,这...

章泽天女团aespa出席戛纳晚宴 宋康昊携新片亮相

搜狐娱乐讯(山今/文玄反影/图科明/视频)法国时间5月23日晚,女团aespa、宋康昊、章泽天等明星亮相戛纳晚宴。章泽天身姿优越。章泽天肩颈线优越。章泽天双臂纤细。章泽天仪态端正。女团aespa亮...

Aespa舞台暴露身高比例,宁艺卓脸大,柳智敏有“TOP”相

作为SM公司最新女团aespa,初舞台《BlackMamba》公开,在初舞台里,看得出来SM公司是下了大功夫的,虽然之前SM公司新出的女团都有很长的先导片,但是aespa显然是有“特殊待遇”。运用了...

AESPA女团成员柳智敏karina大美女

真队内速度最快最火达成队内首个且唯一两百万点赞五代男女团中输断层第一(图转自微博)...

对来学校演出的女团成员语言性骚扰?韩国这所男高的学生恶心透了

哕了……本月4日,景福男子高中相关人士称已经找到了在SNS中上传对aespa成员进行性骚扰文章的学生,并开始着手调查。2日,SM娱乐创始人李秀满的母校——景福高中迎来了建校101周年庆典活动。当天,S...