mplfinance
mplfinance copied to clipboard
Feature Request: Add ability to add rectangles representing price range in mplfinance
Drawing Supply/Demand zones is a common price action methodology to analyze charts. Typically involves drawing a rectangle from a high and low point in a group of candles. Typically this rectangle can be bounded to a time-frame occupied by the said candles or extend to the right. See for example: https://www.flowbank.com/en/research/price-action-trading-strategy-supply-demand-zones
Solution Proposal Like hlines, vlines, alines, tlines - create a first class object rectangle, specifying the 4 point coordinates. Ideally rectangles should take a list of dicts representing each rectangle. All style options like edgecolor, fillcolor, alpha, linewidths should be available for customization. A bonus would be to have an annotation capability to write a text in the rectangle describing the drawing.
Alternatives Tried Tried to leverage alines to draw this using the linewidths. So for example if I needed to draw a rectangle with coordinates between price 250 and 270 from a specific date to today, I tried to draw the aline at 260 with a linewidths of 10. But what I realized is that linewidths doesn't represent the y axis scale but some arbitrary value. So it wasn't possible to draw the desired rectangle. By adjusting the linewidths, I was either overshooting or undercutting the rectangle I needed. Also it was only a trial and error. My suspicion is that if the scale of the figure changed, the linewidths would need to be calibrated again.
Hope my description of the above problem is clear enough
Example
In this example I'm trying to draw a line between a low point of 950.5 and high point of 1072.38. To approximately match the two end points, I drew the aline at the mid point of 1011.44, however arrived at a width of 91.41 by a trial and error, even though the width according to the y-axis would have been 60.94 (in each direction) or 121.88 (total width)
{'alines': [(Timestamp('2021-12-06 05:00:00+0000', tz='UTC'), 1011.44), (Timestamp('2021-12-08 05:00:00+0000', tz='UTC'), 1011.44)], 'colors': ['c'], 'alpha': 0.4, 'linewidths': 91.41000000000008}

Was just reading through https://github.com/matplotlib/mplfinance/issues/42 Gives me hope that a feature like hlines, vlines, alines and tlines started from a request like this. Thanks @DanielGoldfarb for your work in mplfinance. Really useful library to create elegant plots
Reasonable request. Working on a another enhancement presently (that is non-trivial and ultimately will make this, and similar enhancements easier to implement) so maybe in a couple months will get to this.
In the meantime, glad you found #42 ... using alines and tlines as a work-around can certainly help accomplish what you want (but with a bit more work than having a rectangle kwarg). You may also want to take a look at this comment here and the links therein for work-arounds to add text to charts.
By the way, regaring your chart here ... looks great!
I am curious to know; did you make use of the recent marketcolor_overrides enhancement, to obtain your candle colors, or did you use another technique?
@DanielGoldfarb Yes I used the brand new marketcolor_overrides. Works like a charm. Thank you for the feature! Glad you think the rectangle feature is reasonable. Looking forward for the feature to drop.
PS: Thanks for the pointers for the annotations. Will check them out.
with a bit of a battle, I was able to get items added to the chart area (theres probably an easier way and i missed it lol), in this case an annotation with a bounding box (arrow style), you may be able to adapt to a rectangle using other matplotlib annotate functions and a calculation of the size. The reason to post this is the highlight that with a bit of calculation its possible using annotate.
The battle is in the placement, and the margin and the axes position is required, so a call to get_ylim() and margins() is necessary.
# cu_results is a list
y_min, y_max = ax1.get_ylim()
xmargin, ymargin = ax1.margins()
for index in cu_results:
ra = len(data[:index]) / len(data)
ax1.annotate(" ", xy=(ra - 2*xmargin*(ra-0.5), (data.loc[index]['High'] - y_min)/(y_max - y_min)), xycoords ='axes fraction', rotation=-90, size=4, bbox=dict(boxstyle="rarrow,pad=0.3", fc="red",))
mpf.plot(data, ax=ax1, type='candle', addplot=apd )
The reason I went to 'axes fraction' was because i couldnt get the annotate to work in 'data' coordinates (the default), I spent some time on it, but couldnt crack it, the error was that the x-coordinate entered couldnt be of datetime format (which is same as @akarun2405 's original situation)
This code adds the red indicator arrows, i have a similar loop for a 'cd_results' list for the green arrows :)

I'm interested to see if you can adapt this to rectangles.