I have been struggling trying to make a program draw a circle containing the corresponding values of a specific range of indices in a MatplotLibAxes
object, here's the data input stored in a variable called df
:
Index | Start Date | Open Price | High Price | Low Price | Close Price | Volume | End Date |
---|---|---|---|---|---|---|---|
0 | 2023-03-12 18:30:00 | 3.996 | 4.038 | 3.988 | 4.008 | 1216259.0 | 2023-03-12 18:44:59.999 |
1 | 2023-03-12 18:45:00 | 4.008 | 4.024 | 3.99 | 3.993 | 638860.0 | 2023-03-12 18:59:59.999 |
2 | 2023-03-12 19:00:00 | 3.993 | 4.024 | 3.992 | 4.019 | 297226.0 | 2023-03-12 19:14:59.999 |
3 | 2023-03-12 19:15:00 | 4.018 | 4.023 | 3.973 | 3.985 | 1101139.0 | 2023-03-12 19:29:59.999 |
4 | 2023-03-12 19:30:00 | 3.986 | 4.003 | 3.976 | 3.993 | 427351.0 | 2023-03-12 19:44:59.999 |
5 | 2023-03-12 19:45:00 | 3.993 | 4.01 | 3.965 | 3.975 | 750141.0 | 2023-03-12 19:59:59.999 |
6 | 2023-03-12 20:00:00 | 3.976 | 3.998 | 3.967 | 3.988 | 552681.0 | 2023-03-12 20:14:59.999 |
7 | 2023-03-12 20:15:00 | 3.989 | 4.009 | 3.983 | 4.004 | 322794.0 | 2023-03-12 20:29:59.999 |
8 | 2023-03-12 20:30:00 | 4.005 | 4.037 | 4.003 | 4.035 | 682787.0 | 2023-03-12 20:44:59.999 |
9 | 2023-03-12 20:45:00 | 4.035 | 4.12 | 4.035 | 4.091 | 2179361.0 | 2023-03-12 20:59:59.999 |
10 | 2023-03-12 21:00:00 | 4.091 | 4.096 | 4.063 | 4.084 | 474021.0 | 2023-03-12 21:14:59.999 |
11 | 2023-03-12 21:15:00 | 4.084 | 4.103 | 4.077 | 4.087 | 480628.0 | 2023-03-12 21:29:59.999 |
12 | 2023-03-12 21:30:00 | 4.086 | 4.107 | 4.076 | 4.086 | 212594.0 | 2023-03-12 21:44:59.999 |
13 | 2023-03-12 21:45:00 | 4.086 | 4.107 | 4.079 | 4.105 | 364555.0 | 2023-03-12 21:59:59.999 |
14 | 2023-03-12 22:00:00 | 4.104 | 4.108 | 4.06 | 4.072 | 474296.0 | 2023-03-12 22:14:59.999 |
15 | 2023-03-12 22:15:00 | 4.072 | 4.257 | 4.069 | 4.232 | 3230671.0 | 2023-03-12 22:29:59.999 |
16 | 2023-03-12 22:30:00 | 4.232 | 4.247 | 4.208 | 4.241 | 851126.0 | 2023-03-12 22:44:59.999 |
17 | 2023-03-12 22:45:00 | 4.241 | 4.276 | 4.218 | 4.254 | 1268534.0 | 2023-03-12 22:59:59.999 |
18 | 2023-03-12 23:00:00 | 4.255 | 4.315 | 4.253 | 4.312 | 1469747.0 | 2023-03-12 23:14:59.999 |
19 | 2023-03-12 23:15:00 | 4.313 | 4.354 | 4.295 | 4.343 | 1352840.0 | 2023-03-12 23:29:59.999 |
20 | 2023-03-12 23:30:00 | 4.344 | 4.479 | 4.336 | 4.464 | 1995492.0 | 2023-03-12 23:44:59.999 |
21 | 2023-03-12 23:45:00 | 4.463 | 4.532 | 4.412 | 4.517 | 2488653.0 | 2023-03-12 23:59:59.999 |
22 | 2023-03-13 00:00:00 | 4.517 | 4.592 | 4.482 | 4.58 | 2140025.0 | 2023-03-13 00:14:59.999 |
23 | 2023-03-13 00:15:00 | 4.58 | 4.695 | 4.552 | 4.625 | 1973254.0 | 2023-03-13 00:29:59.999 |
24 | 2023-03-13 00:30:00 | 4.626 | 4.7 | 4.577 | 4.677 | 2444439.0 | 2023-03-13 00:44:59.999 |
25 | 2023-03-13 00:45:00 | 4.677 | 4.678 | 4.584 | 4.595 | 1353901.0 | 2023-03-13 00:59:59.999 |
26 | 2023-03-13 01:00:00 | 4.594 | 4.601 | 4.528 | 4.528 | 1181759.0 | 2023-03-13 01:14:59.999 |
27 | 2023-03-13 01:15:00 | 4.528 | 4.546 | 4.489 | 4.499 | 785683.0 | 2023-03-13 01:29:59.999 |
28 | 2023-03-13 01:30:00 | 4.499 | 4.507 | 4.473 | 4.49 | 634040.0 | 2023-03-13 01:44:59.999 |
29 | 2023-03-13 01:45:00 | 4.49 | 4.5 | 4.473 | 4.475 | 361538.0 | 2023-03-13 01:59:59.999 |
30 | 2023-03-13 02:00:00 | 4.476 | 4.479 | 4.445 | 4.45 | 507443.0 | 2023-03-13 02:14:59.999 |
31 | 2023-03-13 02:15:00 | 4.451 | 4.457 | 4.422 | 4.43 | 514609.0 | 2023-03-13 02:29:59.999 |
32 | 2023-03-13 02:30:00 | 4.431 | 4.438 | 4.412 | 4.412 | 283667.0 | 2023-03-13 02:44:59.999 |
33 | 2023-03-13 02:45:00 | 4.413 | 4.437 | 4.401 | 4.435 | 443083.0 | 2023-03-13 02:59:59.999 |
34 | 2023-03-13 03:00:00 | 4.435 | 4.451 | 4.411 | 4.418 | 304109.0 | 2023-03-13 03:14:59.999 |
35 | 2023-03-13 03:15:00 | 4.418 | 4.435 | 4.393 | 4.432 | 354457.0 | 2023-03-13 03:29:59.999 |
36 | 2023-03-13 03:30:00 | 4.433 | 4.461 | 4.415 | 4.449 | 256813.0 | 2023-03-13 03:44:59.999 |
37 | 2023-03-13 03:45:00 | 4.45 | 4.462 | 4.435 | 4.439 | 226006.0 | 2023-03-13 03:59:59.999 |
38 | 2023-03-13 04:00:00 | 4.437 | 4.464 | 4.418 | 4.458 | 304705.0 | 2023-03-13 04:14:59.999 |
39 | 2023-03-13 04:15:00 | 4.459 | 4.465 | 4.436 | 4.439 | 288049.0 | 2023-03-13 04:29:59.999 |
When running df.dtypes
it throws
Start Date datetime64[ns]
Open Price float64
High Price float64
Low Price float64
Close Price float64
Volume float64
End Date datetime64[ns]
dtype: object
The code to plot this data input is the following:
import pandas as pd
import matplotlib
import mplfinance as mpf
import matplotlib.pyplot as plt
import datetime
# Don't spend memory ram unnecesary pl0x
matplotlib.use("Agg")
def set_DateTimeIndex(df_trading_pair):
df_trading_pair = df_trading_pair.set_index('Start Date', inplace=False)
# Rename the column names for best practices
df_trading_pair.rename(columns = { "Open Price" : 'Open',
"High Price" : 'High',
"Low Price" : 'Low',
"Close Price" :'Close',
}, inplace = True)
return df_trading_pair
def convert_to_unix_ms(string_date):
date_format = "%d %b '%y %H:%M"
dt = datetime.datetime.strptime(string_date, date_format)
unix_timestamp_ms = int(dt.timestamp() * 1000)
return unix_timestamp_ms
def plot_this(df):
global trading_pair
global start_date
global end_date
df_trading_pair_date_time_index = set_DateTimeIndex(df)
# Define periods
k_period = 14
d_period = 1
smooth_window = 3
stochastic = pd.DataFrame()
stochastic['%K'] = ((df['Close Price'] - df['Low Price'].rolling(k_period).min()) \
/ (df['High Price'].rolling(k_period).max() - df['Low Price'].rolling(k_period).min())) * 100
stochastic['%D'] = stochastic['%K'].rolling(d_period).mean()
stochastic['%SD'] = stochastic['%D'].rolling(smooth_window).mean()
stochastic['UL'] = 80
stochastic['DL'] = 20
# Get the index of the last nan value in the lower bound series
last_index_nan_value = len(stochastic['%D']) - pd.isna(stochastic['%D'])[::-1].argmax() - 1
# Evaluate if there's a pattern
previous_signal = "None"
bearish_indices = []
bearish_entries = []
for i in range(last_index_nan_value+1,len(df)-3):
slice_df = df.iloc[i:i+4]
if (slice_df["Volume"].max() > df["Volume"][slice_df.index[0]-8:slice_df.index[0]]).all():
start = slice_df.index[0]
end = slice_df.index[-1]
# First BEARISH signal
all_stochastics_up = stochastic.loc[start:end][["%D", "%SD"]].ge(stochastic.loc[start:end]["UL"], axis=0).all(axis=1)
all_stochastics_down = stochastic.loc[start:end][["%D", "%SD"]].le(stochastic.loc[start:end]["DL"], axis=0).all(axis=1)
if all_stochastics_up.sum() >= 2 and previous_signal == "None":
previous_signal = "bearish"
bearish_indices.append(stochastic.loc[start:end].index.values.tolist())
# SHORT ENTRY signal
if previous_signal == "bearish":
if df["Start Date"].loc[bearish_indices[-1][-1]] < slice_df["Start Date"].iat[0]:
if ((slice_df[:2]["Close Price"] > slice_df[:2]["Open Price"]).all() and (slice_df[-2:]["Close Price"] < slice_df[-2:]["Open Price"]).all()).all():
start = slice_df.index[0]
end = slice_df.index[-1]
previous_signal = "None"
bearish_entries.append(stochastic.loc[start:end].index.values.tolist())
# Store the plots of the last 120 data rows of upper and lower bounds as well as the entry and exit points
plots_to_add = {"Stochastics":mpf.make_addplot((stochastic[['%K', '%SD', 'UL', 'DL']]), ylim=[0, 100], panel=2, ylabel="Stochastics", y_on_right=False)}
# Plotting
# Create my own `marketcolors` style:
mc = mpf.make_marketcolors(up='#0ECB81',down='#F64670',inherit=True)
# Create my own `MatPlotFinance` style:
s = mpf.make_mpf_style(figcolor='#162125', facecolor= "#162125", marketcolors=mc, y_on_right=True, rc={'font.size':18, 'xtick.color': 'w'}, gridcolor='white', gridstyle='--', edgecolor='white')
# Plot it
candlestick_plot, axlist = mpf.plot(df_trading_pair_date_time_index,
figsize=(20,10),
figratio=(12, 6),
panel_ratios=(5,1,1),
type="candle",
volume=True,
style=s,
tight_layout=True,
datetime_format = '%b %d, %H:%M:%S',
ylabel = "Price ($)",
returnfig=True,
show_nontrading=True,
warn_too_much_data=870, # Silence the Too Much Data Plot Warning by setting a value greater than the amount of rows you want to be plotted
addplot = list(plots_to_add.values()) # Add the stochastic plot as well as the bullish entries to the main plot
)
# Add Title
axlist[0].set_title("APEUSDT - 15m", fontsize=60, style='italic', fontfamily='fantasy', color="white")
# Set the color of the xticks, yticks and ylabel in every axes object
## Main Plot (Candlesticks)
axlist[0].tick_params(axis='y', colors='white')
axlist[0].yaxis.label.set_color('white')
## Volume Indicator
axlist[2].tick_params(axis='y', colors='white')
axlist[2].yaxis.label.set_color('white')
## Stochastics Indicator
axlist[4].tick_params(axis='y', colors='white')
axlist[4].yaxis.label.set_color('white')
# Get the Volume indicator and modify its font size
vol_ax = plt.gcf().axes[2]
vol_ax.yaxis.label.set_size(15)
# Set the x axis label
axlist[0].set_xlabel('Timezone UTC')
# Find the interval between the 7 custom x-tick marks
time_delta = (df["Start Date"].iloc[-1]-df["Start Date"].iloc[last_index_nan_value+1])/6
# Set the locations of the custom x-tick marks
tick_locations = [df["Start Date"].iloc[last_index_nan_value+1] + i*time_delta for i in range(7)]
# Set the labels of the custom x-tick marks
tick_labels = [date.strftime("%b %d, %H:%M") for date in tick_locations]
# Apply the custom x-tick marks and labels
axlist[0].xaxis.set_ticks(tick_locations)
axlist[0].xaxis.set_ticklabels(tick_labels)
# Set the y axis range
ymin_value = pd.concat([df["Low Price"]], axis=0).min()
ymax_value = pd.concat([df["High Price"]], axis=0).max()
axlist[0].set_ylim([ymin_value,ymax_value])
# Save the plot
random_filename = "TEST_APEUSDT"+".png"
candlestick_plot.savefig(random_filename,dpi=300, bbox_inches = "tight")
#RELEASE THE MEMORY RAM
plt.close('all')
The current output when running plot_this(df)
is the following:
Say I'm interested in drawing a purple circle that contains the data of this statement stochastic[["%K","%SD"]][15:19]
and a red circle that contains the data of this statement stochastic[["%K","%SD"]][23:27]
.
The desired output should look something like this (I know these circles look like complete ovals, but they are indeed circles):
I added the following code in the lines between # Get the Volume indicator and modify its font size
and ## Stochastics Indicator
, but it didn't make any difference nor threw any error:
# Define the ranges for the circles
purple_circle = [[15, 16, 17, 18, 19]]
red_circle = [[23, 24, 25, 26, 27]]
# Get the Stochastics subplot
stochastics_ax = axlist[4]
# Draw the purple circle
for range_ in purple_circle:
for i in range(range_[0], range_[-1]+1):
x, y = i, stochastics_ax.lines[0].get_ydata()[i]
circle = Circle((x, y), radius=5, alpha=0.3, color='purple')
stochastics_ax.add_patch(circle)
# Draw the red circle
for range_ in red_circle:
for i in range(range_[0], range_[-1]+1):
x, y = i, stochastics_ax.lines[0].get_ydata()[i]
circle = Circle((x, y), radius=5, alpha=0.3, color='red')
stochastics_ax.add_patch(circle)
I'm open to learn the necessary to fix my code.
The short answer is that a circle can be drawn using a matplotlib Circle Patch (similar to what you have tried already), or by using a circle shaped marker on a scatter plot.
There are problems with the Circle Patch. For example, it requires direct access to the Axes object. Furthermore it may require a coordinates transformation so that it actually appears round.
Using a scatter plot with a circle 'o' scatter marker is a much simpler approach, and can be done without accessing the Axes objects by using mplfinance's mpf.make_addplot(data,type='scatter',...)
. Also, we won't need any coordinate transformations to ensure nice round circles.
Before I show a specific example, since you said "I'm open to learn ... to fix my code
," let me offer some constructive criticism, and I hope it will be accepted in the helpful spirit intended. As a rule, when there is more than one way to code something, simpler is better. First allow me to commend you on the excellent quality of you question overall, clearing describing what you are trying to accomplish, and showing what you have coded so far. That said, some of the code is more complicated than it needs to be. For example:
set_index()
itself, since Pandas has a couple of convenient ways to do that in a single line of code. For example, using read_csv()
or using the Pandas.DatetimeIndex()
constructor:# This tells read_csv which column to use for the index,
# AND it tells it to parse the text into Pandas Timestamp objects:
df = pd.read_csv(filename,index_col='Start Date',parse_dates=True)
# Alternatively, if the dataframe is already in memory, with a 'Start Date' column, then:
df.index = pd.DatetimeIndex(df['Start Date'])
# The above will leave the 'Start Date' column inplace while at the same time using
# it to set the index. The column can then be ignored or deleted.
Axes.tick_params(axis='y', colors='white')
and yaxis.label.set_color('white')
, specify these items using rc=
when calling mpf.make_mpf_style()
s = mpf.make_mpf_style(figcolor='#162125', facecolor= "#162125", marketcolors=mc,
y_on_right=True,gridcolor='white',gridstyle='--',edgecolor='white'
rc={'font.size':18, 'xtick.color': 'w',
'axes.labelsize': 12, 'ytick.color': 'w', # NEW
'ytick.labelcolor': 'w', 'axes.labelcolor':'w'},) # NEW
savefig
and the x-axis label can be set with kwarg xlabel
.figsize
and figratio
does not make sense. Note that figsize
includes both figscale
and figratio
. So either specify figsize
alone, or specify figscale
and figratio
.In summary, if there is a simpler way to do something, choose that way. And along these lines, when using mplfinance if directly accessing the Axes object can be avoided, then it should be avoided. It will keep the code simpler and easier to maintain. From what I can tell the only thing you are trying to do that (presently) requires direct access to the Axes objects is setting the tick locations. That will be available in a future version of mplfinance. Here is a re-written, simplified version of your code that I believe does everything you want except for specifically defining where the xticks will be located. Please note that in the example below, to keep the example simple I hard-coded the location of the circles; however that portion of the code is isolated to into functions so that it can be filled in and made dynamic later. I hope this helps:
Here is the data that you provide, but in csv format:
Index,Start Date,Open Price,High Price,Low Price,Close Price,Volume,End Date
0,2023-03-12 18:30:00,3.996,4.038,3.988,4.008,1216259.0,2023-03-12 18:44:59.999
1,2023-03-12 18:45:00,4.008,4.024,3.99,3.993,638860.0,2023-03-12 18:59:59.999
2,2023-03-12 19:00:00,3.993,4.024,3.992,4.019,297226.0,2023-03-12 19:14:59.999
3,2023-03-12 19:15:00,4.018,4.023,3.973,3.985,1101139.0,2023-03-12 19:29:59.999
4,2023-03-12 19:30:00,3.986,4.003,3.976,3.993,427351.0,2023-03-12 19:44:59.999
5,2023-03-12 19:45:00,3.993,4.01,3.965,3.975,750141.0,2023-03-12 19:59:59.999
6,2023-03-12 20:00:00,3.976,3.998,3.967,3.988,552681.0,2023-03-12 20:14:59.999
7,2023-03-12 20:15:00,3.989,4.009,3.983,4.004,322794.0,2023-03-12 20:29:59.999
8,2023-03-12 20:30:00,4.005,4.037,4.003,4.035,682787.0,2023-03-12 20:44:59.999
9,2023-03-12 20:45:00,4.035,4.12,4.035,4.091,2179361.0,2023-03-12 20:59:59.999
10,2023-03-12 21:00:00,4.091,4.096,4.063,4.084,474021.0,2023-03-12 21:14:59.999
11,2023-03-12 21:15:00,4.084,4.103,4.077,4.087,480628.0,2023-03-12 21:29:59.999
12,2023-03-12 21:30:00,4.086,4.107,4.076,4.086,212594.0,2023-03-12 21:44:59.999
13,2023-03-12 21:45:00,4.086,4.107,4.079,4.105,364555.0,2023-03-12 21:59:59.999
14,2023-03-12 22:00:00,4.104,4.108,4.06,4.072,474296.0,2023-03-12 22:14:59.999
15,2023-03-12 22:15:00,4.072,4.257,4.069,4.232,3230671.0,2023-03-12 22:29:59.999
16,2023-03-12 22:30:00,4.232,4.247,4.208,4.241,851126.0,2023-03-12 22:44:59.999
17,2023-03-12 22:45:00,4.241,4.276,4.218,4.254,1268534.0,2023-03-12 22:59:59.999
18,2023-03-12 23:00:00,4.255,4.315,4.253,4.312,1469747.0,2023-03-12 23:14:59.999
19,2023-03-12 23:15:00,4.313,4.354,4.295,4.343,1352840.0,2023-03-12 23:29:59.999
20,2023-03-12 23:30:00,4.344,4.479,4.336,4.464,1995492.0,2023-03-12 23:44:59.999
21,2023-03-12 23:45:00,4.463,4.532,4.412,4.517,2488653.0,2023-03-12 23:59:59.999
22,2023-03-13 00:00:00,4.517,4.592,4.482,4.58,2140025.0,2023-03-13 00:14:59.999
23,2023-03-13 00:15:00,4.58,4.695,4.552,4.625,1973254.0,2023-03-13 00:29:59.999
24,2023-03-13 00:30:00,4.626,4.7,4.577,4.677,2444439.0,2023-03-13 00:44:59.999
25,2023-03-13 00:45:00,4.677,4.678,4.584,4.595,1353901.0,2023-03-13 00:59:59.999
26,2023-03-13 01:00:00,4.594,4.601,4.528,4.528,1181759.0,2023-03-13 01:14:59.999
27,2023-03-13 01:15:00,4.528,4.546,4.489,4.499,785683.0,2023-03-13 01:29:59.999
28,2023-03-13 01:30:00,4.499,4.507,4.473,4.49,634040.0,2023-03-13 01:44:59.999
29,2023-03-13 01:45:00,4.49,4.5,4.473,4.475,361538.0,2023-03-13 01:59:59.999
30,2023-03-13 02:00:00,4.476,4.479,4.445,4.45,507443.0,2023-03-13 02:14:59.999
31,2023-03-13 02:15:00,4.451,4.457,4.422,4.43,514609.0,2023-03-13 02:29:59.999
32,2023-03-13 02:30:00,4.431,4.438,4.412,4.412,283667.0,2023-03-13 02:44:59.999
33,2023-03-13 02:45:00,4.413,4.437,4.401,4.435,443083.0,2023-03-13 02:59:59.999
34,2023-03-13 03:00:00,4.435,4.451,4.411,4.418,304109.0,2023-03-13 03:14:59.999
35,2023-03-13 03:15:00,4.418,4.435,4.393,4.432,354457.0,2023-03-13 03:29:59.999
36,2023-03-13 03:30:00,4.433,4.461,4.415,4.449,256813.0,2023-03-13 03:44:59.999
37,2023-03-13 03:45:00,4.45,4.462,4.435,4.439,226006.0,2023-03-13 03:59:59.999
38,2023-03-13 04:00:00,4.437,4.464,4.418,4.458,304705.0,2023-03-13 04:14:59.999
39,2023-03-13 04:15:00,4.459,4.465,4.436,4.439,288049.0,2023-03-13 04:29:59.999
And here is the code:
#!/usr/bin/env python
# coding: utf-8
# ---
#
# # Draw circle on plot with mplfinance
#
# ## https://stackoverflow.com/questions/75737197/
#
# ---
# NOTICE we keep it simple:
# These are the only imports we need:
import pandas as pd
import mplfinance as mpf
# The data is stored in 'so75737197_data.csv'
# Only read the columns we need, specify which column will be the index,
# and `parse_dates=True` so that the index will be a DatetimeIndex:
columns_we_need = ['Start Date','Open Price','High Price','Low Price','Close Price','Volume']
# Use the first line down below if you just copiedpasted the data into a txt file and saved it as 'test_ape.txt'
#df = pd.read_csv('test_ape.txt',usecols=columns_we_need,index_col='Start Date',parse_dates=True)
df = pd.read_csv('so75737197_data.csv',
usecols=columns_we_need,index_col='Start Date',parse_dates=True)
# Calculate the stochastics:
k_period = 14
d_period = 1
smooth_window = 3
stochastic = pd.DataFrame()
stochastic['%K'] = ((df['Close Price'] - df['Low Price'].rolling(k_period).min()) \
/ (df['High Price'].rolling(k_period).max() - df['Low Price'].rolling(k_period).min())) * 100
stochastic['%D'] = stochastic['%K'].rolling(d_period).mean()
stochastic['%SD'] = stochastic['%D'].rolling(smooth_window).mean()
stochastic['UL'] = 80
stochastic['DL'] = 20
# Create my own `marketcolors` style:
mc = mpf.make_marketcolors(up='#0ECB81',down='#F64670',inherit=True)
# Create my own `MatPlotFinance` style:
s = mpf.make_mpf_style(figcolor='#162125', facecolor= "#162125", marketcolors=mc, y_on_right=True,
gridcolor='white', gridstyle='--', edgecolor='white',
rc={'font.size':18,'xtick.color': 'w','axes.labelsize': 12,
'ytick.color': 'w', 'ytick.labelcolor': 'w', 'axes.labelcolor':'w'})
def get_stochastic_indicator_purple(df, stochastic):
# Add logic here to determine where the purple circles should be.
# For now, for demonstration purposes,
# we are just hard-coding the 17th position:
# We are going to display the circles using mpf.make_addplot(type='scatter')
# With `mpf.make_addplot()` scatter plots, we want data to exist where we want
# the markers (circles) to appear, and NAN values to exist in all other locations:
circles = [float('nan')]*len(df)
circles[17] = stochastic.iloc[17]['%K']
return circles
def get_stochastic_indicator_red(df, stochastic):
# Add logic here to determine where the red circles should be.
# For now, for demonstration purposes,
# we are just hard-coding the 25th position:
# We are going to display the circles using mpf.make_addplot(type='scatter')
# With `mpf.make_addplot()` scatter plots, we want data to exist where we want
# the markers (circles) to appear, and NAN values to exist in all other locations:
circles = [float('nan')]*len(df)
circles[25] = stochastic.iloc[25]['%K']
return circles
purple_circles = get_stochastic_indicator_purple(df, stochastic)
red_circles = get_stochastic_indicator_red(df, stochastic)
# The purpose of these `range_markers` was to make it easier to know
# how big to make the `markersize` so that the circle would cover
# these ranges as you had requested. Once the correct circle size
# is determined, then the range_markers are no longer needed:
# range_markers = [float('nan')]*len(df)
# range_markers[15] = 50
# range_markers[19] = 50
# range_markers[23] = 50
# range_markers[27] = 50
# Set ylim on the stochastic to make room for the circles and
# also to see the stochastic a little better:
ylimits = (-10,140)
# To make cicles, choose 'o' as the marker for the scatter plot. Normally 'o' will
# create a solid circle for a scatter plot, but by setting `color='None'` and
# `edgecolors=<color>` we can make hollow circles:
plots_to_add = {"Stochastics": mpf.make_addplot(stochastic[['%K', '%SD', 'UL', 'DL']],
ylim=ylimits, panel=2, ylabel="Stochastics",y_on_right=False),
"Purple_Cicles":mpf.make_addplot(purple_circles,type='scatter',markersize=9600,color='None',
edgecolors='purple',marker='o',linewidths=10,panel=2,ylim=ylimits),
"Red_Cicles": mpf.make_addplot(red_circles,type='scatter',markersize=9600,color='None',
edgecolors='red' ,marker='o',linewidths=10,panel=2,ylim=ylimits),
#"RangeMarkers": mpf.make_addplot(range_markers,type='scatter',markersize=250,color="w",
# edgecolors='yellow',marker='^',linewidths=3,panel=2,ylim=(0,140))
}
filename = 'test_apeusdt.png'
mpf.plot(df,columns=columns_we_need[1:],figsize=(18,10),panel_ratios=(5,1.25,2),type="candle",
volume=True,style=s,tight_layout=True,datetime_format='%b %d, %H:%M',ylabel="Price ($)",
show_nontrading=True,warn_too_much_data=870, # Silence the Too Much Data Warning
addplot = list(plots_to_add.values()), # Add the stochastic plot as well as the bullish entries to the main plot
title=dict(title="APEUSDT - 15m", fontsize=40, style='italic', weight='bold', color="white"),
xlabel='Timezone UTC',
savefig=dict(fname=filename,dpi=300,bbox_inches="tight")
)
print('Done: Result is in file "'+filename+'"')
And the result that I get: