myTestFreqAI/tools/analytic.py
2025-10-16 19:12:11 +00:00

152 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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✅ 分析完成")