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

More easily Plot Trades or Trade Signals #49

Open
thegamecat opened this issue Mar 10, 2020 · 15 comments
Open

More easily Plot Trades or Trade Signals #49

thegamecat opened this issue Mar 10, 2020 · 15 comments
Labels
enhancement New feature or request

Comments

@thegamecat
Copy link

Is your feature request related to a problem? Please describe.
Your addplot.ipynb page is phenomenal and I was able to figure out that I can add scatter points by;

  1. Making a numpy array empty/zero
    trs = np.zeros((length_to_add, 1))
  2. Filling it with Nans
    trs.fill(np.nan)
  3. Setting my 2 scatter points as I know the index (x) and y values
    trs[x] = y
  4. Adding this to a dataframe
    toplot.insert(6, "trades", trs, True)
  5. Then using your well documented addplot:
    apdict = mpf.make_addplot(toplot['trades'],scatter=True,secondary_y=False)
    mpf.plot(toplot,type='candle',volume=True,addplot=apdict)

Describe the solution you'd like
While this is great it took a lot of energy - I'm moving from the plotpy (for the candles!) and there I simply wrote:
plt.scatter(trade_list_idx,trade_list_price,c='b')

Which was simpler than messing around with a dataframe and so on.

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

DanielGoldfarb commented Mar 10, 2020

