revert tradetocsv

This commit is contained in:
zhangkun9038@dingtalk.com 2025-10-14 15:06:07 +00:00
parent c8bd742cea
commit 52467775e9

View File

@ -11,37 +11,27 @@ result_dir = Path('../result')
if not result_dir.exists():
raise FileNotFoundError(f"Directory {result_dir} does not exist")
# 寻找JSON文件优先找backtest-result文件如果没有则使用已有的backtest_trades.json
# 寻找文件名包含 'backtest-result-' 的 JSON 文件
json_files = [f for f in result_dir.glob('*.json') if 'backtest-result-' in f.name]
trades = []
if not json_files:
# 如果没有backtest-result文件尝试使用backtest_trades.json作为输入
existing_json = result_dir / 'backtest_trades.json'
if existing_json.exists():
print("警告: 找不到backtest-result文件使用backtest_trades.json作为输入")
# 读取现有的backtest_trades.json
with open(existing_json) as f:
trades = json.load(f)
else:
raise FileNotFoundError("No JSON files with 'backtest-result-' in name found in ../result, and no existing backtest_trades.json")
else:
# 找到文件大小最大的 JSON 文件
largest_file = max(json_files, key=lambda x: x.stat().st_size)
# 读取最大的 JSON 文件
with open(largest_file) as f:
data = json.load(f)
# 从环境变量中获取策略名称
strategy_name = os.environ.get('STRATEGY_NAME', 'FreqaiPrimer') # 默认使用FreqaiPrimer
# 获取交易记录
if 'strategy' not in data or strategy_name not in data['strategy'] or 'trades' not in data['strategy'][strategy_name]:
raise ValueError(f"Could not find trades data for strategy {strategy_name}")
trades = data['strategy'][strategy_name]['trades']
raise FileNotFoundError("No JSON files with 'backtest-result-' in name found in ../result")
# 找到文件大小最大的 JSON 文件
largest_file = max(json_files, key=lambda x: x.stat().st_size)
# 读取最大的 JSON 文件
with open(largest_file) as f:
data = json.load(f)
# 从环境变量中获取策略名称
strategy_name = os.environ.get('STRATEGY_NAME', 'FreqaiPrimer') # 默认使用FreqaiPrimer
# 获取交易记录
if 'strategy' not in data or strategy_name not in data['strategy'] or 'trades' not in data['strategy'][strategy_name]:
raise ValueError(f"Could not find trades data for strategy {strategy_name}")
trades = data['strategy'][strategy_name]['trades']
# 定义输出文件路径
output_csv = result_dir / 'backtest_trades.csv'
@ -52,7 +42,7 @@ fieldnames = [
'pair', 'open_date', 'close_date', 'open_rate', 'close_rate', 'amount',
'profit_ratio', 'profit_abs', 'exit_reason', 'fee_open', 'fee_close',
'trade_duration', 'min_rate', 'max_rate',
'entry_orders_count', 'exit_orders_count', 'adjustments_count', 'avg_entry_price',
'entry_orders_count', 'adjustments_count', 'avg_entry_price',
'initial_entry_cost', 'total_adjustment_cost'
]
@ -62,7 +52,7 @@ json_data = []
with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
# 处理每笔交易
for trade in trades:
# 准备交易数据行
@ -82,14 +72,14 @@ with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
'min_rate': trade.get('min_rate', ''),
'max_rate': trade.get('max_rate', '')
}
# 分析订单信息,计算加仓相关字段
# 添加调试信息查看trade对象的键
# print(f"Trade keys: {list(trade.keys())}")
# 尝试从不同可能的位置获取订单信息
orders = trade.get('orders', [])
# 如果没有orders字段尝试从其他可能的字段获取
if not orders:
# 尝试从order_type或其他相关字段推断
@ -103,15 +93,15 @@ with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
'price': trade.get('open_rate', 0),
'ft_is_entry': True
}
# 模拟加仓订单
adjustment_orders = []
remaining_amount = trade.get('amount', 0) * 0.95 # 剩余95%的数量
remaining_cost = trade.get('open_rate', 0) * remaining_amount
# 如果有加仓次数信息(从之前的计算),创建相应数量的加仓订单
adjustments_count = row.get('adjustments_count', 2) # 默认2次加仓
for i in range(adjustments_count):
adj_order = {
'cost': remaining_cost / (adjustments_count),
@ -121,55 +111,42 @@ with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
'ft_is_entry': True
}
adjustment_orders.append(adj_order)
# 模拟出场订单
exit_order = {
'cost': trade.get('close_rate', 0) * trade.get('amount', 0),
'amount': trade.get('amount', 0),
'timestamp': trade.get('close_date', ''),
'price': trade.get('close_rate', 0),
'ft_is_entry': False,
'exit_reason': trade.get('exit_reason', 'unknown')
}
# 组合初始订单、加仓订单和出场订单
orders = [initial_order] + adjustment_orders + [exit_order]
# 分离入场订单和出场订单
# 组合初始订单和加仓订单
orders = [initial_order] + adjustment_orders
entry_orders = [order for order in orders if order.get('ft_is_entry')]
exit_orders = [order for order in orders if not order.get('ft_is_entry')]
row['entry_orders_count'] = len(entry_orders)
row['adjustments_count'] = max(0, len(entry_orders) - 1) # 加仓次数 = 入场订单数 - 1
row['exit_orders_count'] = len(exit_orders)
# 创建JSON对象添加CSV中的所有字段
json_trade = row.copy()
# 计算平均入场价格、初始入场金额和加仓总金额
if len(entry_orders) > 0:
# 初始入场金额
initial_entry_cost = entry_orders[0].get('cost', 0)
row['initial_entry_cost'] = initial_entry_cost
# 计算总入场成本和总入场数量
total_entry_cost = sum(order.get('cost', 0) for order in entry_orders)
total_entry_amount = sum(order.get('amount', 0) for order in entry_orders)
# 平均入场价格
if total_entry_amount > 0:
avg_entry_price = total_entry_cost / total_entry_amount
else:
avg_entry_price = 0
row['avg_entry_price'] = avg_entry_price
# 加仓总金额
if len(entry_orders) > 1:
total_adjustment_cost = sum(order.get('cost', 0) for order in entry_orders[1:])
else:
total_adjustment_cost = 0
row['total_adjustment_cost'] = total_adjustment_cost
# 在JSON中添加每次入场/加仓的详细信息
entries = []
for i, order in enumerate(entry_orders):
@ -178,7 +155,7 @@ with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
# 对于加仓订单,我们无法确定准确时间,但可以提供一个估算的价格
timestamp = order.get('timestamp', '')
price = order.get('price', 0)
# 如果没有timestamp使用交易的基本信息进行填充
if not timestamp or timestamp == '' or timestamp is None:
if i == 0:
@ -189,19 +166,19 @@ with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
# 获取交易的开始和结束时间
open_date_str = trade.get('open_date', '')
close_date_str = trade.get('close_date', '')
if open_date_str and close_date_str:
try:
# 尝试解析时间字符串并生成中间时间点
from datetime import datetime, timedelta
# 解析open_date和close_date
open_date = datetime.fromisoformat(open_date_str.replace('Z', '+00:00'))
close_date = datetime.fromisoformat(close_date_str.replace('Z', '+00:00'))
# 计算交易总持续时间
total_duration = close_date - open_date
# 根据加仓订单的索引,计算相对时间位置
total_entries = len(entry_orders)
if total_entries > 1:
@ -209,7 +186,7 @@ with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
# 分配时间戳在交易时间范围内均匀分布
time_ratio = (i + 1) / (total_entries + 1) # 使用+1避免最后一个加仓订单时间戳接近结束时间
entry_time = open_date + total_duration * time_ratio
# 格式化为与open_date相同的字符串格式
timestamp = entry_time.isoformat().replace('+00:00', 'Z') if entry_time.utcoffset() is None else entry_time.isoformat()
else:
@ -219,21 +196,21 @@ with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
timestamp = ''
else:
timestamp = ''
if price == 0 or price is None:
# 获取交易的价格范围
min_rate = trade.get('min_rate', trade.get('open_rate', 0))
max_rate = trade.get('max_rate', trade.get('open_rate', 0))
if i == 0:
# 对于初始订单,使用最大价格
price = max_rate
else:
# 对于加仓订单,基于交易的价格范围生成不同的价格
# 计算价格范围跨度
price_range = max_rate - min_rate
# 确保价格范围有意义
if price_range <= 0:
# 如果没有有效的价格范围使用open_rate
@ -245,14 +222,14 @@ with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
if total_adjustments > 0:
# 计算加仓订单的相对索引从1开始
adjustment_rel_index = i - 1 # 减去初始订单的索引
# 为不同的加仓订单生成不同的价格
# 从max_rate到min_rate均匀递减分布
# 让索引从1开始计算确保第一个加仓订单价格低于初始订单
price = max_rate - (price_range * (adjustment_rel_index + 1) / total_adjustments)
else:
price = trade.get('open_rate', 0)
entry_info = {
'order_index': i,
'timestamp': timestamp,
@ -262,47 +239,18 @@ with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
'order_type': 'initial' if i == 0 else 'adjustment'
}
entries.append(entry_info)
json_trade['entries'] = entries
# 在JSON中添加每次出场的详细信息
exitorders = []
for i, order in enumerate(exit_orders):
# 确保timestamp和price字段有值
timestamp = order.get('timestamp', '')
price = order.get('price', 0)
exit_reason = order.get('exit_reason', trade.get('exit_reason', 'unknown'))
# 如果没有timestamp使用交易的close_date
if not timestamp or timestamp == '' or timestamp is None:
timestamp = trade.get('close_date', '')
if price == 0 or price is None:
price = trade.get('close_rate', 0)
exit_info = {
'order_index': i,
'timestamp': timestamp,
'price': price,
'amount': order.get('amount', 0),
'cost': order.get('cost', 0),
'order_type': 'exit',
'exit_reason': exit_reason
}
exitorders.append(exit_info)
json_trade['exitorders'] = exitorders
else:
# 没有入场订单的情况
row['initial_entry_cost'] = 0
row['avg_entry_price'] = 0
row['total_adjustment_cost'] = 0
json_trade['entries'] = []
json_trade['exitorders'] = []
# 写入CSV行
writer.writerow(row)
# 添加到JSON数据
json_data.append(json_trade)
@ -313,4 +261,3 @@ with open(output_json, 'w', encoding='utf-8') as jsonfile:
print(f"Successfully converted {largest_file} to {output_csv}")
print(f"Successfully converted {largest_file} to {output_json}")
print(f"Added position adjustment information to both CSV and JSON outputs.")