Reputation: 983
My very 1st need is to overlay a curve over a candlestick chart.
To draw this candlestick chart, mplfinance
appears very nice. Unfortunately, I have found no way to overlay additional curve to the candlestick.
Considering example below, if anyone of you knows how to overlay 'Noise' column over the candlesticks drawn from 'minutely' dataframe, this would be great!
import pandas as pd
import mplfinance as mpf
minutely = pd.DataFrame({'Date':[pd.Timestamp('2021-01-07 00:00:00'),
pd.Timestamp('2021-01-07 00:01:00'),
pd.Timestamp('2021-01-07 00:02:00'),
pd.Timestamp('2021-01-07 00:03:00'),
pd.Timestamp('2021-01-07 00:04:00')],
'Open':[36769.36, 36880.00, 36851.42,36922.19,37083.18],
'High':[36880.00, 36880.00, 36950.00, 37089.69, 37094.70],
'Low': [36760.00, 36817.64, 36810.03, 36922.13, 36565.49],
'Close':[36880.00, 36851.97, 36922.14, 37075.80, 36691.3]})
noise = pd.DataFrame({'Date':[pd.Timestamp('2021-01-07 00:00:00'),
pd.Timestamp('2021-01-07 00:01:00'),
pd.Timestamp('2021-01-07 00:02:00'),
pd.Timestamp('2021-01-07 00:03:00'),
pd.Timestamp('2021-01-07 00:04:00')],
'Noise':[36779.36, 36870.00, 36881.42,36902.19,37103.18]})
# Draw candlesticks
minutely = minutely.set_index('Date')
noise = noise.set_index('Date')
mpf.plot(minutely, type='candle')
Not stopping here, I had in mind to use the 'old' candlestick_ohlcv
function to draw a candlestick graph, then overlay data using native matplotlib capabilities.
This gives the code below, but when displaying the candlesticks, the x scale appears meaningless.
I should have only 5 candles, with a x scale going from 2020/01/07 00:00 to 2020/01/07 00:04.
I can see the graph shows a x scale starting from 2020/01/06 16:48 to 2020/01/07 07:12.
I don't understand this and candles are meaningless...
import pandas as pd
import matplotlib.pyplot as plt
from mplfinance.original_flavor import candlestick_ohlc
import matplotlib.dates as mpdates
minutely = pd.DataFrame({'Date':[pd.Timestamp('2021-01-07 00:00:00'),
pd.Timestamp('2021-01-07 00:01:00'),
pd.Timestamp('2021-01-07 00:02:00'),
pd.Timestamp('2021-01-07 00:03:00'),
pd.Timestamp('2021-01-07 00:04:00')],
'Open':[36769.36, 36880.00, 36851.42,36922.19,37083.18],
'High':[36880.00, 36880.00, 36950.00, 37089.69, 37094.70],
'Low': [36760.00, 36817.64, 36810.03, 36922.13, 36565.49],
'Close':[36880.00, 36851.97, 36922.14, 37075.80, 36691.3]})
noise = pd.DataFrame({'Date':[pd.Timestamp('2021-01-07 00:00:00'),
pd.Timestamp('2021-01-07 00:01:00'),
pd.Timestamp('2021-01-07 00:02:00'),
pd.Timestamp('2021-01-07 00:03:00'),
pd.Timestamp('2021-01-07 00:04:00')],
'Noise':[36779.36, 36870.00, 36881.42,36902.19,37103.18]})
minutely['Date'] = minutely['Date'].map(mpdates.date2num)
plt.style.use('dark_background')
fig, ax = plt.subplots()
candlestick_ohlc(ax, minutely.values, width = 0.6,
colorup = 'green', colordown = 'red',
alpha = 0.8)
# Setting labels
ax.set_xlabel('Date')
ax.set_ylabel('Price')
# Formatting Date
date_format = mpdates.DateFormatter('%d-%m-%Y %H:%M')
ax.xaxis.set_major_formatter(date_format)
fig.autofmt_xdate()
fig.tight_layout()
# show the plot
plt.show()
Please, would someone know of a way to overlay this external data to candlestick data? Thanks in advance for any help, Bests,
Upvotes: 3
Views: 3435
Reputation: 7714
You can do this by adding only one line of code to your first code example above:
Just before calling mpf.plot()
add the following line:
ap = mpf.make_addplot(noise)
Then change the call to mpf.plot()
to include the addplot
keyword, thus:
ap = mpf.make_addplot(noise)
mpf.plot(minutely, type='candle', addplot=ap)
If you want to, you can also modify the datetime format:
ap = mpf.make_addplot(noise)
mpf.plot(minutely, type='candle', addplot=ap, datetime_format='%b %d, %H:%M')
I would highly recommend that you read through these two tutorials. They are relatively short and will probably take only 15 to 30 minutes to carefully read both of them:
P.S. As a general rule I would discourage gaining access to the Figure and Axes objects of mplfinance: your code will be much simpler as a result. Access to the Figure and Axes should only be used for plots that require advanced features not yet supported by mplfinance. If you read through the tutorials, I'm sure you will find that most things done with financial plots can be done simply without resorting to manipulating the Figure and Axes directly.
Upvotes: 4
Reputation: 3630
You can overlay a plot on top of the candlestick chart by using the returnfig=True
argument to get the matplotlib Figure and Axes objects. There are two axes returned: primary and secondary. In the following example based on the sample that you have provided, the noise line plot is created using the primary axes.
Note that mpf.plot
returns a figure where the x-axis scale is made of integer units starting from zero by default (like a pandas bar chart). This is because the plotting function is built to visualize data for trading hours and not a continuous datetime variable which would include many gaps for non-trading hours. This behavior can be changed by setting show_nontrading=True
. In the following example, I provide a solution for both alternatives, using the pandas plotting function to plot the line as it is slightly more convenient to use compared to matplotlib:
import pandas as pd # v 1.1.3
import matplotlib.pyplot as plt # v 3.3.2
import matplotlib.dates as mpdates
import mplfinance as mpf # v 0.12.7a4
from mplfinance.original_flavor import candlestick_ohlc
# Create sample data
dti = pd.date_range('2021-01-07', periods=5, freq='min')
minutely = pd.DataFrame({'Open':[36769.36, 36880.00, 36851.42,36922.19,37083.18],
'High':[36880.00, 36880.00, 36950.00, 37089.69, 37094.70],
'Low': [36760.00, 36817.64, 36810.03, 36922.13, 36565.49],
'Close':[36880.00, 36851.97, 36922.14, 37075.80, 36691.3]},
index=dti)
noise = pd.DataFrame({'Noise':[36779.36, 36870.00, 36881.42,36902.19,37103.18]},
index=dti)
# Create candlestick chart overlaid with a pandas line plot
fig, (ax1, ax2) = mpf.plot(minutely, type='candle', returnfig=True, figsize=(6,4))
noise.plot(ax=ax1, use_index=False);
# # Create same figure including non-trading hours, in this case the datetime
# # variable is used for the x-axis scale
# fig, (ax1, ax2) = mpf.plot(minutely, type='candle', show_nontrading=True,
# returnfig=True, figsize=(6,4))
# noise.plot(ax=ax1, x_compat=True);
Regarding the second part of your question, the docstring of the old candlestick_ohlcv
function states that the width
is in terms of a fraction of a day (which corresponds to matplotlib date units). The sample data spans just a few minutes but you have set width=0.6
(more than half a day) which produces very wide candlesticks making the plot unreadable. Setting width=0.0003
seems to work well. Another thing that needs to be adjusted is the x ticks as they seem to be placed at somewhat random locations. Here is an example using the same data as above:
# Edit minutely dataframe for use with candlestick_ohlc function
minutely['Date'] = mpdates.date2num(minutely.index)
minutely = minutely[['Date', 'Open', 'High', 'Low', 'Close']]
# Create candlestick chart overlaid with a pandas line plot
plt.style.use('dark_background')
fig, ax = plt.subplots(figsize=(6,4))
candlestick_ohlc(ax, minutely.values, width=0.0003,
colorup='green', colordown='red', alpha=0.8)
noise.plot(ax=ax, x_compat=True)
# Set labels
ax.set_xlabel('Date')
ax.set_ylabel('Price')
# Create ticks that match the locations of the candlesticks and format labels
ax.set_xticks(minutely['Date'])
date_format = mpdates.DateFormatter('%H:%M\n%d-%m-%Y ')
ax.xaxis.set_major_formatter(date_format)
fig.autofmt_xdate(rotation=0, ha='center')
References: this answer by Daniel Goldfarb (the current mplfinance package maintainer); pandas plotting function, and the x_compat
argument used to convert the pandas plot date units to matplotlib date units
Upvotes: 2