Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plotting options for y-axis grid increment, volume y-axis labels on the left #295

Closed
tranceitionalMynd opened this issue Dec 7, 2020 · 5 comments
Labels
question Further information is requested

Comments

@tranceitionalMynd
Copy link

tranceitionalMynd commented Dec 7, 2020

If you have them handy, could you point me in the direction of the documentation or lines of mplfinance code where these can be customized please?

I checked the mplfinance and mpl docs on plotting options:
https://github.com/matplotlib/mplfinance/blob/master/examples/styles.ipynb
https://matplotlib.org/tutorials/introductory/customizing.html

But I didn't see configuration options for these 2:

Y-axis grid increment- customizing the price difference between the lines in the grids. Abnormally tall single candlesticks can ruin the proportion of the rest of the candlesticks and price movements. E.g. After the tall single candlestick it looks like there's no or very little price movement (I'm plotting 1 minute and 10s charts). It's hard to judge the price movements and candlestick shapes and patterns since the plot is too zoomed out.

An example use case would be fixing the y-axis height to display .60 cents between bottom and top. That way the proportion would be the same regardless of intraday volatility. When a new value exceeds the bottom or top, the bottom or top y-limit of the plot could be moved there. When older values are outside of the .60 cent range from the newest value they would be out of bounds on the plot and not displayed. Since that's pretty specific, just some tips on where the best place to start would be should help.

Volume y-axis values displayed on the left. I'd like to display the TA addplot y-axis value on the right (and keep the price y-axis values on the right). I think the newest TA values (where the numeric values themselves might have significance) displayed on the right by the newest candlestick makes more sense for me than having the volume values on the right (since volume can be roughly estimated or compared by bar size).

Thanks,
Tyler

@tranceitionalMynd tranceitionalMynd added the question Further information is requested label Dec 7, 2020
@tranceitionalMynd tranceitionalMynd changed the title Plotting options for y-axis grid increment, volume y-axis on left Plotting options for y-axis grid increment, volume y-axis labels on the left Dec 7, 2020
@DanielGoldfarb
Copy link
Collaborator

DanielGoldfarb commented Dec 7, 2020

Hi Tyler,
Thanks for getting involved with mplfinance. Normally I would answer your questions in order, but your second question is simpler (if I understand it correctly) so let me answer that one first:

Volume y-axis values displayed on the left
It sounds to me like you want your volume axes labels and price axis labels on opposite sides, so that you can put your technical analysis axis labels on the same side as the price. In your example you have the price on the right, so you want volume on the left and TA on the right.

Presently, with mplfinance, the only way I can think to put volume and price on opposite sides is if you put an addplot() on the same panel as the volume and specify, in the mpf.make_addplot(), that you want y_on_right=False and secondary_y=True.
This is assuming you are already starting with a style that has y_on_right=True.

As an example:

  • Take the addplot notebook:
  • Run all the cells through cell [14].
  • Then replace the code in cell [15] with the following code:
s  = mpf.make_mpf_style(base_mpf_style='default',y_on_right=True)
apds = mpf.make_addplot((df['PercentB']*100),panel=1,color='g',y_on_right=False,secondary_y=True,ylabel='% B')
mpf.plot(df,type='candle',addplot=apds,volume=True,style=s)

This should give you a plot that looks like this:

image

Let me know if that is what you were looking to do, or if maybe I misunderstood your question.

All the best. --Daniel

(I will answer your question about Y-axis grid increment separately in a little while.)

@DanielGoldfarb
Copy link
Collaborator

Regarding

Y-axis grid increment - customizing the price difference between the lines in the grids. Abnormally tall single candlesticks can ruin the proportion of the rest of the candlesticks and price movements. E.g. After the tall single candlestick it looks like there's no or very little price movement (I'm plotting 1 minute and 10s charts). It's hard to judge the price movements and candlestick shapes and patterns since the plot is too zoomed out.

Correct me if I am wrong, but it sounds to me that what you are looking to do is not so much change the grid increments (which is controled by the location of the major ticks) but rather you want to change the upper and lower limits of the y-axis. This can be done using the kwarg ylim=(ymin,ymax). This kwarg can be passed into either mpf.plot() and/or mpf.make_addplot().

Regarding

When a new value exceeds the bottom or top, the bottom or top y-limit of the plot could be moved there. When older values are outside of the .60 cent range from the newest value they would be out of bounds on the plot and not displayed.

