You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现资产牛熊市识别:标普500熊市区间判定咨询

熊市周期识别代码优化方案

判定规则

当证券价格较其52周高点下跌20%及以上时标志熊市开启,当证券价格较近期低点上涨20%及以上时标志熊市结束。

计算目标

基于Yahoo Finance获取的标普500期货(标的代码ES=F)行情数据,输出以下核心指标:

  • 熊市开始日期
  • 对应区间价格峰值
  • 熊市结束日期
  • 对应区间价格谷底

原代码问题说明

原实现存在4个核心逻辑漏洞,会直接导致结果偏差:

  • 谷底计算窗口错误:使用固定21天滚动窗口取最小值,不符合熊市周期内全局谷底的判定要求
  • 日期匹配逻辑缺陷:遇到重复价格值时会错误匹配到非周期内的历史日期
  • 缺失熊市结束判定:仅筛选了回撤超20%的时点,未实现「从低点反弹20%即结束」的规则,会重复拆分同一段熊市
  • 运行效率低:逐行循环匹配日期的写法可通过简化逻辑大幅降低计算开销

优化后实现代码

import yfinance as yf
import pandas as pd
import numpy as np

# 阈值配置
DRAWDOWN_THRESHOLD = 0.2  # 熊市开启回撤阈值
REBOUND_THRESHOLD = 0.2   # 熊市结束反弹阈值
START_DATE = "1990-1-1"
TICKER = "ES=F"

# 获取行情数据
df = yf.download(tickers=TICKER, start=START_DATE)
close = df["Close"].squeeze()  # 兼容yfinance新版本多级列返回格式

# 初始化状态变量
bear_markets = []
in_bear = False
current_peak = np.nan
current_peak_date = None
current_trough = np.nan
current_trough_date = None

# 状态机逻辑逐行识别周期,无歧义
for date, price in close.items():
    # 非熊市状态:监控熊市开启信号
    if not in_bear:
        # 计算过去52周(约365天)滚动最高价
        window_start = date - pd.Timedelta(days=365)
        window_data = close.loc[window_start:date]
        rolling_peak = window_data.max()
        rolling_peak_date = window_data.idxmax()
        
        # 达到20%回撤阈值,标记熊市开启
        if price <= rolling_peak * (1 - DRAWDOWN_THRESHOLD):
            in_bear = True
            current_peak = rolling_peak
            current_peak_date = rolling_peak_date
            current_trough = price
            current_trough_date = date
        continue
    
    # 熊市状态:更新谷底,监控结束信号
    # 更新本轮熊市周期内的谷底值
    if price < current_trough:
        current_trough = price
        current_trough_date = date
    # 判定是否从谷底反弹20%,达到则结束本轮熊市
    if price >= current_trough * (1 + REBOUND_THRESHOLD):
        bear_markets.append({
            "Start_Date": current_peak_date,
            "Peak": round(current_peak, 2),
            "End_Date": date,
            "Trough": round(current_trough, 2),
            "Peak_To_Trough(%)": round(100*(current_trough/current_peak - 1), 2),
            "Num_Days": (date - current_peak_date).days
        })
        # 重置状态,等待下一轮熊市信号
        in_bear = False
        current_peak = np.nan
        current_peak_date = None
        current_trough = np.nan
        current_trough_date = None

# 转为结构化DataFrame输出
result_df = pd.DataFrame(bear_markets)
print(result_df)

逻辑说明

  • 采用状态机思路实现,清晰区分「非熊市」「熊市」两种状态,避免逻辑交叉混乱
  • 熊市开启前,实时计算过去52周滚动高点,回撤达标即标记周期起点和对应峰值
  • 熊市存续期间持续更新周期内最低点,直到价格从最低点反弹20%,立即标记周期终点
  • 自动去重,不会将同一段熊市拆分为多条重复记录
  • 结果直接输出结构化的熊市周期列表,无冗余数据

内容的提问来源于stack exchange,提问作者Boris Mikanikrezai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 11:36:18