Skip to content

15.4 经济周期择时

名词解释:经济周期择时(Business Cycle Timing)

经济周期择时是指识别当前经济所处的周期阶段(衰退、复苏、扩张、放缓),并据此调整资产配置。与市场择时不同,经济周期择时的信号频率较低(月度到季度),关注的是经济基本面的结构性转变,而非短期价格波动。

一、美林时钟模型及其改进

1.1 经典美林时钟

美林时钟(Merrill Lynch Investment Clock)将经济周期按增长和通胀两个维度划分为四个象限:

阶段增长通胀最优资产最优板块
复苏(Recovery)上升下降权益 > 债券 > 商品 > 现金可选消费、科技
过热(Overheat)上升上升商品 > 权益 > 现金 > 债券能源、材料、工业
滞胀(Stagflation)下降上升现金 > 商品 > 债券 > 权益公用事业、必需消费
衰退(Recession)下降下降债券 > 现金 > 权益 > 商品医疗、必需消费

1.2 改进:三维经济周期模型

经典美林时钟仅使用增长和通胀两个维度,但忽略了流动性和信贷条件这一关键维度:

PYTHON82 行 · 3.2 KB
📄此处有展示代码82 行 · 3.2 KB展开 ▼
python
import numpy as np
import pandas as pd
from scipy import stats
import matplotlib.pyplot as plt

def enhanced_investment_clock(growth_momentum: float,
                               inflation_momentum: float,
                               credit_momentum: float,
                               thresholds: dict = None) -> dict:
    """
    三维增强版美林时钟。

    参数:
        growth_momentum: 增长动量(标准化后的趋势强度)
        inflation_momentum: 通胀动量
        credit_momentum: 信用条件动量(正=信贷宽松,负=信贷紧缩)
        thresholds: 各维度的阈值
    返回:
        包含阶段分类和资产配置建议的字典
    """
    if thresholds is None:
        thresholds = {
            'growth': 0.0,
            'inflation': 0.0,
            'credit': 0.0
        }

    # 确定状态
    growth_state = 'up' if growth_momentum > thresholds['growth'] else 'down'
    infl_state = 'up' if inflation_momentum > thresholds['inflation'] else 'down'
    credit_state = 'tight' if credit_momentum < thresholds['credit'] else 'loose'

    # 8种可能的状态组合
    state = (growth_state, infl_state, credit_state)

    # 状态与资产配置的映射
    config_map = {
        ('up', 'down', 'loose'): {
            'phase': 'Goldilocks (金发姑娘)',
            'equity': 0.55, 'bonds': 0.25, 'commodities': 0.10, 'cash': 0.10,
            'description': '最佳宏观环境:增长强劲、通胀温和、流动性充裕'
        },
        ('up', 'down', 'tight'): {
            'phase': 'Recovery with Tight Credit',
            'equity': 0.40, 'bonds': 0.30, 'commodities': 0.15, 'cash': 0.15,
            'description': '增长恢复但信贷偏紧'
        },
        ('up', 'up', 'loose'): {
            'phase': 'Overheat (过热)',
            'equity': 0.30, 'bonds': 0.05, 'commodities': 0.45, 'cash': 0.20,
            'description': '通胀压力上升'
        },
        ('up', 'up', 'tight'): {
            'phase': 'Tightening Cycle (紧缩周期)',
            'equity': 0.20, 'bonds': 0.20, 'commodities': 0.30, 'cash': 0.30,
            'description': '央行收紧政策对抗通胀'
        },
        ('down', 'up', 'loose'): {
            'phase': 'Stagflation-lite (轻滞胀)',
            'equity': 0.20, 'bonds': 0.10, 'commodities': 0.30, 'cash': 0.40,
            'description': '增长放缓但通胀仍高'
        },
        ('down', 'up', 'tight'): {
            'phase': 'Stagflation (滞胀)',
            'equity': 0.15, 'bonds': 0.15, 'commodities': 0.25, 'cash': 0.45,
            'description': '最糟糕组合:低增长+高通胀+紧信用'
        },
        ('down', 'down', 'loose'): {
            'phase': 'Early Recession (衰退初期)',
            'equity': 0.25, 'bonds': 0.50, 'commodities': 0.10, 'cash': 0.15,
            'description': '经济下行,债券为王'
        },
        ('down', 'down', 'tight'): {
            'phase': 'Credit Crunch (信用紧缩)',
            'equity': 0.10, 'bonds': 0.40, 'commodities': 0.10, 'cash': 0.40,
            'description': '信用收缩加剧经济下行'
        }
    }

    allocation = config_map.get(state, config_map[('down', 'down', 'tight')])

    return allocation
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `enhanced_investment_clock`(三维增强版美林时钟)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

