🚀 AI 一键生成 ptrade 策略代码

PTrade 图论应用:使用 NetworkX 分析股票关联关系

ptrade | 发布时间: 2025/12/23
以下内容由 EasyQuant 生成。

问题描述

如何用 networkx 分析股票间的关联?

解决方案

使用 networkx 分析股票间的关联是量化金融中“复杂网络”分析的一种常见应用。通过将股票视为节点(Nodes),将股票间的相关性(如收益率相关系数)视为边(Edges),我们可以构建一个市场网络图,从而识别出市场中的核心资产、板块轮动效应或潜在的风险传导路径。

以下是在 PTrade 平台中使用 networkx 进行股票关联分析的完整策略示例。

核心逻辑

  1. 数据获取:获取股票池(如上证50)的历史收盘价。
  2. 计算相关性:计算每只股票的日收益率,并生成皮尔逊相关系数矩阵。
  3. 构建网络
    • 设定一个阈值(例如 0.6)。
    • 如果两只股票的相关系数大于该阈值,则在它们之间建立一条边。
  4. 网络分析
    • 使用度中心性(Degree Centrality):衡量一个节点与其他节点连接的紧密程度。度中心性最高的股票通常被认为是该板块的“领头羊”或市场情绪的核心。
  5. 交易决策:买入度中心性最高的股票(假设其最具代表性及上涨动力)。

PTrade 策略代码实现

import networkx as nx
import pandas as pd
import numpy as np

def initialize(context):
    """
    初始化函数
    """
    # 设定股票池,这里以上证50为例,代表大盘蓝筹
    # 注意:get_index_stocks 建议在 before_trading_start 调用,但为了初始化方便,
    # 这里先定义一个全局变量存储代码,实际获取在盘前进行
    g.index_code = '000016.SH' 
    g.stocks = []
    
    # 设定相关系数阈值,只有相关性高于此值的股票才会被连接
    g.corr_threshold = 0.6
    
    # 设定持仓股票数量
    g.target_hold_count = 5
    
    # 设定历史数据窗口长度(用于计算相关性)
    g.history_days = 60
    
    # 每日运行一次
    run_daily(context, trade_func, time='10:00')

def before_trading_start(context, data):
    """
    盘前处理:获取成分股,构建网络,计算中心性
    """
    # 获取上证50成分股
    g.stocks = get_index_stocks(g.index_code)
    
    if not g.stocks:
        log.info("未获取到成分股信息")
        return

    # 1. 获取历史收盘价数据
    # PTrade中,get_history获取多只股票单字段时,返回DataFrame,列名为股票代码
    history_data = get_history(g.history_days, '1d', 'close', g.stocks, fq='pre', include=False)
    
    if history_data is None or history_data.empty:
        log.info("历史数据获取失败")
        g.centrality_ranking = []
        return

    # 2. 计算日收益率
    # pct_change() 计算 (现价-前价)/前价
    returns_df = history_data.pct_change().dropna()
    
    # 3. 计算相关系数矩阵
    corr_matrix = returns_df.corr()
    
    # 4. 构建 NetworkX 图
    G = nx.Graph()
    
    # 添加节点
    G.add_nodes_from(g.stocks)
    
    # 添加边:遍历相关系数矩阵
    # 注意:矩阵是对称的,且对角线为1,我们需要过滤掉重复的和自身的
    columns = corr_matrix.columns
    for i in range(len(columns)):
        for j in range(i + 1, len(columns)):
            stock_a = columns[i]
            stock_b = columns[j]
            correlation = corr_matrix.iloc[i, j]
            
            # 如果相关性大于阈值,则添加边
            if correlation > g.corr_threshold:
                # 将相关系数作为权重(可选)
                G.add_edge(stock_a, stock_b, weight=correlation)
    
    # 5. 分析网络:计算度中心性 (Degree Centrality)
    # 度中心性越高,说明该股票与板块内其他股票的联动性越强
    if len(G.nodes()) > 0:
        degree_dict = nx.degree_centrality(G)
        # 将字典转换为列表并排序 [(股票代码, 中心性数值), ...]
        # Python 3.5 兼容写法
        sorted_centrality = sorted(degree_dict.items(), key=lambda x: x[1], reverse=True)
        
        # 提取排名靠前的股票代码
        g.centrality_ranking = [item[0] for item in sorted_centrality]
        
        log.info("今日网络关联度最高的股票前三名: %s" % str(g.centrality_ranking[:3]))
    else:
        g.centrality_ranking = []

