3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在股票市场中,企业“应收账款”与“应收票据”过高往往暗示着资金回笼困难、客户信用风险大,甚至可能存在财务造假的隐患。利用 ptrade 的财务数据接口,我们可以在策略运行前,对应收账款及应收票据占总资产的比例进行计算,剔除比例过高的股票,从而有效防范爆雷风险。
在 ptrade 中,我们使用 get_fundamentals 接口来获取财务报表数据。
'balance_statement' (资产负债表)account_receivable: 应收账款bill_receivable: 应收票据total_assets: 资产总计$$\text{应收占比} = \frac{\text{应收账款} + \text{应收票据}}{\text{资产总计}}$$
如果该比例超过一定阈值(例如 30%),则认为该股票存在潜在的财务爆雷风险,予以剔除。
以下是一个完整的 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)
get_fundamentals 接口每秒调用不得超过 100 次。在筛选全市场股票时,建议采用代码中所示的分批获取 (batch_size) 方式,并根据需要加入 time.sleep() 规避限流。date 参数不传时默认取当前回测日。为了严格模拟实盘,建议在盘前(如 9:15)获取前一交易日已公布的最新财报数据,避免引入未来函数。get_stock_blocks 接口按行业进行动态阈值筛选。