A few points

  1. While I appreciate that using addplot to scatter-plot trades may not be as simple as you might expect, it is much simpler than you have illustrated above. For example, you can insert a column of nans into a dataframe in a single line of code: df['trades'] = [np.nan]*len(df) (instead of three steps, 1, 2, and 4, in your example above).

  2. Then just set the values for df['trades'] to be the trade price for those days in which you had trades. Using DataFrame.combine, you can do that also in a single line of code. (Whereas in your example from plotly, you already have built your trade_list, so it's not an equal comparison).

  3. addplot() is intended as a generic way to add data to an mplfinance ohlc or candlestick plot. The fact that it can be used also to scatter-plot trades or trade-signals is an added bonus, but because it is a generic function not specifically designed to only add trade signals, it takes a couple more lines of code compared with some other APIs. If you feel more comfortable using plotly for candlestick and scatter plots, then by all means use that.

  4. There is a plan for mpf.plot() to have a kwarg trades= or signals= where you simply pass in the trade_list (as in your example above). Then mpf.plot() will plot those trades as either a scatter plot or, if you prefer, you can distinguish buys from sells by shading the holding period as shown here:

signals

When this trades= enhancement is done, then given a trade_list, you can make the above plot, or its analagous scatter-plot, with a simple kwarg assignment in your call to mpf.plot() (addplot won't be necessary for plotting trades or trade signals).

  • Please let me know if the functionality as described in item # 4 here is what you are looking for. If it is, then I will leave this issue open as a placeholder for adding the trades or signals kwarg. If not, please a more specific description of how you want the interface to look, or continue to use plotly if that is better for your needs.

@thegamecat
Copy link
Author

Yes to 4, and that and your explanation of how to simplify the nan list is brilliant. Thank you so much!

@DanielGoldfarb DanielGoldfarb changed the title Feature Request: adding new scatter variables More easily Plot Trades or Trade Signals Mar 13, 2020
@fintron
Copy link

fintron commented Mar 30, 2020

+1 to this feature. You could also consider combining it with:
#54

What if you had a generic way of adding "annotations" to the graph. An annotation would only require a start_time, but can also include many other parameters like end, color fill, etc. The interface could look like:

class Annotation(object):
  def __init__(self, start, end=None, line_color=None, fill_color=None, text='', text_align='vertical'):
    pass

end_trading = Annotation(Timestamp(9:30), text='end of trading')
holding_period = Annotation(Timestamp(10), Timestamp(10:30), fill_color='yellow')
mpf.plot(annotations=[end_trading, holding_period])

This could combine all the various use-cases for marking up the graph with annotations.

Thoughts?

@DanielGoldfarb
Copy link
Collaborator

The code being written for #54 will be used to support this, however first #54 and #42 will be developed together, and released, as a general way to plot straight lines anywhere on the plot. It will then be easier to implement annotations.

@CNich
Copy link

CNich commented May 19, 2020

Hi all. Is anyone actively working on this? If not, I think I can handle this with a few clarifications.

@DanielGoldfarb
Copy link
Collaborator

DanielGoldfarb commented May 19, 2020

No one is actively working on this presently. Glad to have you contribute.

@DanielGoldfarb
Copy link
Collaborator

Please let me know what you need clarified, and/or what you have in mind for this.

@manuelwithbmw
Copy link

Just to note, I had nicely handled this with a long list of make_addplot with scatter=True as below:

apd = [mpf.make_addplot(sell_signal, scatter=True,
markersize=50, marker=r'$\Downarrow$'),
mpf.make_addplot(buy_signal, scatter=True,
markersize=50, marker=r'$\Uparrow$'),
mpf.make_addplot(buy_Count_1, scatter=True,
markersize=50, marker='$1$', color="g"), ...

This made the code longer due to heavy numbering needed (300 lines only for plotting tasks) but very effective for my purposes

@CNich
Copy link

CNich commented May 21, 2020

Hi all,

I've got something for plotting trades done. It assumes the data is just a DataFrame where the index is a Datetime and the price column is named "Price". It does not assume the lengths are equal, it simply plots things the way the first post ask for, essentially along the lines of

plt.scatter(trade_list_idx,trade_list_price,c='b')

while doing all of the necessary checks while attempting to maintain the conventions of the project (at least I hope).

Below is a simple example of what things look like:

mpl.plot(df, buys=df_buys, sells=df_sells, style='checkers', volume=True, show_nontrading=True)

default_mpl_trades

or if you want to customize the trades marker, markersize, and/or color you pass a dict:

mpl.plot(df, buys={'data':df_buys, 'color':'green', 'markersize': 60}, sells={'data': df_sells, 'color':'red', 'markersize': 60, 'marker':'*'}, style='checkers', volume=True)

custom_mpl_trades

@DanielGoldfarb, I am unsure how to proceed with the signals though. Will the data be passed into signals be sparse as well, and I should try to calculate the shaded regions? Or will I be given a list/series of something like [0, 0, 0, 1, 1, 1, 0, 0, ... -1, -1, 0, 0] that equals the length of the plot data, where 0 is no active trade, 1 is a long signal, and -1 is a short signal?

If you want, I can make a pull request of what I have so you can review before moving forward, whatever you think is best.

edit: minor wording

@CNich
Copy link

CNich commented May 21, 2020

I was also thinking that passing in trades (buys, sells) would only make a scatterplot (ie if you want to plot simulated/actual trades) whereas if you want to plot a signal, it would automatically plot a shading region to keep things simple.

@DanielGoldfarb
Copy link
Collaborator

@CNich -- Thank you so much for getting involved with this!

I don't have a lot of time to look into this with much detail; hopefully within 2 to 3 days, but I will give you some immediate thoughts:

  • I suggest avoiding a PR for now. I am almost down round of enhancements that significantly restructures some of the code. I hope to have my own PR ready in a day or two; just want to include all the documentation for these new enhancments.
  • A quick reaction to your buys and sells scatter plot kwargs: It seems to me (correct me if I'm missing something) that it is very similar to addplot except that it allows sparse data. So I am wondering whether it may make sense to just enhance addplot to accept sparse data.
  • I will provide more information about the "shading" or fill_between version of showing trades or signals later (short on time right now). But will mention this:
    • fill_between is one of the enhancments in my next PR so we can leverage that.
    • this is my own personal favorite way to visualize trades (as in this image) because it allows me to see quickly in which time periods I have a position, and in which time periods I have cash.
  • regarding your question about using 0's when there is no trade, vs sparse data: It seems to me that we can allow sparse data in a lot of situations provided (a) the data includes a datetime index similar to the original plot dataframe, and (b) we write an internally re-usable method that we can use throughout mplfinance, to easily line up any sparse data with the time-line of the main plot. (And it looks like you've got most of the code for something like this already, with your convert_to_integer_index_dates() ).

As mentioned, I will put some more time and thought into this in two or three days time. In the meantime I hope the above comments are somewhat helpful, and feel free to take a look at the code in my fork to see what's coming (keeping in mind that it may change a little more before it is merged in another day or two).

All the best. And thanks again. --Daniel

@DanielGoldfarb
Copy link
Collaborator

Also, please take a look at this issue. It would be nice if as part of this trades/signals enhancement, we can also make it easier to have different "markers" for one set of trades or signals.

Presently the underlying matplotlib does not support having a sequence of markers (although there is an issue on matplotlib requesting it). In the meantime, we probably can handle it in mplfinance by abstracting it for the user.

@CNich
Copy link

CNich commented May 21, 2020

Hi @DanielGoldfarb

Thanks for the feedback, I am more than happy to be involved! My initial reaction is that addplot seems to be doing much more under the hood than what I added, but I am not fully familiar with the code base yet. In the coming days, I will look into rewriting my code to enhance addplot instead of making a separate scatter function like it is currently -I just didn't want to make big changes to code you wrote but if you think it's the best way then I am happy to help.

I will also take a look at the marker issue #97 when I get the chance.

@CNich
Copy link

CNich commented May 26, 2020

feel free to take a look at the code in my fork to see what's coming

Hi @DanielGoldfarb, I can't seem to find your fork/branch that you are talking about, could you link to it? Is it in this repository?

As for adding custom markers, will the input also be a specialized arg like buys and sells, so it might be something like:

mpl.plot(data, marker_list=df_markers)

where df_markers would be a list len(data) or a dataframe with a datetime index and each column could be a parameter?

Index marker size color location
2020-02-01 "^" 200 "green" "low"
2020-02-02 "v" 200 "red" "high"
2020-02-03 "*" 200 "blue" "open"

@DanielGoldfarb
Copy link
Collaborator

Hi @CNich,

My fork is here: https://github.com/DanielGoldfarb/mplfinance and I hope to merge it into the matplotlib/mplfinance repository soon.

Regarding Issue #97 , I was inspired to use Elan Ernest's solution here and I now have it working (in my fork, soon to be in the main repository). The user can now call make_addplot(type='scatter') and pass in a sequence of markers instead of a single marker.

Users still are limited, however, in that the sequence length must be same as the data length for the main mpf.plot() call. So they must include NaNs in their data, and Nones in their marker sequnce for where they don't want to place markers.

That said, I really like your idea of passing in a dataframe describing trade/signal markers! And I like the idea of being able to pass in "low" or "high" etc. for the 'location' column. Ideally that column should also accept numbers (prices).

I want to think about the exact implementation, whether to integrate with make_addplot() or pass in as a separate kwarg as in your example. In the meantime, you can familiarize yourself with the code in my fork. I will let you know when it has been merged into matplotlib/mplfinance master. Feel free also to email me at dgoldfarb.github@gmail.com if you have any questions (or post them here).

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

5 participants