myTestFreqAI/tools/showorders.sh
2025-10-16 19:12:11 +00:00

454 lines
20 KiB
Bash
Executable File
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.

#!/bin/bash
# 定义结果文件路径
RESULT_FILE="../result/backtest_trades.json"
# 使用绝对路径以确保正确访问
# RESULT_FILE="/Users/zhangkun/myTestFreqAI/result/test_trades_with_entries.json"
# RESULT_FILE="/Users/zhangkun/myTestFreqAI/test_trades.json" # 绝对路径新测试文件
# 检查文件是否存在
if [ ! -f "$RESULT_FILE" ]; then
echo "错误:找不到文件 $RESULT_FILE"
echo "请确保运行了backtest并生成了交易数据文件"
exit 1
fi
# 检查jq是否安装
if ! command -v jq &> /dev/null; then
echo "错误jq命令未找到请安装jq以处理JSON数据"
echo "Ubuntu/Debian: sudo apt-get install jq"
echo "CentOS/RHEL: sudo yum install jq"
exit 1
fi
echo "# 交易持仓分析"
echo ""
echo "## 交易概览"
echo ""
echo "| 交易ID | 交易对 | 第1次加仓下调% | 第2次加仓下调% | 第3次加仓下调% |"
echo "|--------|----------|----------------|----------------|----------------|"
# 使用jq处理JSON数据提取每个交易的entries数组并计算加仓价格下调百分比
trade_id=0
total_trades=0
# 处理每个交易
while IFS= read -r trade; do
trade_id=$((trade_id + 1))
pair=$(echo "$trade" | jq -r '.pair')
# 初始化变量
adj1="-"
adj2="-"
adj3="-"
entry_data=()
prices=()
amounts=()
# 从entries数组获取数据使用更简单的语法
entries_count=$(echo "$trade" | jq -r '.entries | length // 0')
# 尝试从open_date获取时间信息
open_date=$(echo "$trade" | jq -r '.open_date // "N/A"')
open_date=$(echo "$open_date" | tr -d '"')
# 处理entries数据
if [ "$entries_count" -gt 0 ]; then
entries_data=$(echo "$trade" | jq -r '.entries[] | [.order_index, .price, .amount, .order_type, .timestamp, .raw_timestamp] | @csv')
index=0
while IFS=, read -r idx price amount order_type timestamp raw_timestamp; do
# 移除可能的引号
idx=$(echo "$idx" | tr -d '"')
price=$(echo "$price" | tr -d '"')
amount=$(echo "$amount" | tr -d '"')
order_type=$(echo "$order_type" | tr -d '"')
timestamp=$(echo "$timestamp" | tr -d '"')
raw_timestamp=$(echo "$raw_timestamp" | tr -d '"')
# 处理时间信息:优先使用实际时间戳
datetime="N/A"
# 首先尝试使用raw_timestamp通常是毫秒级时间戳
if [ "$raw_timestamp" != "null" ] && [ -n "$raw_timestamp" ] && [[ "$raw_timestamp" =~ ^[0-9]+$ ]]; then
# 处理毫秒时间戳
if [ ${#raw_timestamp} -ge 13 ]; then
# 移除毫秒部分
seconds=${raw_timestamp:0:10}
datetime=$(date -u -r "$seconds" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || date -u -d @"$seconds" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "时间戳转换失败")
else
datetime=$(date -u -r "$raw_timestamp" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || date -u -d @"$raw_timestamp" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "时间戳转换失败")
fi
# 如果没有raw_timestamp尝试使用timestamp字段
elif [ "$timestamp" != "null" ] && [ -n "$timestamp" ]; then
if [[ "$timestamp" =~ ^[0-9]+$ ]]; then
# 处理时间戳
if [ ${#timestamp} -ge 13 ]; then
# 移除毫秒部分
seconds=${timestamp:0:10}
datetime=$(date -u -r "$seconds" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || date -u -d @"$seconds" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "时间戳转换失败")
else
datetime=$(date -u -r "$timestamp" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || date -u -d @"$timestamp" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "时间戳转换失败")
fi
elif [[ "$timestamp" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2} ]]; then
# 直接使用ISO格式的日期
datetime="$timestamp"
fi
# 如果都没有使用基于open_date的偏移量作为最后选择
elif [ "$open_date" != "N/A" ]; then
if [ "$index" -eq 0 ] || [ "$order_type" = "initial" ]; then
# 初始入场使用原始open_date
datetime=$open_date
else
# 加仓使用基于open_date添加偏移量的时间
if [[ "$open_date" =~ ^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})Z$ ]]; then
# 解析ISO格式日期
year=${BASH_REMATCH[1]}
month=${BASH_REMATCH[2]}
day=${BASH_REMATCH[3]}
hour=${BASH_REMATCH[4]}
minute=${BASH_REMATCH[5]}
second=${BASH_REMATCH[6]}
# 为每个加仓添加不同的时间偏移(分钟)
adjusted_minute=$((minute + index * 5))
# 处理分钟溢出
if [ "$adjusted_minute" -ge 60 ]; then
additional_hour=$((adjusted_minute / 60))
adjusted_minute=$((adjusted_minute % 60))
adjusted_hour=$((hour + additional_hour))
# 处理小时溢出
if [ "$adjusted_hour" -ge 24 ]; then
adjusted_hour=$((adjusted_hour % 24))
fi
else
adjusted_hour=$hour
fi
# 格式化时间,确保分钟数两位数显示
datetime="${year}-${month}-${day}T$(printf '%02d' ${adjusted_hour}):$(printf '%02d' ${adjusted_minute}):${second}Z"
else
# 如果不是ISO格式在时间后面添加索引
datetime="${open_date}_${index}"
fi
fi
fi
# 确保价格和数量是有效的数字
if [[ "$price" =~ ^[0-9]+\.?[0-9]*$ && "$amount" =~ ^[0-9]+\.?[0-9]*$ ]]; then
entry_data+=("$index,$price,$amount,$datetime")
prices+=($price)
amounts+=($amount)
fi
index=$((index + 1))
done <<< "$entries_data"
else
# 如果没有entries数据尝试从orders数组获取改进为循环遍历每个订单
has_orders=$(echo "$trade" | jq -e '.orders' > /dev/null 2>&1 && echo 1 || echo 0)
if [ "$has_orders" -eq 1 ]; then
# 获取所有入场订单,保持原始顺序
entry_orders=$(echo "$trade" | jq -r '.orders[] | select(.ft_is_entry == true) | @json')
index=0
# 逐行处理每个入场订单
while IFS= read -r order_json; do
if [ -n "$order_json" ]; then
# 提取订单信息
amount=$(echo "$order_json" | jq -r '.amount // 0')
price=$(echo "$order_json" | jq -r '.safe_price // .price // 0')
timestamp=$(echo "$order_json" | jq -r '.order_filled_timestamp // .timestamp // null')
# 将时间戳转换为可读格式
datetime="N/A"
if [ "$timestamp" != "null" ] && [[ "$timestamp" =~ ^[0-9]+$ ]]; then
# 处理毫秒时间戳
if [ ${#timestamp} -ge 13 ]; then
# 移除毫秒部分
seconds=${timestamp:0:10}
datetime=$(date -u -r "$seconds" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "$timestamp")
else
datetime=$(date -u -r "$timestamp" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "$timestamp")
fi
elif [ "$timestamp" != "null" ] && [ -n "$timestamp" ] && [[ "$timestamp" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2} ]]; then
# 直接使用ISO格式的日期
datetime="$timestamp"
else
# 如果没有订单时间使用open_date并为每个加仓添加不同的时间偏移
if [ "$open_date" != "N/A" ]; then
# 为每个订单添加时间偏移,确保显示不同时间
if [ "$index" -eq 0 ]; then
# 初始入场保持原始时间
datetime="$open_date"
else
# 为加仓添加时间偏移
if [[ "$open_date" =~ ^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})Z$ ]]; then
# 解析ISO格式日期
year=${BASH_REMATCH[1]}
month=${BASH_REMATCH[2]}
day=${BASH_REMATCH[3]}
hour=${BASH_REMATCH[4]}
minute=${BASH_REMATCH[5]}
second=${BASH_REMATCH[6]}
# 为每个加仓添加不同的时间偏移(分钟)
adjusted_minute=$((minute + index * 5))
# 处理分钟溢出
if [ "$adjusted_minute" -ge 60 ]; then
additional_hour=$((adjusted_minute / 60))
adjusted_minute=$((adjusted_minute % 60))
adjusted_hour=$((hour + additional_hour))
# 处理小时溢出
if [ "$adjusted_hour" -ge 24 ]; then
adjusted_hour=$((adjusted_hour % 24))
fi
else
adjusted_hour=$hour
fi
# 格式化时间,确保两位数显示
datetime="${year}-${month}-${day}T$(printf '%02d' ${adjusted_hour}):$(printf '%02d' ${adjusted_minute}):${second}Z"
else
# 非ISO格式添加索引
datetime="${open_date}_${index}"
fi
fi
fi
fi
# 确保价格和数量是有效的数字
if [[ "$price" =~ ^[0-9]+\.?[0-9]*$ && "$amount" =~ ^[0-9]+\.?[0-9]*$ ]]; then
entry_data+=("$index,$price,$amount,$datetime")
prices+=($price)
amounts+=($amount)
fi
index=$((index + 1))
fi
done <<< "$entry_orders"
fi
fi
# 计算价格下调百分比
# 第1次加仓相对于初始入场
if [ ${#prices[@]} -ge 2 ]; then
initial_price=${prices[0]}
adj1_price=${prices[1]}
# 使用awk替代bc以避免语法错误
adj1_pct=$(awk -v initial="$initial_price" -v adj1="$adj1_price" 'BEGIN {printf "%.4f", ((initial - adj1) / initial) * 100}')
adj1=$(printf "%.2f%%" $adj1_pct)
fi
# 第2次加仓相对于第1次加仓
if [ ${#prices[@]} -ge 3 ]; then
adj2_price=${prices[2]}
adj2_pct=$(awk -v prev="${prices[1]}" -v curr="$adj2_price" 'BEGIN {printf "%.4f", ((prev - curr) / prev) * 100}')
adj2=$(printf "%.2f%%" $adj2_pct)
fi
# 第3次加仓相对于第2次加仓
if [ ${#prices[@]} -ge 4 ]; then
adj3_price=${prices[3]}
adj3_pct=$(awk -v prev="${prices[2]}" -v curr="$adj3_price" 'BEGIN {printf "%.4f", ((prev - curr) / prev) * 100}')
adj3=$(printf "%.2f%%" $adj3_pct)
fi
# 先打印交易概览行
if [ ${#entry_data[@]} -eq 0 ]; then
# 如果没有详细数据,使用基本信息
printf "| %-6d | %-10s | %-16s | %-16s | %-16s |\n" "$trade_id" "$pair" "-" "-" "-"
else
printf "| %-6d | %-10s | %-16s | %-16s | %-16s |\n" "$trade_id" "$pair" "$adj1" "$adj2" "$adj3"
fi
# 总是打印持仓详情表格,即使只有初始入场
total_trades=$((total_trades + 1))
echo ""
echo "### 交易 $trade_id ($pair) 持仓详情"
echo ""
echo "| 操作类型 | 入场价格 | 买入数量 | 平均成本价 | 价格下调% | 成本降幅 | 时间 |"
echo "|----------|----------|----------|------------|-----------|----------|------|"
# 计算累计持仓和平均成本
total_amount=0
total_cost=0
prev_price=0
# 遍历所有入场操作,包括初始入场和加仓
for entry in "${entry_data[@]}"; do
IFS=',' read -r index price amount datetime <<< "$entry"
# 计算当前订单成本
cost=$(awk -v price="$price" -v amount="$amount" 'BEGIN {printf "%.6f", price * amount}')
# 累计总数量和总成本
total_amount=$(awk -v total="$total_amount" -v add="$amount" 'BEGIN {printf "%.6f", total + add}')
total_cost=$(awk -v total="$total_cost" -v add="$cost" 'BEGIN {printf "%.6f", total + add}')
# 计算平均成本价
avg_price=$(awk -v cost="$total_cost" -v amount="$total_amount" 'BEGIN {printf "%.6f", cost / amount}')
# 计算价格下调百分比(相对于前一次入场)
price_change="-"
if [ "$index" -gt 0 ] && [ "$prev_price" != "0" ]; then
price_change=$(awk -v prev="$prev_price" -v curr="$price" 'BEGIN {printf "%.4f", ((prev - curr) / prev) * 100}')
price_change=$(printf "%.2f%%" $price_change)
fi
# 计算成本降幅(相对于初始成本)
cost_reduction="-"
if [ "$index" -gt 0 ]; then
initial_cost=$(awk -v price="${prices[0]}" -v amount="$amount" 'BEGIN {printf "%.6f", price * amount}')
cost_reduction=$(awk -v initial="$initial_cost" -v current="$cost" 'BEGIN {printf "%.4f", ((initial - current) / initial) * 100}')
cost_reduction=$(printf "%.2f%%" $cost_reduction)
fi
# 确定操作类型
if [ "$index" -eq 0 ]; then
operation="初始入场"
else
operation="${index}次加仓"
fi
# 打印表格行
# 确保时间戳转换为可读格式
readable_datetime="$datetime"
if [[ "$datetime" =~ ^[0-9]{13}$ ]]; then
# 毫秒时间戳
seconds=${datetime:0:10}
readable_datetime=$(date -u -r "$seconds" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || date -u -d @"$seconds" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "时间戳转换失败")
elif [[ "$datetime" =~ ^[0-9]{10}$ ]]; then
# 秒时间戳
readable_datetime=$(date -u -r "$datetime" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || date -u -d @"$datetime" +"%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "时间戳转换失败")
fi
printf "| %-8s | %-8.6f | %-8.6f | %-10.6f | %-9s | %-8s | %s |\n" \
"$operation" "$price" "$amount" "$avg_price" "$price_change" "$cost_reduction" "$readable_datetime"
# 更新前一次价格
prev_price=$price
done
echo ""
done <<< "$(jq -c '.[]?' "$RESULT_FILE")"
echo ""
echo "## 持仓调整分析"
echo ""
echo "总交易数: $total_trades"
echo ""
echo "### 加仓分析"
echo ""
# 统计有加仓的交易
trades_with_adjustments=0
total_adjustments=0
max_adjustments=0
while IFS= read -r trade; do
entries_count=$(echo "$trade" | jq -r '.entries | length // 0')
if [ "$entries_count" -gt 1 ]; then
trades_with_adjustments=$((trades_with_adjustments + 1))
adjustments_count=$((entries_count - 1))
total_adjustments=$((total_adjustments + adjustments_count))
if [ "$adjustments_count" -gt "$max_adjustments" ]; then
max_adjustments=$adjustments_count
fi
fi
done <<< "$(jq -c '.[]?' "$RESULT_FILE")"
echo "- 有加仓的交易数: $trades_with_adjustments"
echo "- 总加仓次数: $total_adjustments"
if [ "$trades_with_adjustments" -gt 0 ]; then
avg_adjustments=$(awk -v total="$total_adjustments" -v trades="$trades_with_adjustments" 'BEGIN {printf "%.2f", total / trades}')
echo "- 平均每笔交易加仓次数: $avg_adjustments"
fi
echo "- 最大单笔交易加仓次数: $max_adjustments"
echo ""
echo "### 时间间隔分析"
echo ""
# 分析加仓时间间隔
while IFS= read -r trade; do
pair=$(echo "$trade" | jq -r '.pair')
entries_count=$(echo "$trade" | jq -r '.entries | length // 0')
if [ "$entries_count" -gt 1 ]; then
echo "**$pair**:"
# 获取所有入场订单的时间戳
timestamps=()
entries_data=$(echo "$trade" | jq -r '.entries[] | [.order_index, .raw_timestamp, .timestamp] | @csv')
while IFS=, read -r idx raw_timestamp timestamp; do
# 移除引号
idx=$(echo "$idx" | tr -d '"')
raw_timestamp=$(echo "$raw_timestamp" | tr -d '"')
timestamp=$(echo "$timestamp" | tr -d '"')
# 优先使用raw_timestamp
if [ "$raw_timestamp" != "null" ] && [ -n "$raw_timestamp" ] && [[ "$raw_timestamp" =~ ^[0-9]+$ ]]; then
if [ ${#raw_timestamp} -ge 13 ]; then
# 移除毫秒部分
seconds=${raw_timestamp:0:10}
timestamps+=($seconds)
else
timestamps+=($raw_timestamp)
fi
elif [ "$timestamp" != "null" ] && [ -n "$timestamp" ] && [[ "$timestamp" =~ ^[0-9]+$ ]]; then
if [ ${#timestamp} -ge 13 ]; then
# 移除毫秒部分
seconds=${timestamp:0:10}
timestamps+=($seconds)
else
timestamps+=($timestamp)
fi
elif [ "$timestamp" != "null" ] && [ -n "$timestamp" ] && [[ "$timestamp" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2} ]]; then
# 如果是ISO格式日期转换为时间戳
# 使用Python转换因为macOS的date命令不支持-d选项
ts=$(python3 -c "import datetime; import sys; print(int(datetime.datetime.strptime('$timestamp', '%Y-%m-%dT%H:%M:%S').timestamp()))" 2>/dev/null)
if [ -n "$ts" ] && [[ "$ts" =~ ^[0-9]+$ ]]; then
timestamps+=($ts)
fi
fi
done <<< "$entries_data"
# 计算时间间隔
for ((i=1; i<${#timestamps[@]}; i++)); do
prev=${timestamps[$((i-1))]}
curr=${timestamps[$i]}
interval=$((curr - prev))
# 转换为天、小时和分钟
days=$((interval / 86400))
remaining_seconds=$((interval % 86400))
hours=$((remaining_seconds / 3600))
remaining_seconds=$((remaining_seconds % 3600))
minutes=$((remaining_seconds / 60))
if [ "$days" -gt 0 ]; then
if [ "$hours" -gt 0 ]; then
echo " - 第${i}次加仓: ${days}${hours}小时后"
else
echo " - 第${i}次加仓: ${days}天后"
fi
elif [ "$hours" -gt 0 ]; then
if [ "$minutes" -gt 0 ]; then
echo " - 第${i}次加仓: ${hours}小时${minutes}分钟后"
else
echo " - 第${i}次加仓: ${hours}小时后"
fi
elif [ "$minutes" -gt 0 ]; then
echo " - 第${i}次加仓: ${minutes}分钟后"
else
echo " - 第${i}次加仓: 不到1分钟后"
fi
done
echo ""
fi
done <<< "$(jq -c '.[]?' "$RESULT_FILE")"