93 lines
3.6 KiB
Python
93 lines
3.6 KiB
Python
import csv
|
||
from datetime import datetime, timezone
|
||
import matplotlib.pyplot as plt
|
||
|
||
# ---------------- 配置 ----------------
|
||
CSV_FILE = "bitmart/kline_3.csv" # 你的 CSV 文件路径
|
||
LEVERAGE = 100
|
||
CAPITAL = 10000
|
||
POSITION_RATIO = 0.01
|
||
FEE_RATE = 0.00015
|
||
|
||
# ---------------- 读取 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']),
|
||
})
|
||
|
||
# ---------------- 识别交易信号 ----------------
|
||
trades = []
|
||
position_usdt = CAPITAL * POSITION_RATIO
|
||
leveraged_position = position_usdt * LEVERAGE
|
||
|
||
for i in range(len(data)-1):
|
||
k1 = data[i]
|
||
k2 = data[i+1]
|
||
|
||
# 刺透形态(Piercing Line,多头)
|
||
if k1['close'] < k1['open'] and k2['close'] > k2['open']:
|
||
midpoint = (k1['open'] + k1['close']) / 2
|
||
if k2['open'] < k1['close'] and k2['close'] > midpoint:
|
||
trades.append({
|
||
'方向': '多',
|
||
'开仓时间': k2['time'],
|
||
'开仓价格': k2['open'],
|
||
'平仓时间': k2['time'],
|
||
'平仓价格': k2['close']
|
||
})
|
||
|
||
# 乌云盖顶(Dark Cloud Cover,空头)
|
||
elif k1['close'] > k1['open'] and k2['close'] < k2['open']:
|
||
midpoint = (k1['open'] + k1['close']) / 2
|
||
if k2['open'] > k1['close'] and k2['close'] < midpoint:
|
||
trades.append({
|
||
'方向': '空',
|
||
'开仓时间': k2['time'],
|
||
'开仓价格': k2['open'],
|
||
'平仓时间': k2['time'],
|
||
'平仓价格': k2['close']
|
||
})
|
||
|
||
# ---------------- 绘制 K 线图 ----------------
|
||
plt.figure(figsize=(16,6))
|
||
|
||
times = [k['time'] for k in data]
|
||
opens = [k['open'] for k in data]
|
||
closes = [k['close'] for k in data]
|
||
highs = [k['high'] for k in data]
|
||
lows = [k['low'] for k in data]
|
||
|
||
# 绘制 K 线(用竖线表示最高最低价,用矩形表示开收盘价)
|
||
for i in range(len(data)):
|
||
color = 'green' if closes[i] >= opens[i] else 'red'
|
||
plt.plot([times[i], times[i]], [lows[i], highs[i]], color='black') # 高低价
|
||
plt.plot([times[i]-0.0005, times[i]+0.0005], [opens[i], opens[i]], color=color, linewidth=5) # 开盘价
|
||
plt.plot([times[i]-0.0005, times[i]+0.0005], [closes[i], closes[i]], color=color, linewidth=5) # 收盘价
|
||
|
||
# ---------------- 标注交易信号 ----------------
|
||
for t in trades:
|
||
if t['方向'] == '多':
|
||
plt.scatter(t['开仓时间'], t['开仓价格'], color='green', marker='^', s=100, label='多开' if '多开' not in plt.gca().get_legend_handles_labels()[1] else "")
|
||
plt.scatter(t['平仓时间'], t['平仓价格'], color='red', marker='v', s=100, label='多平' if '多平' not in plt.gca().get_legend_handles_labels()[1] else "")
|
||
else:
|
||
plt.scatter(t['开仓时间'], t['开仓价格'], color='red', marker='v', s=100, label='空开' if '空开' not in plt.gca().get_legend_handles_labels()[1] else "")
|
||
plt.scatter(t['平仓时间'], 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 月交易回测(刺透 & 乌云形态)')
|
||
plt.legend()
|
||
plt.grid(True)
|
||
plt.gcf().autofmt_xdate()
|
||
plt.show()
|