赚钱机器指标分析
This commit is contained in:
304
finance/money-machine-A.py
Normal file
304
finance/money-machine-A.py
Normal file
@ -0,0 +1,304 @@
|
||||
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代码格式
|
||||
if symbol.startswith('6'):
|
||||
wind_code = f"{symbol}.SH"
|
||||
else:
|
||||
wind_code = f"{symbol}.SZ"
|
||||
|
||||
try:
|
||||
end_date = datetime.now().strftime('%Y-%m-%d')
|
||||
|
||||
print(f"📊 获取 {wind_code} 十年财务数据...")
|
||||
print(f"查询参数: ED-10Y 到 {end_date}")
|
||||
|
||||
# 获取资本支出数据 - 使用您提供的参数格式
|
||||
print("获取资本支出数据...")
|
||||
capex_data = w.wsd(wind_code, "cash_pay_acq_const_fiolta", "ED-10Y", end_date, "unit=1;rptType=1;Period=Y;Days=Alldays")
|
||||
|
||||
# 获取净利润数据 - 使用相同参数格式
|
||||
print("获取净利润数据...")
|
||||
profit_data = w.wsd(wind_code, "net_profit_is", "ED-10Y", end_date, "unit=1;rptType=1;Period=Y;Days=Alldays")
|
||||
|
||||
print(f"资本支出数据点: {len(capex_data.Data[0]) if capex_data.Data else 0}")
|
||||
print(f"净利润数据点: {len(profit_data.Data[0]) if profit_data.Data else 0}")
|
||||
|
||||
# 检查数据错误代码
|
||||
print(f"资本支出错误代码: {capex_data.ErrorCode}")
|
||||
print(f"净利润错误代码: {profit_data.ErrorCode}")
|
||||
|
||||
# 创建包含所有数据的DataFrame
|
||||
data_list = []
|
||||
|
||||
if capex_data.Data and profit_data.Data:
|
||||
# 确定数据长度
|
||||
data_length = min(len(capex_data.Times), len(capex_data.Data[0]), len(profit_data.Data[0]))
|
||||
print(f"有效数据长度: {data_length}")
|
||||
|
||||
for i in range(data_length):
|
||||
date = capex_data.Times[i]
|
||||
capex_value = capex_data.Data[0][i]
|
||||
profit_value = profit_data.Data[0][i]
|
||||
|
||||
# 计算比率(如果数据有效)- 改为百分比
|
||||
ratio = None
|
||||
is_capex_valid = capex_value is not None and not np.isnan(capex_value)
|
||||
is_profit_valid = profit_value is not None and not np.isnan(profit_value) and profit_value != 0
|
||||
|
||||
if is_capex_valid and is_profit_valid:
|
||||
ratio = (abs(capex_value) / profit_value) * 100 # 乘以100转换为百分比
|
||||
|
||||
data_list.append({
|
||||
'year': date.year,
|
||||
'report_date': date,
|
||||
'capital_expenditure': capex_value,
|
||||
'net_profit': profit_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, capex_data, profit_data
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 数据获取失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None, 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_str = f"{row['capital_expenditure']/1e8:8.2f}亿" if row['is_capex_valid'] else " NaN"
|
||||
profit_str = f"{row['net_profit']/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}年: 资本支出={capex_str} {capex_status}, "
|
||||
f"净利润={profit_str} {profit_status}, 比率={ratio_str} {ratio_status}")
|
||||
|
||||
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']
|
||||
capex = row['capital_expenditure'] / 1e8
|
||||
profit = row['net_profit'] / 1e8
|
||||
ratio = row['capex_to_profit_ratio_pct'] # 已经是百分比
|
||||
|
||||
print(f" {year}年: 资本支出 {capex:6.2f}亿 / 净利润 {profit:6.2f}亿 = 比率 {ratio:.2f}%") # 改为百分比显示
|
||||
|
||||
# 统计信息
|
||||
capex_mean = valid_df['capital_expenditure'].mean() / 1e8
|
||||
profit_mean = valid_df['net_profit'].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" 平均资本支出: {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()
|
||||
capex = valid_df['capital_expenditure'] / 1e8 # 转换为亿元
|
||||
profit = valid_df['net_profit'] / 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, 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 = "688981" # 贵州茅台
|
||||
|
||||
print(f"🔍 开始分析 {symbol}...")
|
||||
|
||||
# 获取十年数据
|
||||
df, capex_data, profit_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不可用")
|
||||
@ -2,7 +2,7 @@
|
||||
import vectorbt as vbt
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
from strategy_executor import generate_strategy, create_portfolio, create_real_stock_portfolio
|
||||
from strategy_executor import generate_strategy, create_portfolio, create_real_stock_portfolio, debug_signal_consistency, debug_signal_logic
|
||||
|
||||
# 设置中文显示
|
||||
plt.rcParams['font.sans-serif'] = ['SimHei']
|
||||
@ -372,12 +372,18 @@ def main():
|
||||
# 生成策略
|
||||
strategy_data = generate_strategy()
|
||||
|
||||
# 调试信号生成逻辑
|
||||
debug_signal_logic(strategy_data)
|
||||
|
||||
# 创建基于比率的投资组合(用于分析)
|
||||
ratio_portfolio = create_portfolio(strategy_data)
|
||||
|
||||
# 创建基于真实股票的投资组合(用于真实收益计算)
|
||||
stock_portfolio = create_real_stock_portfolio(strategy_data)
|
||||
|
||||
# 调试信号一致性
|
||||
debug_signal_consistency(strategy_data, stock_portfolio)
|
||||
|
||||
# 打印基于比率的统计
|
||||
print_statistics(strategy_data, ratio_portfolio)
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ from data_fetcher import get_processed_data
|
||||
def calculate_ratio_signals(ratio_series, window=20, num_std=2):
|
||||
"""
|
||||
基于价格比率计算配对交易信号
|
||||
优化信号逻辑,避免过于频繁的交易
|
||||
修正信号逻辑:比率低时做多价差,比率高时做空价差
|
||||
"""
|
||||
# 计算布林带
|
||||
ratio_ma = ratio_series.rolling(window=window).mean()
|
||||
@ -26,15 +26,22 @@ def calculate_ratio_signals(ratio_series, window=20, num_std=2):
|
||||
|
||||
ratio_val = ratio_series.iloc[i]
|
||||
ma_val = ratio_ma.iloc[i]
|
||||
upper_val = upper_band.iloc[i]
|
||||
lower_val = lower_band.iloc[i]
|
||||
|
||||
# 当前无仓位时的开仓条件
|
||||
if current_signal == 0:
|
||||
if ratio_val < lower_band.iloc[i]: # 比率突破下轨,做多价差
|
||||
signals.iloc[i] = 1
|
||||
# 比率突破下轨:SMIC相对低估,做多价差(买入SMIC,卖空HHIC)
|
||||
if ratio_val < lower_val:
|
||||
signals.iloc[i] = 1 # 做多价差
|
||||
current_signal = 1
|
||||
elif ratio_val > upper_band.iloc[i]: # 比率突破上轨,做空价差
|
||||
signals.iloc[i] = -1
|
||||
print(f"开仓做多价差: {ratio_series.index[i]} - 比率{ratio_val:.4f} < 下轨{lower_val:.4f}")
|
||||
|
||||
# 比率突破上轨:SMIC相对高估,做空价差(卖空SMIC,买入HHIC)
|
||||
elif ratio_val > upper_val:
|
||||
signals.iloc[i] = -1 # 做空价差
|
||||
current_signal = -1
|
||||
print(f"开仓做空价差: {ratio_series.index[i]} - 比率{ratio_val:.4f} > 上轨{upper_val:.4f}")
|
||||
|
||||
# 当前有仓位时的平仓条件
|
||||
elif current_signal != 0:
|
||||
@ -43,6 +50,7 @@ def calculate_ratio_signals(ratio_series, window=20, num_std=2):
|
||||
(current_signal == -1 and ratio_val <= ma_val):
|
||||
signals.iloc[i] = 0
|
||||
current_signal = 0
|
||||
print(f"平仓: {ratio_series.index[i]} - 比率{ratio_val:.4f} 回归均线{ma_val:.4f}")
|
||||
|
||||
return signals, ratio_ma, upper_band, lower_band
|
||||
|
||||
@ -50,10 +58,10 @@ def calculate_ratio_signals(ratio_series, window=20, num_std=2):
|
||||
def generate_ratio_size(signals, price_ratio, position_size=0.5):
|
||||
"""
|
||||
生成比率交易的size数据
|
||||
返回一个与price_ratio相同形状的Series,包含交易数量
|
||||
修复数据类型问题
|
||||
"""
|
||||
# 创建与price_ratio相同形状的size Series,初始为0
|
||||
size_series = pd.Series(0, index=signals.index, name='size')
|
||||
size_series = pd.Series(0.0, index=signals.index, name='size') # 改为float类型
|
||||
current_position = 0
|
||||
|
||||
for i in range(len(signals)):
|
||||
@ -63,25 +71,24 @@ def generate_ratio_size(signals, price_ratio, position_size=0.5):
|
||||
signal = signals.iloc[i]
|
||||
|
||||
if signal == 1 and current_position != 1: # 做多价差 -> 买入比率
|
||||
# 买入相当于做多中芯/做空华虹
|
||||
size_series.iloc[i] = position_size # 正数表示买入比率
|
||||
size_series.iloc[i] = float(position_size) # 明确转换为float
|
||||
current_position = 1
|
||||
|
||||
elif signal == -1 and current_position != -1: # 做空价差 -> 卖空比率
|
||||
# 卖空相当于做空中芯/做多华虹
|
||||
size_series.iloc[i] = -position_size # 负数表示卖空比率
|
||||
size_series.iloc[i] = -float(position_size) # 明确转换为float
|
||||
current_position = -1
|
||||
|
||||
elif signal == 0 and current_position != 0: # 平仓
|
||||
size_series.iloc[i] = 0 # 平仓
|
||||
size_series.iloc[i] = 0.0 # 明确转换为float
|
||||
current_position = 0
|
||||
|
||||
return size_series
|
||||
|
||||
|
||||
def generate_stock_sizes(signals, close_smic, close_hhic, initial_cash=100000, position_ratio=0.5):
|
||||
"""
|
||||
生成真实股票交易的size数据
|
||||
确保每次配对交易都是等市值对冲,避免使用杠杆
|
||||
添加详细的调试信息来跟踪信号执行
|
||||
"""
|
||||
# 创建空的size Series
|
||||
smic_size = pd.Series(0.0, index=signals.index, name='SMIC')
|
||||
@ -91,29 +98,43 @@ def generate_stock_sizes(signals, close_smic, close_hhic, initial_cash=100000, p
|
||||
smic_position = 0.0 # 当前中芯持仓数量
|
||||
hhic_position = 0.0 # 当前华虹持仓数量
|
||||
|
||||
print(f"\n=== 交易执行调试信息 ===")
|
||||
print(f"信号总数: {len(signals)}")
|
||||
print(f"非零信号数量: {(signals != 0).sum()}")
|
||||
print(f"做多信号: {(signals == 1).sum()}, 做空信号: {(signals == -1).sum()}, 平仓信号: {(signals == 0).sum()}")
|
||||
|
||||
for i in range(len(signals)):
|
||||
if i < 20: # 跳过布林带计算期
|
||||
continue
|
||||
|
||||
signal = signals.iloc[i]
|
||||
date = signals.index[i]
|
||||
smic_price = close_smic.iloc[i]
|
||||
hhic_price = close_hhic.iloc[i]
|
||||
|
||||
# 只有信号变化时才执行交易
|
||||
if signal != 0 or (signal == 0 and current_position != 0):
|
||||
print(f"\n日期: {date}, 信号: {signal}, 当前仓位: {current_position}")
|
||||
|
||||
# 平仓条件:信号为0且当前有仓位
|
||||
if signal == 0 and current_position != 0:
|
||||
print(f" 执行平仓: SMIC持仓{smic_position:.2f}, HHIC持仓{hhic_position:.2f}")
|
||||
|
||||
# 平掉所有仓位
|
||||
if smic_position != 0:
|
||||
smic_size.iloc[i] = -smic_position
|
||||
smic_position = 0.0
|
||||
print(f" 平仓SMIC: {-smic_size.iloc[i]:.2f}股")
|
||||
if hhic_position != 0:
|
||||
hhic_size.iloc[i] = -hhic_position
|
||||
hhic_position = 0.0
|
||||
print(f" 平仓HHIC: {-hhic_size.iloc[i]:.2f}股")
|
||||
|
||||
current_position = 0
|
||||
continue
|
||||
|
||||
# 开仓条件:只有当前无仓位时才开新仓
|
||||
if current_position == 0:
|
||||
if current_position == 0 and signal != 0:
|
||||
if signal == 1: # 做多价差:买入中芯,卖空华虹
|
||||
# 计算每只股票的仓位价值(等市值对冲)
|
||||
position_value = initial_cash * position_ratio
|
||||
@ -129,7 +150,9 @@ def generate_stock_sizes(signals, close_smic, close_hhic, initial_cash=100000, p
|
||||
hhic_position = hhic_shares
|
||||
|
||||
current_position = 1
|
||||
print(f"开仓做多价差: {signals.index[i]} - 买入SMIC {smic_shares:.2f}股 @{smic_price:.2f}, 卖空HHIC {abs(hhic_shares):.2f}股 @{hhic_price:.2f}")
|
||||
print(f" 执行做多价差开仓:")
|
||||
print(f" 买入SMIC: {smic_shares:.2f}股 @{smic_price:.2f}")
|
||||
print(f" 卖空HHIC: {abs(hhic_shares):.2f}股 @{hhic_price:.2f}")
|
||||
|
||||
elif signal == -1: # 做空价差:卖空中芯,买入华虹
|
||||
# 计算每只股票的仓位价值(等市值对冲)
|
||||
@ -146,16 +169,28 @@ def generate_stock_sizes(signals, close_smic, close_hhic, initial_cash=100000, p
|
||||
hhic_position = hhic_shares
|
||||
|
||||
current_position = -1
|
||||
print(f"开仓做空价差: {signals.index[i]} - 卖空SMIC {abs(smic_shares):.2f}股 @{smic_price:.2f}, 买入HHIC {hhic_shares:.2f}股 @{hhic_price:.2f}")
|
||||
print(f" 执行做空价差开仓:")
|
||||
print(f" 卖空SMIC: {abs(smic_shares):.2f}股 @{smic_price:.2f}")
|
||||
print(f" 买入HHIC: {hhic_shares:.2f}股 @{hhic_price:.2f}")
|
||||
|
||||
# 最后检查是否有未平仓的仓位,如果有则在最后一天平仓
|
||||
if current_position != 0:
|
||||
last_index = len(signals) - 1
|
||||
last_date = signals.index[last_index]
|
||||
print(f"\n最终平仓: {last_date}")
|
||||
if smic_position != 0:
|
||||
smic_size.iloc[last_index] = -smic_position
|
||||
print(f" 平仓SMIC: {-smic_size.iloc[last_index]:.2f}股")
|
||||
if hhic_position != 0:
|
||||
hhic_size.iloc[last_index] = -hhic_position
|
||||
print(f"最终平仓: {signals.index[last_index]} - 平掉所有剩余仓位")
|
||||
print(f" 平仓HHIC: {-hhic_size.iloc[last_index]:.2f}股")
|
||||
|
||||
# 统计实际执行的交易
|
||||
smic_trades = (smic_size != 0).sum()
|
||||
hhic_trades = (hhic_size != 0).sum()
|
||||
print(f"\n实际执行交易统计:")
|
||||
print(f" SMIC交易次数: {smic_trades}")
|
||||
print(f" HHIC交易次数: {hhic_trades}")
|
||||
|
||||
# 创建size DataFrame
|
||||
size_df = pd.DataFrame({
|
||||
@ -165,6 +200,103 @@ def generate_stock_sizes(signals, close_smic, close_hhic, initial_cash=100000, p
|
||||
|
||||
return size_df
|
||||
|
||||
def debug_signal_logic(strategy_data):
|
||||
"""调试信号生成逻辑"""
|
||||
print("\n" + "="*60)
|
||||
print("=== 信号生成逻辑调试 ===")
|
||||
print("="*60)
|
||||
|
||||
signals = strategy_data['signals']
|
||||
price_ratio = strategy_data['price_ratio']
|
||||
ratio_ma = strategy_data['ratio_ma']
|
||||
upper_band = strategy_data['upper_band']
|
||||
lower_band = strategy_data['lower_band']
|
||||
|
||||
# 检查关键日期的信号逻辑
|
||||
key_dates = [
|
||||
'2024-12-20', '2024-12-23', '2025-02-18', '2025-02-19',
|
||||
'2025-04-22', '2025-04-23', '2025-05-16', '2025-05-19'
|
||||
]
|
||||
|
||||
for date_str in key_dates:
|
||||
date = pd.Timestamp(date_str)
|
||||
if date in signals.index:
|
||||
signal = signals.loc[date]
|
||||
ratio_val = price_ratio.loc[date]
|
||||
ma_val = ratio_ma.loc[date]
|
||||
upper_val = upper_band.loc[date]
|
||||
lower_val = lower_band.loc[date]
|
||||
|
||||
print(f"\n{date}:")
|
||||
print(f" 比率: {ratio_val:.4f}, 均线: {ma_val:.4f}")
|
||||
print(f" 上轨: {upper_val:.4f}, 下轨: {lower_val:.4f}")
|
||||
print(f" 信号: {signal} ({'平仓' if signal == 0 else '做多' if signal == 1 else '做空'})")
|
||||
|
||||
# 检查信号逻辑
|
||||
if signal == 1:
|
||||
print(f" 逻辑: 比率{ratio_val:.4f} < 下轨{lower_val:.4f} = {ratio_val < lower_val}")
|
||||
elif signal == -1:
|
||||
print(f" 逻辑: 比率{ratio_val:.4f} > 上轨{upper_val:.4f} = {ratio_val > upper_val}")
|
||||
elif signal == 0:
|
||||
print(f" 逻辑: 平仓信号")
|
||||
|
||||
def debug_signal_consistency(strategy_data, stock_portfolio):
|
||||
"""调试信号和交易的一致性"""
|
||||
print("\n" + "="*60)
|
||||
print("=== 信号与交易一致性调试 ===")
|
||||
print("="*60)
|
||||
|
||||
signals = strategy_data['signals']
|
||||
price_ratio = strategy_data['price_ratio']
|
||||
ratio_ma = strategy_data['ratio_ma']
|
||||
upper_band = strategy_data['upper_band']
|
||||
lower_band = strategy_data['lower_band']
|
||||
|
||||
# 获取订单记录
|
||||
orders_df = stock_portfolio.orders.records_readable
|
||||
|
||||
print(f"\n信号数据:")
|
||||
print(f"信号时间范围: {signals.index[0]} 到 {signals.index[-1]}")
|
||||
print(f"信号总数: {len(signals)}")
|
||||
|
||||
# 找出所有信号变化点
|
||||
signal_changes = signals[signals != signals.shift(1)]
|
||||
print(f"\n信号变化点数量: {len(signal_changes)}")
|
||||
|
||||
# 显示前10个信号变化点
|
||||
print(f"\n前10个信号变化点:")
|
||||
for i, (date, signal) in enumerate(signal_changes.head(10).items()):
|
||||
ratio_val = price_ratio.loc[date]
|
||||
ma_val = ratio_ma.loc[date]
|
||||
upper_val = upper_band.loc[date]
|
||||
lower_val = lower_band.loc[date]
|
||||
|
||||
signal_desc = "平仓" if signal == 0 else ("做多" if signal == 1 else "做空")
|
||||
print(f" {date}: {signal_desc} (比率: {ratio_val:.4f}, 均线: {ma_val:.4f})")
|
||||
|
||||
# 检查订单时间与信号时间的对应关系
|
||||
if 'Timestamp' in orders_df.columns:
|
||||
order_dates = pd.to_datetime(orders_df['Timestamp']).unique()
|
||||
print(f"\n订单执行日期: {len(order_dates)}个")
|
||||
print("订单日期:", sorted(order_dates))
|
||||
|
||||
# 检查哪些信号日期有对应的订单
|
||||
signal_dates_with_orders = []
|
||||
signal_dates_without_orders = []
|
||||
|
||||
for date in signal_changes.index:
|
||||
if date in order_dates:
|
||||
signal_dates_with_orders.append(date)
|
||||
else:
|
||||
signal_dates_without_orders.append(date)
|
||||
|
||||
print(f"\n有对应订单的信号日期: {len(signal_dates_with_orders)}")
|
||||
print(f"无对应订单的信号日期: {len(signal_dates_without_orders)}")
|
||||
|
||||
if signal_dates_without_orders:
|
||||
print("缺失订单的信号日期:", signal_dates_without_orders[:5])
|
||||
|
||||
|
||||
def generate_strategy():
|
||||
"""生成配对交易策略"""
|
||||
# 获取数据
|
||||
|
||||
Reference in New Issue
Block a user