def trade_func(context):
    """
    交易函数
    """
    if not g.centrality_ranking:
        return
        
    # 选取中心性最高的前N只股票
    target_stocks = g.centrality_ranking[:g.target_hold_count]
    
    # 获取当前持仓
    current_positions = list(context.portfolio.positions.keys())
    
    # 1. 卖出不在目标列表中的股票
    for stock in current_positions:
        if stock not in target_stocks:
            order_target_value(stock, 0)
            log.info("卖出非核心关联股票: %s" % stock)
            
    # 2. 买入目标股票
    # 简单的等权重分配资金
    if len(target_stocks) > 0:
        cash_per_stock = context.portfolio.portfolio_value / len(target_stocks)
        
        for stock in target_stocks:
            order_target_value(stock, cash_per_stock)
            log.info("买入高关联度核心股票: %s" % stock)

def handle_data(context, data):
    """
    盘中运行函数(本策略主要逻辑在 run_daily 中执行)
    """
    pass

代码关键点解析

  1. 库的导入

    • import networkx as nx:这是核心库。PTrade 环境通常内置了 networkx(文档显示版本为 1.9.1),该版本较老,因此代码中使用了兼容性较好的基础方法(如 G.add_nodes_from)。
  2. 数据处理

    • get_history:一次性获取多只股票的收盘价。在 Python 3.5 环境下,当 field 为单个字段(如 'close')时,返回的是 DataFrame,列索引为股票代码,这非常适合直接计算相关性。
    • returns_df.corr():Pandas 内置方法,快速计算皮尔逊相关系数矩阵。
  3. 图的构建 (Graph Construction)

    • 我们使用 nx.Graph() 创建无向图。
    • 双重循环遍历相关系数矩阵的上三角部分(避免重复计算 A-BB-A),只有当 correlation > g.corr_threshold 时才添加边。这意味着我们只关注强相关的股票对。
  4. 中心性指标 (Centrality)

    • nx.degree_centrality(G):计算节点的度中心性。在股票网络中,度中心性高的节点意味着它与大量其他股票同涨同跌,通常被视为市场风格的代表系统性风险的敏感点

扩展分析思路

除了上述代码中的度中心性,您还可以利用 networkx 进行更深度的分析:

  • 最小生成树 (MST):使用 nx.minimum_spanning_tree(G)。在金融中,MST 常用于去噪,构建市场的骨干结构,观察资金如何在板块间流动。
  • PageRank 算法:使用 nx.pagerank(G)。不仅考虑连接的数量,还考虑连接对象的质量(即与重要股票关联的股票更重要)。
  • 社群检测 (Community Detection):识别网络中紧密连接的子图,这通常对应着实际的行业板块或概念板块(有时能发现跨行业的隐形关联)。

Q&A

Q1: 为什么选择相关系数作为边的权重?
A1: 相关系数直接反映了资产价格变动的同步性。正相关表示同涨同跌,负相关表示对冲。在构建网络时,通常关注高正相关性来寻找核心资产,或关注低/负相关性来构建分散化投资组合。

Q2: 阈值 g.corr_threshold 设置多少合适?
A2: 这取决于市场环境和股票池的大小。

  • 在牛市或暴跌时,市场普涨普跌,相关性普遍较高,阈值应调高(如 0.7-0.8),以区分真正的核心关联。
  • 在震荡市中,个股分化,阈值可适当调低(如 0.5)。
  • 也可以使用动态阈值(例如取相关系数矩阵的前 10% 分位数)。

Q3: PTrade 中的 networkx 版本较老有什么影响?
A3: PTrade 文档显示支持 networkx 1.9.1。新版(2.x+)中很多方法的返回值从列表(List)变成了迭代器(Iterator/View),例如 G.nodes()。在编写代码时,尽量使用基础的图论方法,避免使用新版特有的语法。上述示例代码已考虑到这一点,使用了通用的写法。