mirror of
https://github.com/xavierchuan/FX-ML-Trading-Engine.git
synced 2026-07-27 18:17:44 +00:00
139 lines
4.1 KiB
Python
139 lines
4.1 KiB
Python
# scripts/plot_indicators.py
|
|
import os
|
|
from datetime import datetime
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
import plotly.graph_objects as go
|
|
from plotly.subplots import make_subplots
|
|
|
|
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
|
DERIVED_DATA_DIR = os.path.join(BASE_DIR, "data", "derived")
|
|
CHARTS_DIR = os.path.join(BASE_DIR, "charts")
|
|
os.makedirs(CHARTS_DIR, exist_ok=True)
|
|
|
|
DATA_PATH = os.path.join(DERIVED_DATA_DIR, "EURUSD_H1_with_indicators.csv")
|
|
|
|
# 自动生成带时间戳的输出文件名
|
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M")
|
|
OUTPUT_PATH = os.path.join(CHARTS_DIR, f"EURUSD_H1_with_indicators_{timestamp}.html")
|
|
|
|
df = pd.read_csv(DATA_PATH, parse_dates=["time"])
|
|
|
|
# 计算均线(若已存在将覆盖为最新计算)
|
|
if {"close"}.issubset(df.columns):
|
|
df["SMA_20"] = df["close"].rolling(20).mean()
|
|
df["SMA_200"] = df["close"].rolling(200).mean()
|
|
|
|
# 创建两行子图,共享x轴
|
|
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
|
|
vertical_spacing=0.1,
|
|
row_heights=[0.7, 0.3],
|
|
specs=[[{"type": "candlestick"}],
|
|
[{"secondary_y": True}]])
|
|
|
|
# 第一个子图:蜡烛图 + 均线
|
|
fig.add_trace(go.Candlestick(
|
|
x=df['time'],
|
|
open=df['open'],
|
|
high=df['high'],
|
|
low=df['low'],
|
|
close=df['close'],
|
|
name='Candlestick'
|
|
), row=1, col=1)
|
|
|
|
if 'SMA_20' in df.columns:
|
|
fig.add_trace(go.Scatter(
|
|
x=df['time'], y=df['SMA_20'],
|
|
line=dict(color='blue', width=1),
|
|
name='SMA 20'
|
|
), row=1, col=1)
|
|
|
|
if 'EMA_50' in df.columns:
|
|
fig.add_trace(go.Scatter(
|
|
x=df['time'], y=df['EMA_50'],
|
|
line=dict(color='orange', width=1),
|
|
name='EMA 50'
|
|
), row=1, col=1)
|
|
|
|
# 绘制 SMA 200
|
|
if 'SMA_200' in df.columns:
|
|
fig.add_trace(go.Scatter(
|
|
x=df['time'], y=df['SMA_200'],
|
|
line=dict(width=1),
|
|
name='SMA 200'
|
|
), row=1, col=1)
|
|
|
|
# 金叉/死叉标记:SMA20 与 SMA200 交叉
|
|
if 'SMA_20' in df.columns and 'SMA_200' in df.columns:
|
|
sign = np.sign(df["SMA_20"] - df["SMA_200"])
|
|
cross = sign.diff().fillna(0).ne(0) & df["SMA_20"].notna() & df["SMA_200"].notna()
|
|
golden = cross & (sign > 0)
|
|
dead = cross & (sign < 0)
|
|
|
|
# 金叉
|
|
fig.add_trace(go.Scatter(
|
|
x=df.loc[golden, "time"], y=df.loc[golden, "SMA_20"],
|
|
mode="markers", name="Golden Cross",
|
|
marker_symbol="triangle-up", marker_size=9
|
|
), row=1, col=1)
|
|
|
|
# 死叉
|
|
fig.add_trace(go.Scatter(
|
|
x=df.loc[dead, "time"], y=df.loc[dead, "SMA_20"],
|
|
mode="markers", name="Dead Cross",
|
|
marker_symbol="triangle-down", marker_size=9
|
|
), row=1, col=1)
|
|
|
|
# 第二个子图:RSI 和 MACD
|
|
rsi_exists = 'RSI' in df.columns
|
|
macd_exists = 'MACD' in df.columns and 'MACD_signal' in df.columns and 'MACD_hist' in df.columns
|
|
|
|
if rsi_exists:
|
|
fig.add_trace(go.Scatter(
|
|
x=df['time'], y=df['RSI'],
|
|
line=dict(color='purple', width=1),
|
|
name='RSI'
|
|
), row=2, col=1, secondary_y=False)
|
|
|
|
if macd_exists:
|
|
# MACD 柱状图
|
|
fig.add_trace(go.Bar(
|
|
x=df['time'], y=df['MACD_hist'],
|
|
marker_color='grey',
|
|
name='MACD Hist'
|
|
), row=2, col=1, secondary_y=True)
|
|
# MACD 线
|
|
fig.add_trace(go.Scatter(
|
|
x=df['time'], y=df['MACD'],
|
|
line=dict(color='blue', width=1),
|
|
name='MACD'
|
|
), row=2, col=1, secondary_y=True)
|
|
# MACD 信号线
|
|
fig.add_trace(go.Scatter(
|
|
x=df['time'], y=df['MACD_signal'],
|
|
line=dict(color='orange', width=1, dash='dot'),
|
|
name='MACD Signal'
|
|
), row=2, col=1, secondary_y=True)
|
|
|
|
# 布局设置
|
|
fig.update_layout(
|
|
title="EUR/USD with Technical Indicators",
|
|
xaxis_title="Time",
|
|
yaxis_title="Price",
|
|
xaxis_rangeslider_visible=False,
|
|
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1)
|
|
)
|
|
|
|
# RSI y轴范围限制
|
|
if rsi_exists:
|
|
fig.update_yaxes(title_text="RSI", row=2, col=1, secondary_y=False, range=[0, 100])
|
|
|
|
# MACD y轴标题
|
|
if macd_exists:
|
|
fig.update_yaxes(title_text="MACD", row=2, col=1, secondary_y=True)
|
|
|
|
# 保存图表
|
|
fig.write_html(OUTPUT_PATH)
|
|
print(f"✅ 图表已保存至 {OUTPUT_PATH}")
|