From 6acfbbf9fbaf4b61593e11b9130a3e6569b2f679 Mon Sep 17 00:00:00 2001 From: bingyi Date: Sat, 15 Nov 2025 17:48:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=BD=E9=99=85=E8=B4=A2=E5=8A=A1=E6=8A=A5?= =?UTF-8?q?=E5=91=8A=E8=B5=9A=E9=92=B1=E6=9C=BA=E5=99=A8=E6=8C=87=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- finance/money-machine-N.py | 316 +++++++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 finance/money-machine-N.py diff --git a/finance/money-machine-N.py b/finance/money-machine-N.py new file mode 100644 index 0000000..55b38ac --- /dev/null +++ b/finance/money-machine-N.py @@ -0,0 +1,316 @@ +import pandas as pd +import matplotlib.pyplot as plt +import numpy as np +from datetime import datetime + +try: + from WindPy import w + WIND_AVAILABLE = True + # 启动Wind + w.start() + if not w.isconnected(): + WIND_AVAILABLE = False + print("❌ 请先启动Wind金融终端") + else: + print("✅ Wind连接成功") +except ImportError: + WIND_AVAILABLE = False + print("❌ 未安装WindPy库") + +# 设置中文字体 +plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans'] +plt.rcParams['axes.unicode_minus'] = False + +def get_ten_year_financial_data(symbol): + """ + 使用ED-10Y参数获取十年财务数据 - 使用新指标 + """ + if not WIND_AVAILABLE: + print("Wind不可用") + return None + + # 台积电的Wind代码 + wind_code = f"{symbol}" + + try: + end_date = datetime.now().strftime('%Y-%m-%d') + + print(f"📊 获取 {wind_code} 十年财务数据...") + print(f"查询参数: ED-10Y 到 {end_date}") + + # 获取三个指标的数据 - 使用您提供的新参数格式 + print("获取财务数据 (资本支出、经营性资产现金流、税前利润)...") + financial_data = w.wsd(wind_code, "wgsd_capex_ff,wgsd_assets_bus_cf,wgsd_inc_pretax", + "ED-10Y", end_date, + "unit=1;rptType=1;currencyType=;Period=Y;Days=Alldays;Currency=CNY") + + print(f"数据点数量: {len(financial_data.Data[0]) if financial_data.Data else 0}") + + # 检查数据错误代码 + print(f"错误代码: {financial_data.ErrorCode}") + + # 创建包含所有数据的DataFrame + data_list = [] + + if financial_data.Data and len(financial_data.Data) >= 3: + # 确定数据长度 + data_length = min(len(financial_data.Times), + len(financial_data.Data[0]), + len(financial_data.Data[1]), + len(financial_data.Data[2])) + print(f"有效数据长度: {data_length}") + + for i in range(data_length): + date = financial_data.Times[i] + capex_value = financial_data.Data[0][i] # wgsd_capex_ff + assets_bus_cf_value = financial_data.Data[1][i] # wgsd_assets_bus_cf + pretax_income_value = financial_data.Data[2][i] # wgsd_inc_pretax + + # 计算调整后的资本支出 (wgsd_capex_ff - wgsd_assets_bus_cf) + adjusted_capex = None + if (capex_value is not None and not np.isnan(capex_value) and + assets_bus_cf_value is not None and not np.isnan(assets_bus_cf_value)): + adjusted_capex = capex_value - assets_bus_cf_value + + # 计算比率(如果数据有效)- 改为百分比 + ratio = None + is_capex_valid = adjusted_capex is not None and not np.isnan(adjusted_capex) + is_profit_valid = pretax_income_value is not None and not np.isnan(pretax_income_value) and pretax_income_value != 0 + + if is_capex_valid and is_profit_valid: + ratio = (abs(adjusted_capex) / pretax_income_value) * 100 # 乘以100转换为百分比 + + data_list.append({ + 'year': date.year, + 'report_date': date, + 'wgsd_capex_ff': capex_value, + 'wgsd_assets_bus_cf': assets_bus_cf_value, + 'adjusted_capital_expenditure': adjusted_capex, # 调整后的资本支出 + 'pretax_income': pretax_income_value, # 税前利润 + 'capex_to_profit_ratio_pct': ratio, # 百分比比率 + 'is_capex_valid': is_capex_valid, + 'is_profit_valid': is_profit_valid, + 'is_ratio_valid': ratio is not None + }) + else: + print("❌ 数据获取失败") + return None + + df = pd.DataFrame(data_list) + + print(f"✅ 成功获取 {len(df)} 年数据") + return df, financial_data + + except Exception as e: + print(f"❌ 数据获取失败: {e}") + import traceback + traceback.print_exc() + return None, None + +def print_ten_year_analysis(df, symbol): + """打印十年数据分析""" + print(f"\n{'='*80}") + print(f"📊 {symbol} - 十年财务数据分析报告") + print(f"{'='*80}") + + print(f"\n📈 数据完整性统计:") + total_years = len(df) + valid_capex = df['is_capex_valid'].sum() + valid_profit = df['is_profit_valid'].sum() + valid_ratio = df['is_ratio_valid'].sum() + + print(f"总年份数: {total_years}") + print(f"有效资本支出年份: {valid_capex} ({valid_capex/total_years*100:.1f}%)") + print(f"有效税前利润年份: {valid_profit} ({valid_profit/total_years*100:.1f}%)") + print(f"有效比率年份: {valid_ratio} ({valid_ratio/total_years*100:.1f}%)") + + print(f"\n🔍 详细年度数据:") + for i, row in df.iterrows(): + year = row['year'] + capex_ff_str = f"{row['wgsd_capex_ff']/1e8:8.2f}亿" if row['wgsd_capex_ff'] is not None and not np.isnan(row['wgsd_capex_ff']) else " NaN" + assets_cf_str = f"{row['wgsd_assets_bus_cf']/1e8:8.2f}亿" if row['wgsd_assets_bus_cf'] is not None and not np.isnan(row['wgsd_assets_bus_cf']) else " NaN" + adjusted_capex_str = f"{row['adjusted_capital_expenditure']/1e8:8.2f}亿" if row['is_capex_valid'] else " NaN" + profit_str = f"{row['pretax_income']/1e8:8.2f}亿" if row['is_profit_valid'] else " NaN" + ratio_str = f"{row['capex_to_profit_ratio_pct']:6.2f}%" if row['is_ratio_valid'] else " NaN" + + capex_status = "✅" if row['is_capex_valid'] else "❌" + profit_status = "✅" if row['is_profit_valid'] else "❌" + ratio_status = "✅" if row['is_ratio_valid'] else "❌" + + print(f" {year}年:") + print(f" wgsd_capex_ff: {capex_ff_str}") + print(f" wgsd_assets_bus_cf: {assets_cf_str}") + print(f" 调整后资本支出: {adjusted_capex_str} {capex_status}") + print(f" 税前利润: {profit_str} {profit_status}") + print(f" 比率: {ratio_str} {ratio_status}") + print() + +def analyze_valid_ten_year_data(df, symbol): + """分析十年有效数据""" + valid_df = df[df['is_ratio_valid']].copy() + + if valid_df.empty: + print(f"\n❌ {symbol} 无有效比率数据") + return None + + print(f"\n📊 {symbol} - 有效数据分析 (共{len(valid_df)}年):") + print("-" * 60) + + for i, row in valid_df.iterrows(): + year = row['year'] + adjusted_capex = row['adjusted_capital_expenditure'] / 1e8 + profit = row['pretax_income'] / 1e8 + ratio = row['capex_to_profit_ratio_pct'] # 已经是百分比 + + print(f" {year}年: 调整后资本支出 {adjusted_capex:6.2f}亿 / 税前利润 {profit:6.2f}亿 = 比率 {ratio:.2f}%") + + # 统计信息 + adjusted_capex_mean = valid_df['adjusted_capital_expenditure'].mean() / 1e8 + profit_mean = valid_df['pretax_income'].mean() / 1e8 + ratio_mean = valid_df['capex_to_profit_ratio_pct'].mean() + ratio_std = valid_df['capex_to_profit_ratio_pct'].std() + ratio_min = valid_df['capex_to_profit_ratio_pct'].min() + ratio_max = valid_df['capex_to_profit_ratio_pct'].max() + + print(f"\n💡 统计摘要:") + print(f" 平均调整后资本支出: {adjusted_capex_mean:.2f} 亿元") + print(f" 平均税前利润: {profit_mean:.2f} 亿元") + print(f" 平均比率: {ratio_mean:.2f}%") + print(f" 比率标准差: {ratio_std:.2f}%") + print(f" 比率范围: {ratio_min:.2f}% - {ratio_max:.2f}%") + + return valid_df + +def plot_ten_year_analysis(valid_df, symbol): + """绘制十年分析图表""" + if valid_df is None or valid_df.empty: + print("❌ 无有效数据可绘制") + return + + # 提取数据 + years = valid_df['year'].tolist() + adjusted_capex = valid_df['adjusted_capital_expenditure'] / 1e8 # 转换为亿元 + profit = valid_df['pretax_income'] / 1e8 # 转换为亿元 + ratios = valid_df['capex_to_profit_ratio_pct'] # 已经是百分比 + + # 创建图表 + fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(14, 15)) + + x = np.arange(len(years)) + + # 1. 调整后资本支出和税前利润对比 + bars1 = ax1.bar(x - 0.2, adjusted_capex, 0.4, label='调整后资本支出(亿元)', alpha=0.8, color='#FF6B6B') + bars2 = ax1.bar(x + 0.2, profit, 0.4, label='税前利润(亿元)', alpha=0.8, color='#4ECDC4') + ax1.set_title(f'{symbol} - 十年调整后资本支出 vs 税前利润', fontsize=14, fontweight='bold') + ax1.set_xticks(x) + ax1.set_xticklabels(years, rotation=45) + ax1.legend() + ax1.grid(True, alpha=0.3) + + # 添加数值标签 + for bar in bars1: + height = bar.get_height() + ax1.text(bar.get_x() + bar.get_width()/2., height, f'{height:.1f}', + ha='center', va='bottom', fontsize=8) + + for bar in bars2: + height = bar.get_height() + ax1.text(bar.get_x() + bar.get_width()/2., height, f'{height:.0f}', + ha='center', va='bottom', fontsize=8) + + # 2. 比率趋势图 - 百分比 + ax2.plot(x, ratios, 'o-', linewidth=3, markersize=8, color='#45B7D1', + markerfacecolor='white', markeredgewidth=2) + ax2.axhline(y=ratios.mean(), color='red', linestyle='--', alpha=0.7, + label=f'平均比率: {ratios.mean():.2f}%') + ax2.set_title(f'{symbol} - 十年调整后资本支出/税前利润比率趋势', fontsize=14, fontweight='bold') + ax2.set_xlabel('年份') + ax2.set_ylabel('比率 (%)') + ax2.set_xticks(x) + ax2.set_xticklabels(years, rotation=45) + ax2.legend() + ax2.grid(True, alpha=0.3) + + # 添加比率数值标签 - 百分比 + for i, (xi, ratio) in enumerate(zip(x, ratios)): + ax2.annotate(f'{ratio:.2f}%', (xi, ratio), textcoords="offset points", + xytext=(0,10), ha='center', fontsize=9, fontweight='bold') + + # 3. 比率柱状图 - 百分比 + colors = ['#FF9999' if ratio > ratios.mean() else '#99FF99' for ratio in ratios] + bars3 = ax3.bar(x, ratios, color=colors, alpha=0.8, edgecolor='black', linewidth=0.5) + ax3.axhline(y=ratios.mean(), color='red', linestyle='--', alpha=0.7, + label=f'平均比率: {ratios.mean():.2f}%') + ax3.set_title(f'{symbol} - 十年调整后资本支出/税前利润比率', fontsize=14, fontweight='bold') + ax3.set_xlabel('年份') + ax3.set_ylabel('比率 (%)') + ax3.set_xticks(x) + ax3.set_xticklabels(years, rotation=45) + ax3.legend() + ax3.grid(True, alpha=0.3) + + # 添加比率数值标签 - 百分比 + for i, (bar, ratio) in enumerate(zip(bars3, ratios)): + ax3.text(bar.get_x() + bar.get_width()/2., ratio, f'{ratio:.2f}%', + ha='center', va='bottom', fontsize=9, fontweight='bold') + + plt.tight_layout() + plt.show() + +def print_financial_insights(valid_df, symbol): + """打印财务洞察""" + if valid_df is None or valid_df.empty: + return + + avg_ratio = valid_df['capex_to_profit_ratio_pct'].mean() # 已经是百分比 + + print(f"\n💡 {symbol} 财务洞察:") + print("=" * 50) + + if avg_ratio < 10: + insight = "公司资本支出相对税前利润非常保守" + explanation = "这表明公司可能处于成熟期,不需要大量资本投入来维持运营" + elif avg_ratio < 30: + insight = "公司资本支出相对税前利润较为适中" + explanation = "公司在维持现有业务的同时进行适度投资" + elif avg_ratio < 50: + insight = "公司资本支出相对税前利润较高" + explanation = "公司可能处于扩张期或进行重大投资项目" + else: + insight = "公司资本支出相对税前利润非常高" + explanation = "这可能表明公司正在进行大规模扩张或面临高资本需求" + + print(f"平均比率: {avg_ratio:.2f}%") + print(f"主要特征: {insight}") + print(f"含义: {explanation}") + +# 使用示例 +if __name__ == "__main__": + if WIND_AVAILABLE: + # 台积电股票代码 + symbol = "2330.TW" # 台积电在台湾交易所的代码 + + print(f"🔍 开始分析 {symbol} (台积电)...") + + # 获取十年数据 + df, financial_data = get_ten_year_financial_data(symbol) + + if df is not None: + # 打印十年数据分析 + print_ten_year_analysis(df, symbol) + + # 分析有效数据 + valid_df = analyze_valid_ten_year_data(df, symbol) + + # 绘制图表 + if valid_df is not None: + plot_ten_year_analysis(valid_df, symbol) + + # 打印财务洞察 + print_financial_insights(valid_df, symbol) + + else: + print("❌ 无法获取数据") + + else: + print("❌ Wind不可用") \ No newline at end of file