🚀 AI 一键生成 ptrade 策略代码
立即体验

ptrade 平台如何利用资产负债表应收账款进行财务选股?(附 Python 源码)

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

问题描述

ptrade 财务选股:如何利用资产负债表应收账款指标防范爆雷风险?
我想在 ptrade 中通过资产负债表获取应收账款和应收票据数据,筛选财务健康的股票,请问该怎么编写?

解决方案

ptrade 财务选股:利用资产负债表应收账款指标防范爆雷风险

在股票市场中,企业“应收账款”与“应收票据”过高往往暗示着资金回笼困难、客户信用风险大,甚至可能存在财务造假的隐患。利用 ptrade 的财务数据接口,我们可以在策略运行前,对应收账款及应收票据占总资产的比例进行计算,剔除比例过高的股票,从而有效防范爆雷风险。


一、核心 API 介绍

在 ptrade 中,我们使用 get_fundamentals 接口来获取财务报表数据。

  • 表名 (table): 'balance_statement' (资产负债表)
  • 核心字段 (fields):
    • account_receivable: 应收账款
    • bill_receivable: 应收票据
    • total_assets: 资产总计

选股逻辑

$$\text{应收占比} = \frac{\text{应收账款} + \text{应收票据}}{\text{资产总计}}$$
如果该比例超过一定阈值(例如 30%),则认为该股票存在潜在的财务爆雷风险,予以剔除。


二、Python 选股策略源码

以下是一个完整的 ptrade 财务选股策略示例。策略在盘前获取全市场 A 股的资产负债表数据,计算应收占比,并筛选出财务健康的股票池。

import pandas as pd
import numpy as np

def initialize(context):
    # 设置基准
    set_benchmark('000300.SS')
    # 每天 9:15 执行选股逻辑
    run_daily(context, filter_receivables, time='09:15')
    g.healthy_stocks = []

def filter_receivables(context):
    log.info("开始进行财务选股筛选...")
    
    # 1. 获取当前交易日全市场 A 股代码
    current_date = context.blotter.current_dt.strftime('%Y%m%d')
    all_stocks = get_Ashares(date=current_date)
    
    # 限制单次查询数量,防止触发接口流控(分批获取)
    batch_size = 300
    receivables_df_list = []
    
    for i in range(0, len(all_stocks), batch_size):
        batch_stocks = all_stocks[i:i+batch_size]
        try:
            # 2. 获取资产负债表相关字段
            df = get_fundamentals(
                security=batch_stocks,
                table='balance_statement',
                fields=['account_receivable', 'bill_receivable', 'total_assets'],
                date=current_date
            )
            if not df.empty:
                receivables_df_list.append(df)
        except Exception as e:
            log.error("获取财务数据异常: %s" % str(e))
            continue
            
    if not receivables_df_list:
        log.warning("未获取到任何财务数据")
        return
        
    # 合并数据
    financial_data = pd.concat(receivables_df_list)
    
    # 3. 数据清洗与计算
    # 填充空值为 0
    financial_data['account_receivable'] = financial_data['account_receivable'].fillna(0)
    financial_data['bill_receivable'] = financial_data['bill_receivable'].fillna(0)
    
    # 剔除总资产为 0 或 NaN 的异常数据
    financial_data = financial_data[financial_data['total_assets'] > 0]
    
    # 计算应收账款及票据占总资产的比例
    financial_data['receivables_ratio'] = (
        financial_data['account_receivable'] + financial_data['bill_receivable']
    ) / financial_data['total_assets']
    
    # 4. 筛选财务健康股票:应收占比小于 25% 的股票
    risk_threshold = 0.25
    healthy_df = financial_data[financial_data['receivables_ratio'] < risk_threshold]
    
    # 获取筛选后的股票列表
    g.healthy_stocks = list(healthy_df.index)
    
    log.info("全市场 A 股共 %d 只,剔除高应收风险股后,剩余健康股票 %d 只。" % (len(all_stocks), len(g.healthy_stocks)))
    # 更新股票池
    set_universe(g.healthy_stocks)

def handle_data(context, data):
    # 在此处编写您的交易逻辑,例如在健康股票池中进行均线择时交易
    if len(g.healthy_stocks) > 0:
        # 示例:仅对筛选出的第一只健康股票进行买入尝试
        target_stock = g.healthy_stocks[0]
        if context.portfolio.cash > 20000 and get_position(target_stock).amount == 0:
            order(target_stock, 100)
            log.info("买入财务健康股: %s" % target_stock)

三、注意事项

  1. 流控限制: get_fundamentals 接口每秒调用不得超过 100 次。在筛选全市场股票时,建议采用代码中所示的分批获取 (batch_size) 方式,并根据需要加入 time.sleep() 规避限流。
  2. 未来数据规避: 在回测中,date 参数不传时默认取当前回测日。为了严格模拟实盘,建议在盘前(如 9:15)获取前一交易日已公布的最新财报数据,避免引入未来函数。
  3. 行业特性差异: 某些特定行业(如建筑装饰、重电设备等)由于业务结算周期长,应收账款比例天然偏高。在实际应用中,可以结合 get_stock_blocks 接口按行业进行动态阈值筛选。