152 lines
5.6 KiB
Python
152 lines
5.6 KiB
Python
import pandas as pd
|
||
|
||
# 加载交易记录
|
||
df = pd.read_csv('../result/backtest_trades.csv')
|
||
|
||
# 转换日期格式
|
||
df['open_date'] = pd.to_datetime(df['open_date'])
|
||
df['close_date'] = pd.to_datetime(df['close_date'])
|
||
|
||
# 计算持仓天数
|
||
df['holding_days'] = (df['close_date'] - df['open_date']).dt.total_seconds() / (60 * 60 * 24)
|
||
|
||
print("=" * 60)
|
||
print("📊 按交易对(币种)统计分析")
|
||
print("=" * 60)
|
||
|
||
# 按币种分组
|
||
grouped_by_pair = df.groupby('pair').agg(
|
||
总交易次数=('profit_abs', 'size'),
|
||
平均收益率=('profit_ratio', 'mean'),
|
||
累计收益=('profit_abs', 'sum'),
|
||
胜率=('profit_ratio', lambda x: (x > 0).mean()),
|
||
平均持仓时间_分钟=('trade_duration', 'mean')
|
||
)
|
||
|
||
# 格式化输出
|
||
grouped_by_pair['平均收益率'] = grouped_by_pair['平均收益率'].map(lambda x: f"{x:.2%}")
|
||
grouped_by_pair['胜率'] = grouped_by_pair['胜率'].map(lambda x: f"{x:.2%}")
|
||
grouped_by_pair['累计收益'] = grouped_by_pair['累计收益'].round(4)
|
||
grouped_by_pair['平均持仓时间_分钟'] = grouped_by_pair['平均持仓时间_分钟'].round(1)
|
||
|
||
print(grouped_by_pair)
|
||
print("\n📌 说明:")
|
||
print(" • 总交易次数:该币种总共完成的交易笔数")
|
||
print(" • 平均收益率:每笔交易的平均盈利比例(正为赚,负为亏)")
|
||
print(" • 累计收益:所有交易加总的绝对收益(单位:币本位)")
|
||
print(" • 胜率:盈利交易占总交易的比例")
|
||
print(" • 平均持仓时间_分钟:平均每笔交易持有多少分钟")
|
||
|
||
|
||
print("\n" + "=" * 60)
|
||
print("🚪 按退出原因统计分析")
|
||
print("=" * 60)
|
||
|
||
# 按退出原因分组
|
||
grouped_by_exit = df.groupby('exit_reason').agg(
|
||
总交易次数=('profit_abs', 'size'),
|
||
平均收益率=('profit_ratio', 'mean'),
|
||
累计收益=('profit_abs', 'sum'),
|
||
胜率=('profit_ratio', lambda x: (x > 0).mean())
|
||
)
|
||
|
||
# 格式化输出
|
||
grouped_by_exit['平均收益率'] = grouped_by_exit['平均收益率'].map(lambda x: f"{x:.2%}")
|
||
grouped_by_exit['胜率'] = grouped_by_exit['胜率'].map(lambda x: f"{x:.2%}")
|
||
grouped_by_exit['累计收益'] = grouped_by_exit['累计收益'].round(4)
|
||
|
||
print(grouped_by_exit)
|
||
print("\n📌 说明:")
|
||
print(" • exit_reason 含义参考:")
|
||
print(" • roi: 达到 ROI 目标自动止盈")
|
||
print(" • stop_loss: 触发止损")
|
||
print(" • trailing_stop_loss: 移动止损出场")
|
||
print(" • custom_exit: 自定义逻辑卖出(如 dynamic_roi)")
|
||
print(" • force_exit: 强制平仓(如策略更换、手动干预)")
|
||
print(" • 分析此表可了解哪种退出方式最有效")
|
||
|
||
|
||
print("\n" + "=" * 60)
|
||
print("📅 按开仓月份统计分析")
|
||
print("=" * 60)
|
||
|
||
# 处理时区并提取月份
|
||
df['open_date_naive'] = df['open_date'].dt.tz_localize(None)
|
||
df['month'] = df['open_date_naive'].dt.to_period('M')
|
||
|
||
grouped_by_month = df.groupby('month').agg(
|
||
总交易次数=('profit_abs', 'size'),
|
||
平均收益率=('profit_ratio', 'mean'),
|
||
累计收益=('profit_abs', 'sum'),
|
||
胜率=('profit_ratio', lambda x: (x > 0).mean())
|
||
)
|
||
|
||
# 格式化输出
|
||
grouped_by_month['平均收益率'] = grouped_by_month['平均收益率'].map(lambda x: f"{x:.2%}")
|
||
grouped_by_month['胜率'] = grouped_by_month['胜率'].map(lambda x: f"{x:.2%}")
|
||
grouped_by_month['累计收益'] = grouped_by_month['累计收益'].round(4)
|
||
|
||
print(grouped_by_month)
|
||
print("\n📌 说明:")
|
||
print(" • 统计每个月的交易表现")
|
||
print(" • 可用于判断策略在不同市场环境下的稳定性")
|
||
print(" • 若某月收益骤降,可结合行情进一步分析原因")
|
||
|
||
|
||
print("\n" + "=" * 60)
|
||
print("📈 按单笔交易盈利区间统计")
|
||
print("=" * 60)
|
||
|
||
# 按盈利区间分组统计
|
||
bins = [-float('inf'), -0.05, -0.02, 0, 0.02, 0.05, float('inf')]
|
||
labels = ['<-5%', '-5%~-2%', '-2%~0%', '0%~2%', '2%~5%', '>5%']
|
||
|
||
df['profit_group'] = pd.cut(df['profit_ratio'], bins=bins, labels=labels)
|
||
|
||
grouped_by_profit = df.groupby('profit_group', observed=True).agg(
|
||
交易次数=('profit_abs', 'size'),
|
||
平均收益率=('profit_ratio', 'mean'),
|
||
累计收益=('profit_abs', 'sum')
|
||
)
|
||
|
||
# 格式化
|
||
grouped_by_profit['平均收益率'] = grouped_by_profit['平均收益率'].map(lambda x: f"{x:.2%}")
|
||
grouped_by_profit['累计收益'] = grouped_by_profit['累计收益'].round(4)
|
||
|
||
print(grouped_by_profit)
|
||
print("\n📌 说明:")
|
||
print(" • 展示每笔交易的盈利分布情况")
|
||
print(" • 理想情况:多数集中在 '0%~2%' 和 '2%~5%' 区间")
|
||
print(" • 若大量亏损(<-2%),需检查止损机制是否有效")
|
||
|
||
|
||
print("\n" + "=" * 60)
|
||
print("⏳ 按持仓时长分类统计")
|
||
print("=" * 60)
|
||
|
||
# 分组为短中长线
|
||
df['duration_group'] = pd.cut(df['trade_duration'],
|
||
bins=[0, 60, 360, 1440, 100000],
|
||
labels=['<1小时', '1~6小时', '6小时~1天', '>1天'])
|
||
|
||
grouped_by_duration = df.groupby('duration_group', observed=True).agg(
|
||
交易次数=('profit_abs', 'size'),
|
||
平均收益率=('profit_ratio', 'mean'),
|
||
胜率=('profit_ratio', lambda x: (x > 0).mean()),
|
||
累计收益=('profit_abs', 'sum')
|
||
)
|
||
|
||
# 格式化
|
||
grouped_by_duration['平均收益率'] = grouped_by_duration['平均收益率'].map(lambda x: f"{x:.2%}")
|
||
grouped_by_duration['胜率'] = grouped_by_duration['胜率'].map(lambda x: f"{x:.2%}")
|
||
grouped_by_duration['累计收益'] = grouped_by_duration['累计收益'].round(4)
|
||
|
||
print(grouped_by_duration)
|
||
print("\n📌 说明:")
|
||
print(" • 分析不同持仓周期的表现")
|
||
print(" • 可帮助优化策略的持有时间设定")
|
||
print(" • 例如:若 '<1小时' 胜率高但收益低,可能适合高频微利策略")
|
||
|
||
print("\n✅ 分析完成")
|
||
|