134 lines
5.2 KiB
Python
134 lines
5.2 KiB
Python
import csv
|
||
from datetime import datetime, timezone
|
||
import matplotlib.pyplot as plt
|
||
|
||
# ---------------- 配置 ----------------
|
||
CSV_FILE = "kline_3.csv" # CSV 文件路径
|
||
LEVERAGE = 100
|
||
CAPITAL = 10000
|
||
POSITION_RATIO = 0.01
|
||
FEE_RATE = 0.0005
|
||
|
||
# ---------------- 读取 CSV ----------------
|
||
data = []
|
||
with open(CSV_FILE, 'r') as f:
|
||
reader = csv.DictReader(f)
|
||
for row in reader:
|
||
ts = int(row['id'])
|
||
dt = datetime.fromtimestamp(ts, tz=timezone.utc)
|
||
if dt.year == 2025 and dt.month == 1:
|
||
data.append({
|
||
'time': dt,
|
||
'open': float(row['open']),
|
||
'high': float(row['high']),
|
||
'low': float(row['low']),
|
||
'close': float(row['close']),
|
||
})
|
||
|
||
# ---------------- 策略回测 ----------------
|
||
total_profit = 0
|
||
total_fee = 0
|
||
trades = [] # 保存每笔交易详情
|
||
|
||
for i in range(len(data) - 1):
|
||
k = data[i]
|
||
k_next = data[i + 1]
|
||
|
||
body = abs(k['close'] - k['open'])
|
||
upper_shadow = k['high'] - max(k['close'], k['open'])
|
||
lower_shadow = min(k['close'], k['open']) - k['low']
|
||
position_usdt = CAPITAL * POSITION_RATIO
|
||
leveraged_position = position_usdt * LEVERAGE
|
||
|
||
# ---------------- 锤子线 → 做多 ----------------
|
||
if body != 0 and lower_shadow >= 2 * body:
|
||
profit_raw = (k_next['close'] - k['close']) / k['close'] * leveraged_position
|
||
fee_open = leveraged_position * FEE_RATE
|
||
fee_close = leveraged_position * FEE_RATE
|
||
profit_net = profit_raw - fee_open - fee_close
|
||
|
||
total_profit += profit_raw
|
||
total_fee += fee_open + fee_close
|
||
|
||
trades.append({
|
||
'方向': '多',
|
||
'开仓时间': k['time'].strftime("%Y-%m-%d %H:%M"),
|
||
'开仓价格': k['close'],
|
||
'平仓时间': k_next['time'].strftime("%Y-%m-%d %H:%M"),
|
||
'平仓价格': k_next['close'],
|
||
'本金': position_usdt,
|
||
'杠杆仓位': leveraged_position,
|
||
'开仓手续费': fee_open,
|
||
'平仓手续费': fee_close,
|
||
'原始盈亏': profit_raw,
|
||
'净盈亏': profit_net
|
||
})
|
||
|
||
# ---------------- 上吊线 → 做空 ----------------
|
||
elif body != 0 and upper_shadow >= 2 * body:
|
||
profit_raw = (k['close'] - k_next['close']) / k['close'] * leveraged_position
|
||
fee_open = leveraged_position * FEE_RATE
|
||
fee_close = leveraged_position * FEE_RATE
|
||
profit_net = profit_raw - fee_open - fee_close
|
||
|
||
total_profit += profit_raw
|
||
total_fee += fee_open + fee_close
|
||
|
||
trades.append({
|
||
'方向': '空',
|
||
'开仓时间': k['time'].strftime("%Y-%m-%d %H:%M"),
|
||
'开仓价格': k['close'],
|
||
'平仓时间': k_next['time'].strftime("%Y-%m-%d %H:%M"),
|
||
'平仓价格': k_next['close'],
|
||
'本金': position_usdt,
|
||
'杠杆仓位': leveraged_position,
|
||
'开仓手续费': fee_open,
|
||
'平仓手续费': fee_close,
|
||
'原始盈亏': profit_raw,
|
||
'净盈亏': profit_net
|
||
})
|
||
|
||
# ---------------- 输出统计 ----------------
|
||
print(f"1月总原始盈亏: {total_profit:.2f} USDT")
|
||
print(f"1月总手续费: {total_fee:.2f} USDT")
|
||
print(f"1月净盈亏: {total_profit - total_fee:.2f} USDT")
|
||
print("\n交易明细(前10笔示例):")
|
||
|
||
n = 0
|
||
for t in trades:
|
||
if t['原始盈亏'] > 10 or t['原始盈亏'] < -10:
|
||
print(f"{t['方向']}仓 | 开仓: {t['开仓时间']} @ {t['开仓价格']:.2f} | "
|
||
f"平仓: {t['平仓时间']} @ {t['平仓价格']:.2f} | "
|
||
f"本金: {t['本金']:.2f} | 杠杆仓位: {t['杠杆仓位']:.2f} | "
|
||
f"开仓手续费: {t['开仓手续费']:.2f} | 平仓手续费: {t['平仓手续费']:.2f} | "
|
||
f"原始盈亏: {t['原始盈亏']:.2f} | 净盈亏: {t['净盈亏']:.2f}")
|
||
|
||
n += t['原始盈亏']
|
||
|
||
print(n)
|
||
|
||
# # ---------------- 绘制 K 线图 + 交易点 ----------------
|
||
# times = [k['time'] for k in data]
|
||
# closes = [k['close'] for k in data]
|
||
#
|
||
# plt.figure(figsize=(16,6))
|
||
# plt.plot(times, closes, color='black', label='ETH 收盘价')
|
||
#
|
||
# for t in trades:
|
||
# open_time = datetime.strptime(t['开仓时间'], "%Y-%m-%d %H:%M")
|
||
# close_time = datetime.strptime(t['平仓时间'], "%Y-%m-%d %H:%M")
|
||
# if t['方向'] == '多':
|
||
# plt.scatter(open_time, t['开仓价格'], color='green', marker='^', s=100, label='多开' if '多开' not in plt.gca().get_legend_handles_labels()[1] else "")
|
||
# plt.scatter(close_time, t['平仓价格'], color='red', marker='v', s=100, label='多平' if '多平' not in plt.gca().get_legend_handles_labels()[1] else "")
|
||
# else:
|
||
# plt.scatter(open_time, t['开仓价格'], color='red', marker='v', s=100, label='空开' if '空开' not in plt.gca().get_legend_handles_labels()[1] else "")
|
||
# plt.scatter(close_time, t['平仓价格'], color='green', marker='^', s=100, label='空平' if '空平' not in plt.gca().get_legend_handles_labels()[1] else "")
|
||
#
|
||
# plt.xlabel('时间')
|
||
# plt.ylabel('价格(USDT)')
|
||
# plt.title('ETH 永续合约 1 月交易回测(100倍杠杆)')
|
||
# plt.legend()
|
||
# plt.grid(True)
|
||
# plt.gcf().autofmt_xdate()
|
||
# plt.show()
|