Matplotlib绘制Binance K线图仅显示竖线,无蜡烛实体与影线求助
问题描述
我通过Binance API获取了BTCUSDT的1日(1d)周期K线数据,使用Matplotlib绘制图表时,图表可正常显示但仅呈现黑色竖线,无法展示包含开盘价(Open)、最高价(High)、最低价(Low)、收盘价(Close)信息的红绿蜡烛实体及影线。现寻求帮助以实现正常蜡烛图的展示。
原代码如下:
import requests import matplotlib.pyplot as plt import matplotlib.dates as mdates import numpy as np # Binance API endpoint for Kline data url = 'https://api.binance.com/api/v3/klines' # Parameters for the API request symbol = 'BTCUSDT' interval = '1d' limit = 200 # Number of Klines to retrieve (max: 1000) # Prepare the request parameters params = { 'symbol': symbol, 'interval': interval, 'limit': limit } # Send the GET request to the Binance API response = requests.get(url, params=params) data = response.json() # Extracting the relevant data from the API response timestamps = [entry[0] / 1000 for entry in data] opens = [float(entry[1]) for entry in data] highs = [float(entry[2]) for entry in data] lows = [float(entry[3]) for entry in data] closes = [float(entry[4]) for entry in data] # Convert timestamps to readable dates dates = [mdates.epoch2num(timestamp) for timestamp in timestamps] # Plotting the candlestick chart fig, ax = plt.subplots() ax.xaxis_date() candlestick_data = list(zip(dates, opens, highs, lows, closes)) ax.vlines(dates, lows, highs, color='black', linewidth=2) ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d')) # Calculate the moving averages moving_average_7 = np.convolve(closes, np.ones(7) / 7, mode='valid') moving_average_20 = np.convolve(closes, np.ones(20) / 20, mode='valid') moving_average_50 = np.convolve(closes, np.ones(50) / 50, mode='valid') # Determine the corresponding dates for the moving averages moving_average_dates_7 = dates[7 - 1:] # Subtract 1 to align the dates with moving average values moving_average_dates_20 = dates[20 - 1:] # Subtract 1 to align the dates with moving average values moving_average_dates_50 = dates[50 - 1:] # Subtract 1 to align the dates with moving average values # Plotting the moving averages ax.plot(moving_average_dates_7, moving_average_7, color='red', linewidth=1, label='7-day Moving Average') ax.plot(moving_average_dates_20, moving_average_20, color='blue', linewidth=1, label='20-day Moving Average') ax.plot(moving_average_dates_50, moving_average_50, color='orange', linewidth=1, label='50-day Moving Average') # Calculate Bollinger Bands period = 20 # Bollinger Bands period std_dev = np.std(closes[-period:]) # Standard deviation for the period middle_band = np.convolve(closes, np.ones(period) / period, mode='valid') # Middle band is the moving average upper_band = middle_band + 2 * std_dev # Upper band is 2 standard deviations above the middle band lower_band = middle_band - 2 * std_dev # Lower band is 2 standard deviations below the middle band # Plotting the Bollinger Bands ax.plot(dates[period - 1:], upper_band, color='purple', linestyle='--', linewidth=1, label='Upper Band') ax.plot(dates[period - 1:], lower_band, color='purple', linestyle='--', linewidth=1, label='Lower Band') # Add the last values of the indicators to the right axis ax.text(1.02, 0.7, f'Last Price: {closes[-1]:.2f}', transform=ax.transAxes, color='black') ax.text(1.02, 0.6, f'MA7: {moving_average_7[-1]:.2f}', transform=ax.transAxes, color='red') ax.text(1.02, 0.5, f'MA20: {moving_average_20[-1]:.2f}', transform=ax.transAxes, color='blue') ax.text(1.02, 0.4, f'MA50: {moving_average_50[-1]:.2f}', transform=ax.transAxes, color='orange') plt.xticks(rotation=45) plt.title(f'Kline Chart for {symbol} - {interval}') plt.xlabel('Date') plt.ylabel('Price (USDT)') plt.legend() plt.grid(True) plt.show()
问题原因
你的代码仅调用ax.vlines()绘制了高低价的竖线(蜡烛影线),完全未处理开盘价与收盘价组成的蜡烛实体,也未根据涨跌(收盘价和开盘价的大小关系)设置不同颜色,因此只会显示黑色竖线。此外原代码中布林带的计算存在错误:仅取了最后20个收盘价的固定标准差,而非滚动计算每个周期的标准差,导致布林带呈现平行直线,不符合实际逻辑。
解决方案
方案1:手动绘制蜡烛实体(无需额外库)
在原有代码基础上,添加蜡烛实体绘制逻辑,同时修复布林带计算:
修改后的完整代码:
import requests import matplotlib.pyplot as plt import matplotlib.dates as mdates import numpy as np # Binance API endpoint for Kline data url = 'https://api.binance.com/api/v3/klines' # Parameters for the API request symbol = 'BTCUSDT' interval = '1d' limit = 200 # Number of Klines to retrieve (max: 1000) # Prepare the request parameters params = { 'symbol': symbol, 'interval': interval, 'limit': limit } # Send the GET request to the Binance API response = requests.get(url, params=params) data = response.json() # Extracting the relevant data from the API response timestamps = [entry[0] / 1000 for entry in data] opens = [float(entry[1]) for entry in data] highs = [float(entry[2]) for entry in data] lows = [float(entry[3]) for entry in data] closes = [float(entry[4]) for entry in data] # Convert timestamps to readable dates dates = [mdates.epoch2num(timestamp) for timestamp in timestamps] # Plotting the candlestick chart fig, ax = plt.subplots(figsize=(12, 6)) ax.xaxis_date() candlestick_data = list(zip(dates, opens, highs, lows, closes)) # 绘制影线(高低价竖线) ax.vlines(dates, lows, highs, color='black', linewidth=1) # 绘制蜡烛实体 candle_width = 0.4 # 调整蜡烛宽度适配日线周期 for date, open_p, high_p, low_p, close_p in candlestick_data: # 根据涨跌设置颜色 if close_p >= open_p: color = '#00ff00' # 上涨用绿色 bottom_price = open_p top_price = close_p else: color = '#ff0000' # 下跌用红色 bottom_price = close_p top_price = open_p # 添加矩形实体 ax.add_patch(plt.Rectangle( (date - candle_width/2, bottom_price), candle_width, top_price - bottom_price, color=color )) ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d')) # Calculate the moving averages moving_average_7 = np.convolve(closes, np.ones(7) / 7, mode='valid') moving_average_20 = np.convolve(closes, np.ones(20) / 20, mode='valid') moving_average_50 = np.convolve(closes, np.ones(50) / 50, mode='valid') # Determine the corresponding dates for the moving averages moving_average_dates_7 = dates[7 - 1:] moving_average_dates_20 = dates[20 - 1:] moving_average_dates_50 = dates[50 - 1:] # Plotting the moving averages ax.plot(moving_average_dates_7, moving_average_7, color='red', linewidth=1, label='7-day Moving Average') ax.plot(moving_average_dates_20, moving_average_20, color='blue', linewidth=1, label='20-day Moving Average') ax.plot(moving_average_dates_50, moving_average_50, color='orange', linewidth=1, label='50-day Moving Average') # Calculate Bollinger Bands(修复滚动标准差计算) period = 20 # 用滚动窗口计算标准差 rolling_std = [] for i in range(len(closes) - period + 1): window = closes[i:i+period] rolling_std.append(np.std(window)) rolling_std = np.array(rolling_std) middle_band = np.convolve(closes, np.ones(period) / period, mode='valid') upper_band = middle_band + 2 * rolling_std lower_band = middle_band - 2 * rolling_std # Plotting the Bollinger Bands ax.plot(dates[period - 1:], upper_band, color='purple', linestyle='--', linewidth=1, label='Upper Band') ax.plot(dates[period - 1:], lower_band, color='purple', linestyle='--', linewidth=1, label='Lower Band') # Add the last values of the indicators to the right axis ax.text(1.02, 0.7, f'Last Price: {closes[-1]:.2f}', transform=ax.transAxes, color='black') ax.text(1.02, 0.6, f'MA7: {moving_average_7[-1]:.2f}', transform=ax.transAxes, color='red') ax.text(1.02, 0.5, f'MA20: {moving_average_20[-1]:.2f}', transform=ax.transAxes, color='blue') ax.text(1.02, 0.4, f'MA50: {moving_average_50[-1]:.2f}', transform=ax.transAxes, color='orange') plt.xticks(rotation=45) plt.title(f'Kline Chart for {symbol} - {interval}') plt.xlabel('Date') plt.ylabel('Price (USDT)') plt.legend() plt.grid(True) plt.tight_layout() # 自动调整布局,防止日期被截断 plt.show()
方案2:使用mplfinance库(推荐,更简洁专业)
mplfinance是专门为金融K线图设计的库,无需手动绘制蜡烛,还能一键添加均线、布林带等指标。
步骤:
- 安装库:
pip install mplfinance pandas - 修改代码如下:
import requests import pandas as pd import mplfinance as mpf # Binance API endpoint for Kline data url = 'https://api.binance.com/api/v3/klines' # Parameters for the API request symbol = 'BTCUSDT' interval = '1d' limit = 200 # Prepare the request parameters params = { 'symbol': symbol, 'interval': interval, 'limit': limit } # 获取数据并整理成DataFrame response = requests.get(url, params=params) data = response.json() df = pd.DataFrame(data, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume', 'close_time', 'quote_asset_volume', 'number_of_trades', 'taker_buy_base_asset_volume', 'taker_buy_quote_asset_volume', 'ignore']) # 转换数据类型和时间格式 df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') df = df.astype({'open': float, 'high': float, 'low': float, 'close': float}) df.set_index('timestamp', inplace=True) # 设置指标:均线和布林带 apds = [ mpf.make_addplot(df['close'].rolling(7).mean(), color='red', label='7-day MA'), mpf.make_addplot(df['close'].rolling(20).mean(), color='blue', label='20-day MA'), mpf.make_addplot(df['close'].rolling(50).mean(), color='orange', label='50-day MA'), mpf.make_addplot(df['close'].rolling(20).mean() + 2*df['close'].rolling(20).std(), color='purple', linestyle='--', label='Upper Band'), mpf.make_addplot(df['close'].rolling(20).mean() - 2*df['close'].rolling(20).std(), color='purple', linestyle='--', label='Lower Band') ] # 绘制蜡烛图 mpf.plot(df, type='candle', style='yahoo', addplot=apds, title=f'{symbol} {interval} Kline Chart', ylabel='Price (USDT)', figratio=(12,6), tight_layout=True, legend=True)
这个方案代码更简洁,指标计算更准确,且默认自带红绿蜡烛样式。
内容的提问来源于stack exchange,提问作者g_rx
相关产品推荐
相关产品推荐

