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

Feature Request: Volume Profile on a chart with alpha argument #162

Open
PowerrNuller opened this issue Jun 10, 2020 · 17 comments
Open

Feature Request: Volume Profile on a chart with alpha argument #162

PowerrNuller opened this issue Jun 10, 2020 · 17 comments
Labels
enhancement New feature or request

Comments

@PowerrNuller
Copy link

Is your feature request related to a problem? Please describe.
I would like to request an easy way to plot a volume profile on top of a chart on the Y-axis (see image)

Describe the solution you'd like
A function that takes two arguments. Volume and Price. To plot Volume by Price Level.

Describe alternatives you've considered
Haven't found any alternatives or easy ways to go about it. No "overlay" solutions exist?

Additional context
See attached image.

(https://i.stack.imgur.com/GEXCd.png)

@PowerrNuller PowerrNuller added the enhancement New feature or request label Jun 10, 2020
@DanielGoldfarb
Copy link
Collaborator

I did some looking into this and some experimenting with the code. It's a reasonable request. Haven't decided yet whether to provide Volume Profile, or simply provide the means for a horizontal bar chart (with alpha) and let the caller calculate the Volume Profile (which can be done relatively easily with a few lines of Pandas code).

For now this is on the back burner, while working on some other enhancements. Will come back and revisit this in a few weeks.

@manuelwithbmw
Copy link

manuelwithbmw commented Jun 18, 2020

I did some looking into this and some experimenting with the code. It's a reasonable request. Haven't decided yet whether to provide Volume Profile, or simply provide the means for a horizontal bar chart (with alpha) and let the caller calculate the Volume Profile (which can be done relatively easily with a few lines of Pandas code).

For now this is on the back burner, while working on some other enhancements. Will come back and revisit this in a few weeks.

Market Profile is a very interesting charting mode, it normally goes standalone, off candlestick, pretty different. But it would be nice to have a Vertical view. I think this is way more than an enhancement and requires a lot of time and data reorganisation. Good luck

https://ftmo.com/en/market-profile/

@Aclavelar
Copy link

Hi Daniel,

I also use Volume Profile, provided by a trading plataform I am using. As I am interested in creating a kind of screener using Volume Profile, it would be very important to have the ways to do it, as it was possible with the mpl_finance. If you succeed to provide means for a horizontal bar chart and to plot it over the candlestick chart, it would be great! As the image below:

Thanks!

image

@DanielGoldfarb
Copy link
Collaborator

Will implement this at some point. In the meantime, here is a work-around example using one of the data files in the examples/data folder:

import pandas     as pd
import mplfinance as mpf

df = pd.read_csv('examples/data/yahoofinance-SPY-20080101-20180101.csv',index_col=0,parse_dates=True)
df = df.iloc[:150]

bucket_size = 0.0012 * max(df['Close'])
volprofile  = df['Volume'].groupby(df['Close'].apply(lambda x: bucket_size*round(x/bucket_size,0))).sum()

mc = mpf.make_marketcolors(base_mpf_style='yahoo')
s  = mpf.make_mpf_style(base_mpf_style='nightclouds',marketcolors=mc)

fig, axlist = mpf.plot(df,type='candle',returnfig=True,style=s,tight_layout=True)

vpax = fig.add_axes(axlist[0].get_position())
vpax.set_axis_off()
vpax.set_xlim(right=1.2*max(volprofile.values))
vpax.barh( volprofile.keys().values, volprofile.values, height=0.75*bucket_size, align='center', color='cyan', alpha=0.45)

mpf.show()

The result:

Figure_1

@Aclavelar
Copy link

Hi Daniel,

You are a genius!!!

Your attention is outstanding!

Thanks a lot!

@Baappii
Copy link

Baappii commented Sep 22, 2021

Will implement this at some point. In the meantime, here is a work-around example using one of the data files in the examples/data folder:

import pandas     as pd
import mplfinance as mpf

df = pd.read_csv('examples/data/yahoofinance-SPY-20080101-20180101.csv',index_col=0,parse_dates=True)
df = df.iloc[:150]

bucket_size = 0.0012 * max(df['Close'])
volprofile  = df['Volume'].groupby(df['Close'].apply(lambda x: bucket_size*round(x/bucket_size,0))).sum()

mc = mpf.make_marketcolors(base_mpf_style='yahoo')
s  = mpf.make_mpf_style(base_mpf_style='nightclouds',marketcolors=mc)

fig, axlist = mpf.plot(df,type='candle',returnfig=True,style=s,tight_layout=True)

vpax = fig.add_axes(axlist[0].get_position())
vpax.set_axis_off()
vpax.set_xlim(right=1.2*max(volprofile.values))
vpax.barh( volprofile.keys().values, volprofile.values, height=0.75*bucket_size, align='center', color='cyan', alpha=0.45)

mpf.show()

The result:

Figure_1

Hello Daniel ... Thank you for the wonderful work!!
In the above chart is it possible to add "scatter" points. I was able to recreate the chart but would like to add scatter points(and change candle type to "renko"). I was able to change the chart type to renko.
Also my chart is intraday, when i tried to add scatter; it gave me error "x and y must be the same size".
Any insight is aprreciated.
sample data for scatter points:

5115.5     2021-09-21 08:14
5096.0	   2021-09-21 09:30
5032.75	   2021-09-21 09:33
5071.5	   2021-09-21 09:35
5084.25	   2021-09-21 11:32
5059.75	   2021-09-21 12:52
5052.25	   2021-09-21 14:46
5056.5	   2021-09-21 15:50
5041.5     2021-09-21 15:54

image

@DanielGoldfarb
Copy link
Collaborator

please see #448 (comment)

@manuelwithbmw
Copy link

Hey Daniel, long time no speak -- @DanielGoldfarb would you ever be able to remember what is the role of the .apply(lambda...) bit in your market profile code?

volprofile = df['Volume'].groupby(df['Close'].apply(lambda x: bucket_size*round(x/bucket_size,0))).sum()

I am not guessing it and I would have omitted it in my mind, is it a sort of normalisation factor? I noticed this changes the volume chart:

volprofile = df['Volume'].groupby(df['Close']).sum()

Thank you,
Manuel

@AGG2017
Copy link

AGG2017 commented Oct 24, 2021

@manuelwithbmw It is obvious that we have to group the closing price by price slots (bucket_size) and not to be grouped by all available closing prices like in your example.

To select bucket_size by predefined number of price slots we may use:

price_slots = 30
bucket_size = (max(df['Close']) - min(df['Close'])) / price_slots

@DanielGoldfarb
Copy link
Collaborator

DanielGoldfarb commented Oct 24, 2021

This (@AGG2017 's answer above) is correct.


what you suggest:

volprofile = df['Volume'].groupby(df['Close']).sum()

would group together volumes only for close prices that are exactly the same close price as each other, which is very unlikely and therefore you may have as many volume bars as you have prices. Maybe, in some cases, this is what you want.

However, more typically you want to divide the price range into slots or buckets, as @AGG2017 has shown above, and sum the volumes together that belong to a single bucket. That is what the lambda function in this code does, it finds all the closes that are within a given bucket, and sums together the volumes for all the closes in that bucket:

volprofile  = df['Volume'].groupby(df['Close'].apply(lambda x: bucket_size*round(x/bucket_size,0))).sum()

To try to make this explanation a little more clear, what the lambda function is actually doing is rounding all the prices so that all of the prices that fall within a given bucket round to the exact same number (essentially the end of the bucket). In other words, each price is rounded to the nearest whole number of bucket_size's.

@AGG2017
Copy link

AGG2017 commented Oct 24, 2021

BTW, I see a strange behavior of the final plot with the provided upper code example. When you select the last 150 bars of the data frame the issue is not well visible but when we remove the line df = df.iloc[:150] we can see that when placing the cursor over the bottom marked price line as $75 at the upper right corner we see the price as $67.7 and for the upper line labeled as $250 it shows y=255.7. When provided test levels for the volume profile I found the y value at the upper right corner is exactly the volume profile price but the bar prices are marked with the left labels so, volume profile bars at the top and bottom of the chart are a bit offset from the bar prices.
For example this simplified version shows the exact price for vp bars and candle bars but I cannot scale the vp bars size to fit the most of the chart area:

import pandas     as pd
import mplfinance as mpf
df = pd.read_csv('examples/data/yahoofinance-SPY-20080101-20180101.csv',index_col=0,parse_dates=True)
vp_bars_needed = 50
price_slot = (max(df['Close']) - min(df['Close'])) / vp_bars_needed
volprofile  = df['Volume'].groupby(df['Close'].apply(lambda x: price_slot*round(x/price_slot,0))).sum()
vp_y = volprofile.keys().values
vp_x = volprofile.values / 50000000
fig, axlist = mpf.plot(df,type='candle',returnfig=True,style='yahoo',tight_layout=True)
axlist[0].barh( vp_y, vp_x, height=0.75*price_slot, align='center', color='cyan', alpha=0.45)
mpf.show()

@DanielGoldfarb
Copy link
Collaborator

@AGG2017
I will try to make some time this week to take a look at the anomaly you have describe. (I'm guessing maybe it has something to do with how lambda function effectively lines up the volumes; but I can't know until I play with it).

The purpose of df = df.iloc[:150] was for nothing more than to grab a relatively small, interesting section of data from the 'examples/data/yahoofinance-SPY-20080101-20180101.csv' file, for the simple purpose to demonstrating the volume profile technique with enough data to show some up and down trends over time, yet with a small enough data set for the candlesticks to be clearly visible.

There really is no reason to have a similiar line of code in your own code except, as explained here, plotting too many rows may present difficulties in resolving the candlesticks, depending, in part, on the resolution of your display device.

@manuelwithbmw
Copy link

manuelwithbmw commented Oct 25, 2021

Interesting! The market/volume profile technique would need to see all the volumes for the day/the week/etc overlapping the candles in vertical as you did well, and designing one (or more) sort of Gaussian(s) bells around the (PoC) most common(s)/used volume(s) in that timeframe: Point of Control(s). So ideally, we would aggregate all the volumes (minute by minute --or within the chosen bucket size) for a daily Volume Profile, superimposing the Bell to the daily candlestick. All the volumes minute by minute (or within the chosen bucket size) for a weekly Volume Profile, superimposing that Bell to the weekly candlesticks. Anyway this quick code works well and allows me to play with it. Yes - the anomaly should be corrected as price have to be the same between candles and volumes. Personally I am going to tweak df = df.iloc[:nn] to have a number that suit my chosen dataframe and needs.

@AGG2017
Copy link

AGG2017 commented Oct 25, 2021

Long time ago I started processing each intraday data for the tickers I need to have the volume profile for each day and for each week. Then I normalize it to 100% for the POC level and extract all levels >= 40, 60 and 80% as green, yellow and red resistence / support levels. Only one POC is not enough when we may have more than one zone of almost equal traded volume. Also for some strategies it is better this volume profile to be separated as red and green + total according to the close<>open prices. For longer term comparing maybe price*volume will be better because for some volatile stocks the volume @ $100 will be not the same as volume @ $300 which can happen in very short timeframe. I started looking for a code just to plot my already existing database of properly calculated volume profile and found this thread which is very helpful. Just one small offset that need to be fixed.

@grdnryn
Copy link

grdnryn commented Dec 23, 2021

@AGG2017

I have used you little snippet from here (#162 (comment)) to use this volume profile method to plot option strike data on the chart. Thanks!

My question is: Is it possible to move the position of the hbars on the x-axis? Ideally I would like it on the right where the most recent candle is, but really any where apart from this default position as some of the bars extend to the left (negative numbers) and are not visible where it is currently located.

image

@DanielGoldfarb
Copy link
Collaborator

@grdnryn
There are two things you can try, depending on what you mean by:

... move the position of the hbars on the x-axis? Ideally I would like it on the right ...

The first technique is, in the call to barh() add the kwarg left=125 ... however, the number (125) will depend on your specific data, and on the scale of the axis on which you are plotting. It could be that 50 will work, or maybe 400 or larger. You'll have to play around. When you use this technique, the bars still go left to right, but their left side is shifted like this:

Figure_1

The second technique is to call Axes.invert_xaxis() which will make the bars go from right to left as shown below. However when using this technique you must create a new Axes object, different from the one on which the candles are plotted, otherwise the candles will also be inverted! You can see code for creating a new Axes object in my comment above. It looks something like this:

vpax = fig.add_axes(axlist[0].get_position())
vpax.set_axis_off()
vpax.set_xlim(right=1.6*max(vp_x))
vpax.barh( vp_y, vp_x, height=0.75*price_slot, align='center', color='cyan', alpha=0.45)
vpax.invert_xaxis()
mpf.show()

Figure_2

@grdnryn
Copy link

grdnryn commented Dec 23, 2021

Thank you Daniel.
The kwarg left= did the trick. Thought I had tried that, but I was probably doing something else wrong at that point in time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants