Segment anchoring problem
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức phù hợp với người mới
- 15/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Cần làm rõ
- Mức độ hoạt động
- Đình trệ
- Công nghệ
- matplotlib, pandas, python
- Lĩnh vực
- data-visualization
Hướng nghiên cứu
Bắt đầu với các entry point add_lines và update_chart trong script được cung cấp, sau đó kiểm tra cách các trục của biểu đồ được xây dựng lại khi thu phóng và điều hướng. Tái hiện chuyển động của đường bằng CSV đính kèm và xác định hành vi neo dự kiến; issue không xác định tệp nào trong repository hoặc test nào.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Hello,
FX_NAS100, 5.csv
I hope I'm not out of line with the problem I can't solve.
I would like to draw a red line and a green line representing the amplitude of the US trading session on the NASDAQ100.
The history is in candlestick units of 5 minutes.
The two lines (for the historical period) should be drawn from the 15:30 candle to the 21:55 candle.
Tracing is correct at first, but the lines move as soon as you use the program's zoom or advance functions.
Perhaps tracing with “axhline” isn't the right solution; I've tried using the xplot method to exploit the position of the reference candle index, but I can't get anywhere.
Do you have any ideas for solving this problem?
Later, I want to draw other lines with different levels, but until I solve this problem, I'm stuck.
Thanks
import` pandas as pd
import mplfinance as mpf
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
from tkinter import ttk
import os
import matplotlib.pyplot as plt
df_bourse = pd.DataFrame([
{'Année': 2022, 'Période': 'Été US', 'Début': '2022-03-14', 'Fin': '2022-03-28', 'Modedate': 1},
{'Année': 2022, 'Période': 'Hiver US', 'Début': '2022-10-31', 'Fin': '2022-11-04', 'Modedate': 1},
{'Année': 2023, 'Période': 'Été US', 'Début': '2023-03-13', 'Fin': '2023-03-24', 'Modedate': 1},
{'Année': 2023, 'Période': 'Hiver US', 'Début': '2023-10-30', 'Fin': '2023-11-03', 'Modedate': 1},
{'Année': 2024, 'Période': 'Été US', 'Début': '2024-03-11', 'Fin': '2024-03-28', 'Modedate': 1},
{'Année': 2024, 'Période': 'Hiver US', 'Début': '2024-10-28', 'Fin': '2024-11-01', 'Modedate': 1}
])
df_bourse['Début'] = pd.to_datetime(df_bourse['Début'])
df_bourse['Fin'] = pd.to_datetime(df_bourse['Fin'])
csv_path = r"C:\Formation Python\FX_NAS100, 5.csv"
df = pd.read_csv(csv_path)
csv_filename = os.path.basename(csv_path)
df["time"] = pd.to_datetime(df["time"], unit='s')
df['date'] = df['time'].dt.date
def determine_modedate(date):
for _, row in df_bourse.iterrows():
if row['Début'].date() <= date <= row['Fin'].date():
return row['Modedate']
return 2
df['Modedate'] = df['date'].apply(determine_modedate)
df['amp_journée'] = 0.0
for day in df['date'].unique():
day_data = df[df['date'] == day]
if not day_data.empty:
modedate = day_data['Modedate'].iloc[0]
if modedate == 1:
start_time = pd.to_datetime("14:30").time()
end_time = pd.to_datetime("21:00").time()
else:
start_time = pd.to_datetime("15:30").time()
end_time = pd.to_datetime("22:00").time()
filtered_data = day_data[(day_data['time'].dt.time >= start_time) & (day_data['time'].dt.time <= end_time)]
if not filtered_data.empty:
high_max = filtered_data['high'].max()
low_min = filtered_data['low'].min()
amplitude = high_max - low_min
df.loc[df['date'] == day, 'amp_journée'] = amplitude
percentages = [25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275]
for p in percentages:
df[f'{p}%'] = df['amp_journée'] * (p / 100)
df[f'-{p}%'] = df['amp_journée'] * (-p / 100)
cols = ['date', 'time', 'open', 'high', 'low', 'close', 'Modedate', 'amp_journée']
percentage_cols = [f'{p}%' for p in percentages] + [f'-{p}%' for p in percentages]
df = df[cols + percentage_cols]
# Interface graphique principale
root = tk.Tk()
root.title("Graphique en chandelier japonais")
root.state('zoomed')
frame = ttk.Frame(root)
frame.pack(fill=tk.BOTH, expand=True)
start_index = 0
num_candles = 100
# Champs pour les pas
step_frame = ttk.Frame(root)
step_frame.pack(side=tk.TOP, fill=tk.X)
tk.Label(step_frame, text="Pas graphique:").pack(side=tk.LEFT, padx=5)
graph_step_entry = ttk.Entry(step_frame, width=5)
graph_step_entry.insert(0, "30")
graph_step_entry.pack(side=tk.LEFT, padx=5)
tk.Label(step_frame, text="Pas zoom:").pack(side=tk.LEFT, padx=5)
zoom_step_entry = ttk.Entry(step_frame, width=5)
zoom_step_entry.insert(0, "30")
zoom_step_entry.pack(side=tk.LEFT, padx=5)
# Fenêtre pour afficher le DataFrame
def show_dataframe():
df_window = tk.Toplevel(root)
df_window.title("Tableau des données")
df_window.state('zoomed')
tree_frame = ttk.Frame(df_window)
tree_frame.pack(fill=tk.BOTH, expand=True)
tree_scroll_y = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL)
tree_scroll_x = ttk.Scrollbar(tree_frame, orient=tk.HORIZONTAL)
tree = ttk.Treeview(tree_frame, yscrollcommand=tree_scroll_y.set, xscrollcommand=tree_scroll_x.set)
tree_scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
tree_scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
tree_scroll_y.config(command=tree.yview)
tree_scroll_x.config(command=tree.xview)
tree.pack(fill=tk.BOTH, expand=True)
df_display = df.copy().reset_index()
numeric_columns = ['amp_journée'] + [col for col in df_display.columns if '%' in col] + ['open', 'high', 'low', 'close']
for column in numeric_columns:
if column in df_display.columns:
df_display[column] = df_display[column].round(2)
tree["columns"] = ["index"] + list(df_display.columns)[1:]
tree["show"] = "headings"
tree.heading("index", text="Index")
tree.column("index", width=50, anchor='center')
for column in df_display.columns[1:]:
tree.heading(column, text=column)
if column == 'time':
tree.column(column, width=200, anchor='center')
else:
tree.column(column, width=100, anchor='center')
for _, row in df_display.iterrows():
tree.insert("", "end", values=[row['index']] + list(row)[1:])
# Champ de saisie pour l'index
index_frame = ttk.Frame(df_window)
index_frame.pack(side=tk.TOP, fill=tk.X)
tk.Label(index_frame, text="Index:").pack(side=tk.LEFT, padx=5)
index_entry = ttk.Entry(index_frame, width=10)
index_entry.pack(side=tk.LEFT, padx=5)
def select_by_index(event=None):
index = index_entry.get()
if index.isdigit():
index = int(index)
for item in tree.get_children():
if int(tree.item(item)['values'][0]) == index:
tree.selection_set(item)
tree.see(item)
break
index_entry.bind('<Return>', select_by_index)
df_window.mainloop()
btn_show_df = ttk.Button(root, text="Afficher le tableau", command=show_dataframe)
btn_show_df.pack(side=tk.TOP, pady=5)
# Ajouter une ligne rouge et verte
def add_lines(ax, df_slice):
try:
unique_dates = df_slice['date'].unique()
for date in unique_dates:
daily_data = df_slice[df_slice['date'] == date]
if daily_data.empty:
continue
modedate = daily_data['Modedate'].iloc[0]
if modedate == 1:
start_time = pd.to_datetime("14:30").time()
end_time = pd.to_datetime("21:00").time()
else:
start_time = pd.to_datetime("15:30").time()
end_time = pd.to_datetime("21:55").time()
filtered_data = daily_data[
(daily_data['time'].dt.time >= start_time) &
(daily_data['time'].dt.time <= end_time)
]
if filtered_data.empty:
continue
max_high = filtered_data['high'].max()
min_low = filtered_data['low'].min()
time_range = df_slice['time']
xmin = (pd.Timestamp.combine(date, start_time) - time_range.min()).total_seconds() / (time_range.max() - time_range.min()).total_seconds()
xmax = (pd.Timestamp.combine(date, end_time) - time_range.min()).total_seconds() / (time_range.max() - time_range.min()).total_seconds()
ax.axhline(y=max_high, color='red', linestyle='--', xmin=xmin, xmax=xmax)
ax.axhline(y=min_low, color='green', linestyle='--', xmin=xmin, xmax=xmax)
except Exception as e:
pass
# fonction pour gérer le mouvement de la souris
def on_mouse_move(event):
if event.inaxes:
x, y = event.xdata, event.ydata
ax = event.inaxes
# Effacer les lignes précédentes
for line in ax.lines:
if line.get_label() in ['crosshair_h', 'crosshair_v']:
line.remove()
# Dessiner les nouvelles lignes
ax.axhline(y=y, color='black', linewidth=0.5, label='crosshair_h')
ax.axvline(x=x, color='black', linewidth=0.5, label='crosshair_v')
# Mettre à jour les données dans la fenêtre
if df_slice is not None and len(df_slice) > 0:
index = max(0, min(int(x), len(df_slice) - 1))
data = df_slice.iloc[index]
info_text = f"Index: {start_index + index}\nOpen: {data['open']:.2f}\nHigh: {data['high']:.2f}\nLow: {data['low']:.2f}\nClose: {data['close']:.2f}\nTime: {data['time']}"
info_window.set(info_text)
# Mise à jour des valeurs X et Y
x_value.set(f"X: {data['time']}")
y_value.set(f"Y: {y:.2f}")
# Redessiner le graphique
fig.canvas.draw_idle()
# Evènement molette de la sourie
def on_scroll(event):
global num_candles
if event.button == 'up':
num_candles = max(num_candles - int(zoom_step_entry.get()), 10)
elif event.button == 'down':
num_candles += int(zoom_step_entry.get())
update_chart()
# Fonctions pour le graphique
def update_chart():
global start_index, num_candles, df_slice, fig
plt.close('all') # Ferme toutes les figures existantes
df_slice = df.iloc[start_index:start_index + num_candles]
if df_slice.empty:
return
df_ohlc = df_slice[['time', 'open', 'high', 'low', 'close']].copy()
df_ohlc.set_index('time', inplace=True)
fig, axlist = mpf.plot(df_ohlc, type='candle', style='charles', title=csv_filename,
ylabel='Prix', volume=False, returnfig=True)
ax = axlist[0]
add_lines(ax, df_slice)
if hasattr(frame, "canvas"):
frame.canvas.get_tk_widget().destroy()
canvas = FigureCanvasTkAgg(fig, master=frame)
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
frame.canvas = canvas
fig.canvas.mpl_connect('motion_notify_event', on_mouse_move)
fig.canvas.mpl_connect('scroll_event', on_scroll)
def increase_candles():
global num_candles
num_candles += int(zoom_step_entry.get())
update_chart()
def decrease_candles():
global num_candles
num_candles = max(num_candles - int(zoom_step_entry.get()), 10) # Minimum de 10 chandeliers
update_chart()
def move_right():
global start_index
start_index += int(graph_step_entry.get())
update_chart()
def move_left():
global start_index
start_index = max(start_index - int(graph_step_entry.get()), 0)
update_chart()
# Boutons
button_frame = ttk.Frame(root)
button_frame.pack(side=tk.BOTTOM, fill=tk.X)
plus_button = ttk.Button(button_frame, text="+", command=decrease_candles)
plus_button.pack(side=tk.LEFT, padx=5, pady=5)
minus_button = ttk.Button(button_frame, text="-", command=increase_candles)
minus_button.pack(side=tk.LEFT, padx=5, pady=5)
left_button = ttk.Button(button_frame, text="←", command=move_left)
left_button.pack(side=tk.LEFT, padx=5, pady=5)
right_button = ttk.Button(button_frame, text="→", command=move_right)
right_button.pack(side=tk.LEFT, padx=5, pady=5)
# Fenêtre d'information
info_frame = ttk.Frame(root)
info_frame.pack(side=tk.BOTTOM, fill=tk.X)
# Sous-frame pour les informations centrées
center_info_frame = ttk.Frame(info_frame)
center_info_frame.pack(side=tk.LEFT, expand=True)
info_window = tk.StringVar()
info_label = ttk.Label(center_info_frame, textvariable=info_window, justify=tk.LEFT)
info_label.pack(pady=10)
# Sous-frame pour les valeurs X et Y à droite
xy_info_frame = ttk.Frame(info_frame)
xy_info_frame.pack(side=tk.RIGHT)
x_value = tk.StringVar()
y_value = tk.StringVar()
x_label = ttk.Label(xy_info_frame, textvariable=x_value, justify=tk.LEFT)
y_label = ttk.Label(xy_info_frame, textvariable=y_value, justify=tk.LEFT)
x_label.pack(padx=10, anchor='w')
y_label.pack(padx=10, anchor='w')
update_chart()
root.mainloop()
- Ngôn ngữ chính
- Python
- Star
- 4.4k
- Fork
- 678
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của matplotlib/mplfinance
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
matplotlib/mplfinance#672 ·
-
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 10/100
matplotlib/mplfinance#700 ·
-
enhancement
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 30/100
matplotlib/mplfinance#695 ·
-
question
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 25/100
matplotlib/mplfinance#691 · 1 bình luận ·
-
question
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 52/100
matplotlib/mplfinance#690 · 5 bình luận ·
Tất cả issue của matplotlib/mplfinance
Issue tương tự
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
stephrobert/dsoxlab#238 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
sublimehq/package_control#1780 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
nwg-piotr/nwg-displays#145 ·