特斯拉股票K线图EMA线与主图分离问题咨询
问题:EMA线与K线主图分离无法对齐
运行代码后,本应叠加在特斯拉股票K线图上的4条EMA线与主图出现分离,无法对齐显示。

原测试代码如下:
import yfinance as yf import mplfinance as mpf import matplotlib.pyplot as plt import matplotlib.patches as mpatches import pandas as pd # Dates to get stock data start_date = "2010-07-01" end_date = "2023-06-17" # Fetch Tesla stock data tesla_data = yf.download("TSLA", start=start_date, end=end_date) tesla_weekly_data = tesla_data.resample("W").agg( {"Open": "first", "High": "max", "Low": "min", "Close": "last", "Volume": "sum"} ).dropna() # Get the latest closing price latest_price = tesla_weekly_data['Close'][-1] # Create additional plot close_price = tesla_weekly_data['Close'] apd = mpf.make_addplot(close_price, color='cyan', width=2) # Calculate the EMA with different lengths ema_lengths = [8, 13, 21, 55] ema_colors = ['blue', 'green', 'yellow', 'red'] ema_lines = [] for length, color in zip(ema_lengths, ema_colors): ema_line = tesla_weekly_data['Close'].ewm(span=length, adjust=False).mean() ema_lines.append(ema_line) # Plot the candlestick chart with EMA lines fig, axes = mpf.plot(tesla_weekly_data, type='candle', addplot=apd, style='yahoo', title='Tesla Stock Prices', ylabel='Price', xlabel='Date', volume=True, ylabel_lower='Volume', volume_panel=1, figsize=(16, 8), returnfig=True) # Move the y-axis labels to the left side axes[0].yaxis.tick_left() axes[1].yaxis.tick_left() # Adjust the position of the y-axis label for price axes[0].yaxis.set_label_coords(-0.08, 0.5) # Adjust the position of the y-axis label for volume axes[1].yaxis.set_label_coords(-0.08, 0.5) # Set y-axis label for price and volume axes[0].set_ylabel('Price', rotation=0, labelpad=20) axes[1].set_ylabel('Volume', rotation=0, labelpad=20) # Make the legend box handles = axes[0].get_legend_handles_labels()[0] red_patch = mpatches.Patch(color='red') green_patch = mpatches.Patch(color='green') cyan_patch = mpatches.Patch(color='cyan') handles = handles[:2] + [red_patch, green_patch, cyan_patch] labels = ["Price Up", "Price Down", "Closing Price"] axes[0].legend(handles=handles, labels=labels) # Add a box to display the current price latest_price_text = f"Current Price: ${latest_price:.2f}" box_props = dict(boxstyle='round', facecolor='white', edgecolor='black', alpha=0.8) axes[0].text(0.02, 0.95, latest_price_text, transform=axes[0].transAxes, fontsize=12, verticalalignment='top', bbox=box_props) # Add EMA lines for ema_line, color in zip(ema_lines, ema_colors): axes[0].plot(ema_line, color=color) # Display the chart plt.show()
问题原因
直接用axes[0].plot()添加EMA线时,matplotlib会将pandas的DatetimeIndex默认转换为从0开始的整数索引绘制,但mplfinance的主图x轴是基于实际日期的坐标系统,两者x轴刻度不匹配,导致EMA线偏移分离。
解决方法
使用mplfinance提供的mpf.make_addplot()方法创建EMA线的绘图对象,将所有需要叠加的线条(收盘价线+EMA线)统一传入mpf.plot()的addplot参数,让mplfinance统一处理坐标轴对齐。
修正后的代码如下:
import yfinance as yf import mplfinance as mpf import matplotlib.pyplot as plt import matplotlib.patches as mpatches import pandas as pd # Dates to get stock data start_date = "2010-07-01" end_date = "2023-06-17" # Fetch Tesla stock data tesla_data = yf.download("TSLA", start=start_date, end=end_date) tesla_weekly_data = tesla_data.resample("W").agg( {"Open": "first", "High": "max", "Low": "min", "Close": "last", "Volume": "sum"} ).dropna() # Get the latest closing price latest_price = tesla_weekly_data['Close'][-1] # Create additional plots: 收盘价线 + 所有EMA线 add_plots = [] # 添加收盘价线 add_plots.append(mpf.make_addplot(tesla_weekly_data['Close'], color='cyan', width=2)) # Calculate the EMA with different lengths and add to add_plots ema_lengths = [8, 13, 21, 55] ema_colors = ['blue', 'green', 'yellow', 'red'] for length, color in zip(ema_lengths, ema_colors): ema_line = tesla_weekly_data['Close'].ewm(span=length, adjust=False).mean() add_plots.append(mpf.make_addplot(ema_line, color=color)) # Plot the candlestick chart with all add plots fig, axes = mpf.plot(tesla_weekly_data, type='candle', addplot=add_plots, # 传入所有叠加图对象 style='yahoo', title='Tesla Stock Prices', ylabel='Price', xlabel='Date', volume=True, ylabel_lower='Volume', volume_panel=1, figsize=(16, 8), returnfig=True) # Move the y-axis labels to the left side axes[0].yaxis.tick_left() axes[1].yaxis.tick_left() # Adjust the position of the y-axis label for price axes[0].yaxis.set_label_coords(-0.08, 0.5) # Adjust the position of the y-axis label for volume axes[1].yaxis.set_label_coords(-0.08, 0.5) # Set y-axis label for price and volume axes[0].set_ylabel('Price', rotation=0, labelpad=20) axes[1].set_ylabel('Volume', rotation=0, labelpad=20) # Make the legend box handles = axes[0].get_legend_handles_labels()[0] # 添加EMA线的图例补丁 ema_patches = [mpatches.Patch(color=color, label=f'EMA-{length}') for length, color in zip(ema_lengths, ema_colors)] red_patch = mpatches.Patch(color='red') green_patch = mpatches.Patch(color='green') cyan_patch = mpatches.Patch(color='cyan', label='Closing Price') handles = handles[:2] + [red_patch, green_patch, cyan_patch] + ema_patches labels = ["Price Up", "Price Down", "Closing Price"] + [f'EMA-{length}' for length in ema_lengths] axes[0].legend(handles=handles, labels=labels) # Add a box to display the current price latest_price_text = f"Current Price: ${latest_price:.2f}" box_props = dict(boxstyle='round', facecolor='white', edgecolor='black', alpha=0.8) axes[0].text(0.02, 0.95, latest_price_text, transform=axes[0].transAxes, fontsize=12, verticalalignment='top', bbox=box_props) # Display the chart plt.show()
内容的提问来源于stack exchange,提问作者Damian
相关产品推荐
相关产品推荐