二、经济周期阶段的定量识别

2.1 基于滤波的趋势-周期分解

Hodrick-Prescott (HP) 滤波和 Christiano-Fitzgerald (CF) 带通滤波是分离经济数据趋势和周期成分的标准工具:

PYTHON41 行 · 1.4 KB
📄此处有展示代码41 行 · 1.4 KB展开 ▼
python
from scipy.signal import savgol_filter
from statsmodels.tsa.filters.hp_filter import hpfilter

def decompose_economic_cycle(gdp_series: pd.Series,
                              method: str = 'hp',
                              hp_lambda: float = 1600) -> dict:
    """
    分解经济时间序列的趋势和周期成分。

    参数:
        gdp_series: 经济时间序列(如季度GDP)
        method: 分解方法 ('hp' 或 'savgol')
        hp_lambda: HP滤波的平滑参数(季度数据=1600,月度=129600)
    返回:
        包含 trend, cycle, cycle_std 的字典
    """
    if method == 'hp':
        cycle, trend = hpfilter(gdp_series, lamb=hp_lambda)
    elif method == 'savgol':
        # Savitzky-Golay 滤波作为趋势
        window = max(5, len(gdp_series) // 4)
        if window % 2 == 0:
            window += 1
        trend = pd.Series(
            savgol_filter(gdp_series.values, window, 2),
            index=gdp_series.index
        )
        cycle = gdp_series - trend
    else:
        raise ValueError(f"Unknown method: {method}")

    # 周期成分标准化
    cycle_standardized = (cycle - cycle.mean()) / cycle.std()

    return {
        'trend': trend,
        'cycle': cycle,
        'cycle_standardized': cycle_standardized,
        'current_gap': cycle.iloc[-1],
        'output_gap_pct': (cycle.iloc[-1] / trend.iloc[-1]) * 100
    }
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `decompose_economic_cycle`(分解经济时间序列的趋势和周期成分)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

2.2 多种经济指标的融合打分

PYTHON79 行 · 2.4 KB
📄此处有展示代码79 行 · 2.4 KB展开 ▼
python
def economic_cycle_scoreboard(indicators: dict) -> dict:
    """
    综合多指标打分当前经济周期位置。

    参数:
        indicators: 各指标的当前得分字典
            {'pmi': 55, 'unemployment': 3.5, 'retail_sales': 3.2, ...}
    返回:
        综合打分和周期判断
    """
    # 各指标的标准化规则
    scoring_rules = {
        'pmi': {
            'score': lambda x: min(100, max(0, (x - 45) / 15 * 100)),
            'weight': 0.20,
            'direction': 1  # PMI越高越好
        },
        'unemployment_rate': {
            'score': lambda x: min(100, max(0, (8 - x) / 5 * 100)),
            'weight': 0.15,
            'direction': -1  # 失业率越低越好
        },
        'retail_sales_yoy': {
            'score': lambda x: min(100, max(0, (x + 5) / 10 * 100)),
            'weight': 0.15,
            'direction': 1
        },
        'industrial_production_yoy': {
            'score': lambda x: min(100, max(0, (x + 5) / 10 * 100)),
            'weight': 0.15,
            'direction': 1
        },
        'credit_spread': {
            'score': lambda x: min(100, max(0, (5 - x) / 5 * 100)),
            'weight': 0.15,
            'direction': -1  # 信用利差越低越好
        },
        'yield_curve_slope': {
            'score': lambda x: min(100, max(0, (x + 1) / 3 * 100)),
            'weight': 0.10,
            'direction': 1  # 收益率曲线越陡越好
        },
        'housing_starts_yoy': {
            'score': lambda x: min(100, max(0, (x + 10) / 20 * 100)),
            'weight': 0.10,
            'direction': 1
        }
    }

    total_score = 0
    component_scores = {}

    for name, rules in scoring_rules.items():
        if name in indicators:
            raw_score = rules['score'](indicators[name])
            weighted = raw_score * rules['weight']
            total_score += weighted
            component_scores[name] = {
                'raw_value': indicators[name],
                'score': raw_score,
                'weighted_score': weighted
            }

    # 周期阶段判断
    if total_score > 65:
        phase = 'expansion'
    elif total_score > 45:
        phase = 'slow_growth'
    elif total_score > 25:
        phase = 'contraction_risk'
    else:
        phase = 'recession'

    return {
        'composite_score': total_score,
        'phase': phase,
        'component_scores': component_scores,
        'confidence': abs(total_score - 50) / 50  # 0到1
    }
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `economic_cycle_scoreboard`(综合多指标打分当前经济周期位置)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

三、先行/同步/滞后指标体系

3.1 指标分类

经济指标按与经济周期的时序关系分为三类:

类型特征代表指标用途
先行指标(Leading)在经济见顶/见底前 3-12个月转向PMI新订单、消费者信心、建筑许可、股价预测周期拐点
同步指标(Coincident)与经济周期同步工业生产、零售销售、非农就业、GDP确认当前周期位置
滞后指标(Lagging)在经济见顶/见底后转向失业率、CPI、单位劳动力成本、商业贷款确认历史拐点、过滤假信号

3.2 先行指标的扩散指数

PYTHON18 行 · 513 B
📄此处有展示代码18 行 · 513 B展开 ▼
python
def diffusion_index(indicator_changes: np.ndarray) -> float:
    """
    计算领先指标的扩散指数。

    扩散指数 = (上升的指标数 / 总指标数) × 100
    当DI > 50时,多数指标扩张;DI < 50时,多数收缩。

    参数:
        indicator_changes: 各指标的最新变化(正=扩张,负=收缩)
    返回:
        扩散指数 [0, 100]
    """
    n_up = np.sum(indicator_changes > 0)
    n_total = len(indicator_changes)

    di = (n_up / n_total) * 100

    return di
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `diffusion_index`(计算领先指标的扩散指数)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

四、基于 HMM 的周期状态切换识别

4.1 隐马尔可夫模型(HMM)

HMM 非常适合建模经济周期,因为周期状态(衰退/扩张)是不可直接观测的隐状态,但可以通过经济指标(观测值)来推断。

PYTHON54 行 · 1.7 KB
📄此处有展示代码54 行 · 1.7 KB展开 ▼
python
from hmmlearn import hmm
import warnings

def hmm_cycle_detection(economic_data: np.ndarray,
                         n_states: int = 2,
                         n_iter: int = 1000) -> dict:
    """
    使用隐马尔可夫模型识别经济周期状态的切换。

    参数:
        economic_data: (T, D) 经济指标矩阵
        n_states: 隐状态数量(通常2=衰退/扩张,或4对应ML时钟)
        n_iter: EM算法迭代次数
    返回:
        包含 state_probabilities, states, model 的字典
    """
    # 数据标准化
    data_std = (economic_data - np.mean(economic_data, axis=0)) / \
               (np.std(economic_data, axis=0) + 1e-10)

    # 拟合高斯HMM
    model = hmm.GaussianHMM(
        n_components=n_states,
        covariance_type='full',
        n_iter=n_iter,
        random_state=42
    )

    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        model.fit(data_std)

    # 预测最可能的隐状态序列
    hidden_states = model.predict(data_std)

    # 计算状态概率(平滑后验概率)
    state_probs = model.predict_proba(data_std)

    # 状态标签解读
    # 假设:高增长状态的均值更高
    state_means = model.means_
    growth_idx = np.argmax(state_means[:, 0])  # 增长维度均值最高的状态
    recession_idx = 0 if growth_idx == 1 else 1

    return {
        'states': hidden_states,
        'state_probabilities': state_probs,
        'model': model,
        'growth_state': growth_idx,
        'recession_state': recession_idx,
        'transition_matrix': model.transmat_,
        'current_state': hidden_states[-1],
        'recession_probability': state_probs[-1, recession_idx]
    }
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `hmm_cycle_detection`(使用隐马尔可夫模型识别经济周期状态的切换)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

4.2 周期转向概率

HMM 的状态转移矩阵给出了状态间切换的概率。这可用于量化周期转向的风险:

τrecession=1St1recessionP(St=recessionSt1)

其中 P(St=recessionSt1) 是状态转移矩阵中从当前状态到衰退状态的概率。

HMM 方法的一个关键优势是概率化的信号输出,允许投资者进行渐进的仓位调整——当衰退概率从 10% 上升到 30% 时开始减仓,而不是等到确定性信号出现后才行动。

经济周期的定量识别为宏观资产配置提供了科学的决策依据。接下来我们将探讨如何将周期判断转化为具体的跨资产宏观交易策略