From this, it sounds to me like you are "monitoring" or animating your plot based on new incoming data, and you want to adjust the y-axis limits based on the newest data. If this is correct, then as a demostration of doing this, I would suggest the following:

Take one of my animation demos, for example mpf_animation_macd.py, and in the animation function, just before the call to mpf.plot() (near the bottom of that file) add some code to calculate new y-axis limits, and add the ylim= kwarg to the mpf.plot() call as follows:

    recent = 22
    if len(data) > recent:
        ymin = min(data['Low'][-recent:])
        ymax = max(data['High'][-recent:])
        xtra = (ymax - ymin) *0.02
        ymin -= xtra
        ymax += xtra
    mpf.plot(data,type='candle',addplot=apds,ax=ax_main,volume=ax_volu,ylim=(ymin,ymax))

Then run python mpf_animation_macd.py to see how that works.

Let me know if that helps. All the best. --Daniel

P.S. one last point, just in case you are not aware: typically, when running matplotlib outside of a notebook or lab, you can access the zoom tool in the user interface that allows you to zoom in on a specific portion of the plot. The zoom tool can also be accessed within a notebook if you install the matplotlib jupyter extension.

@tranceitionalMynd
Copy link
Author

Hi @DanielGoldfarb, thanks! Both of your tips and examples help. I'm streaming frames generated with savefig, so I don't have the zoom capability of the stream figured out in my browser yet. Thanks though, I hadn't thought about exploring zoom options.

@tranceitionalMynd
Copy link
Author

tranceitionalMynd commented Dec 8, 2020

I made it a little more complex; something like this seems right for me. For live-streaming/animation I think standardizing the visual magnitude of the price movements and candlestick sizes (by having a constant y-axis and x-axis range) helps keep a particular stock's activity in context. Reducing changes in the y-axis limits and grid positions as much as possible helps you characterize the pattern and trends since there's less shifting around. Since it's live streaming there's a lot of variability in the current tick's values (and potentially the y-axis and grid positions) on a second-by-second basis. Just as important in my use case, there's also variability in the volatility which is hard to visualize if the y-axis doesn't have a fixed height- so being able to visualize the volatility by standardizing the y-axis range is helpful.

This was a really specific use case, so again I appreciate you taking your time to help!
Tyler

def calculate_y_axis_limit(df, prev_y_min, prev_y_max, prev_index):
    fixed_height = 1.0
    #fixed_height = 0.6
    half_height = fixed_height / 2

    current = df.iloc[-1]
    if current.name  == prev_index:
        # Reduce jitter by only adjusting the y-axis if a new bar is created or the new values are out of bounds
        if current['high'] <= prev_y_max and current['low'] >= prev_y_min:
            return prev_y_min,prev_y_max

    ymin = min(df['low'])
    ymax = max(df['high'])
    diff = ymax - ymin
    if diff <= fixed_height:
        mean = df['close'].mean()
        return mean - half_height, mean + half_height

    if len(df) > 1:
        mean = df.head(-1)['close'].mean()
    else:
        mean = df['close']
    # The new value is out of bounds; adjust the boundaries
    if current['high'] > prev_y_max:
        upper_half = ymax - half_height
        if current['close'] > upper_half:
            return current['high'] - fixed_height, current['high']
        # The upper wick is abnormal
        else: # The current bar has an abnormal height
            if len(df) > 1 and current['close'] >= df['high'][-1]:
                # Truncate the wick
                return current['close'] - fixed_height, current['close']
            return current['close'] - half_height, current['close'] + half_height

    assert current['high'] <= prev_y_max
    if current['low'] < prev_y_min:
        lower_half = ymin + half_height
        if current['close'] < lower_half:
            return current['low'], current['low'] + fixed_height
        # The lower wick is abnormal
        else: # The current bar has an abnormal height
            if current['close'] <= df['low'][-1]:
                # Truncate the wick
                return current['close'], current['close'] + fixed_height
            return current['close'] - half_height, current['close'] + half_height

    return prev_y_min,prev_y_max

@DanielGoldfarb
Copy link
Collaborator

Tyler,
Thanks for the feedback. And thanks for sharing your code. I enjoy seeing the things people are doing with mplfinance. If you get a chance, and it's not much trouble, would like seeing a gif or short mp4 of what you've got working.
All the best. --Daniel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants