Library / SDK
highfestiva/finplot avatar
highfestiva/finplot

finplot: a desktop candlestick plotter built on pyqtgraph for backtesting work

Performant and effortless finance plotting for Python

1,186 stars210 forksPythonMIT

At a glance

What is it?
finplot is a Python finance plotting library built on pyqtgraph and PyQt6, aimed at backtesting rather than web dashboards, with candlesticks, volume profile, heatmaps, multi-chart zooming on one time axis, and handling of hundreds of thousands of points. It installs with a single pip command and requires Python 3 with numpy, pandas, PyQt6, and pyqtgraph.
Who is it for?
finplot fits a quant or trader who wants a fast, interactive desktop chart while backtesting, who works in a normal Python script rather than a notebook, and who wants hundreds of thousands of points on screen without waiting. It is the wrong tool for a web dashboard, for a hosted chart service, and for a Jupyter workflow, because the project states plainly that it is not a web app and does not work with Jupyter Labs.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 29 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Built for looking at a chart while you work

finplot, short for Finance Plotter, is a performant library with a clean api to help you with your backtesting. The framing in the project summary is precise about the audience, and it is worth quoting the shape of the claim rather than the adjectives: it is optionated with good defaults, so you can start doing your work without having to setup plots, colors, scales, autoscaling, keybindings, handle panning and vertical zooming, which the summary notes all non-finance libraries have problems with.

That list is the actual feature specification, and it is a list of the things that annoy people. Colors, scales, and autoscaling are what you spend the first hour of a plotting session configuring. Keybindings and panning are what you miss when the library does not have them. Vertical zooming in particular is a finance-specific requirement, because a price chart is read by looking at a band of it, and a general purpose plotting library tends to zoom in x and y independently in a way that makes the band jump around.

The last claim in that paragraph is the one to hold onto: it can show hundreds of thousands of datapoints without batting an eye. That is a performance claim about a specific architecture rather than about a plotting library in general.

The result is a desktop application, not a component. The library is based on the eminent pyqtgraph, which is fast and flexible, and the project explicitly invites you to hack away if you want to build something else with it, such as a ticker or a trade widget. But the intended use is narrower, and the summary says so: it is only intended for you to do backtesting in.

The candlestick call takes four columns and nothing else

The example in the project summary is the whole onboarding experience, and it is worth reading closely because it tells you the data contract.

python
import finplot as fplt
import yfinance

df = yfinance.download('AAPL')
fplt.candlestick_ochl(df[['Open', 'Close', 'High', 'Low']])
fplt.show()

Two things stand out. First, the data comes from yfinance, so the library does not fetch anything itself, it takes a pandas DataFrame you already have. Second, the call is a single function taking a column selection, `df[['Open', 'Close', 'High', 'Low']]`, and the function name says what it expects: OCHL, open, close, high, low. The order in the name is the order in the slice, and the library takes the frame as given rather than reshaping it for you.

That is a deliberate design point about the boundary between data handling and plotting. The library plots; you prepare. A backtesting script typically has a DataFrame with whatever column names and index your strategy produced, and the friction of a plotting library that insists on renaming or reordering is exactly the friction the author is trying to remove. If your column names differ, you rename them before the call.

`fplt.show()` is the other half of the contract, and it is the part that makes this a desktop tool rather than a library you call from a script and walk away from. The chart is a window, and the interactions the feature list promises, panning, vertical zooming, keybindings, zooming on all charts at once, are things you do to a live window.

The other plot functions follow the same shape. The examples directory and the wiki are where you find how to plot MACD, Parabolic SAR, RSI, volume profile, and more, and the project says it comes with a dozen examples.

One time axis for every chart on screen

The feature list has one item that separates a finance plotter from a general purpose plotting library, and it is this: show as many charts as you want on the same time axis, zoom on all of them at once.

The problem this solves is specific to time series. When you stack a price chart, a volume chart, and an RSI panel, the three share a time axis but nothing forces them to scroll together. In a general purpose library, each subplot has its own view, so panning the price panel moves it and leaves the RSI showing a different period. The two panels then disagree, and the disagreement is silent: the numbers still look plausible, so you do not notice until you misread an indicator.

A shared time axis removes the possibility. Panning or zooming anywhere moves every panel, and the panels cannot drift out of alignment because there is only one axis.

The other features in the same list are the standard vocabulary of a trading chart. Overlays, fill between, value bands, symbols, labels, legend, volume profile, heatmaps. Volume profile in particular is a distribution of where price spent time at each level rather than a time series, and it is the one that requires real computation over the data rather than a mapping from columns to geometry. Heatmaps are the same idea applied to a two-dimensional surface, such as price against time coloured by another variable.

Two smaller items are worth noting for what they imply about the use case. The library can show real-time updates, including an orderbook, and it can save a screenshot. The orderbook mention is the clearest sign of the intended audience, since an orderbook is live market microstructure data and rendering it is a task you do while watching a market, not while producing a report.

The dependency list is a Qt application, not a plotting shim

The install requirements in setup.py are short and they tell you exactly what this package is:

code
install_requires=['numpy>=1.23.5', 'pandas>=1.5.2', 'PyQt6>=6.4.0', 'pyqtgraph>=0.13.1', 'python-dateutil'],

Five dependencies, two of which are the whole story. PyQt6 is the Qt binding, and pyqtgraph is the plotting engine built on it. The other three, numpy, pandas, and python-dateutil, are the data layer. There is no plotting abstraction of its own, no template engine, no web framework, and no JavaScript runtime in the dependency tree.

The version floors are informative. numpy 1.23.5 and pandas 1.5.2 are from the early 2020s, so the library tolerates a fairly wide range of data stack versions, while PyQt6 6.4.0 and pyqtgraph 0.13.1 are recent floors for the Qt binding and the plotting engine.

That combination explains the performance claim in a way a general purpose library could not match. pyqtgraph is described as fast and flexible, which is how a chart with hundreds of thousands of points stays interactive. A library built on a different rendering approach, or one that draws through a per-point Python loop, cannot reach the same number without becoming a different kind of tool.

It also explains the constraints. PyQt6 is a GUI toolkit with a windowing system dependency, so the library needs a display. On a headless server there is no screen to open a chart on, and the project says nothing about an offscreen rendering mode. The classifiers are minimal, listing Python 3, an MIT licence, and Operating System:: OS Independent, with no per-Python-version breakdown and no per-OS breakdown beyond that.

The project is explicit about what it refuses to be

There is a section in the project summary titled what it is not, and it is worth reading in full because it is unusual to find a library stating its exclusions so plainly.

finplot is not a web app. It does not help you create a homebrew exchange. It does not work with Jupyter Labs. Then the reasoning: it is only intended for you to do backtesting in, and that is not to say that you cannot create a ticker or a trade widget yourself, because the library is based on pyqtgraph, which is fast and flexible, so feel free to hack away if that is what you want.

The Jupyter Labs exclusion is the one that surprises people, and it is worth understanding rather than just accepting. finplot opens a window and shows a live, interactive chart. A notebook cell that opens a window either blocks the cell until you close it, or renders to a static image in the output, which is a different thing entirely. The library's value is the interaction, the panning and the vertical zoom and the multi-panel axis, and none of that survives in a notebook output cell. So a project built for backtesting in a script, with the chart on a second monitor while the backtest runs, is a coherent target, and the library does not pretend to serve the notebook case.

The homebrew exchange line is a similar kind of honesty. The library is a plotting layer, not a data feed, not an order router, and not a matching engine. It draws what you give it.

The same honesty shows in the support section, which asks for a small donation for future support and features and gives a Bitcoin and an Ethereum address. A library that small, with a single main author, and a donation request rather than a support contract, tells you what to expect in terms of responsiveness.

The licence is MIT, recorded in the classifiers and in the `LICENSE.txt` file, and the package is built with setuptools, with the version read from `finplot._version` rather than hard coded in setup.py.

Where finplot is the wrong tool

The boundaries are sharp, and most of them follow from the desktop-application design.

First, there is no headless or server rendering path described. The dependency on PyQt6 and the fact that `fplt.show()` opens a window means a script running on a server, a CI job, or a container has nowhere to draw. For batch chart generation, a library that writes a PNG or SVG without a display is the right tool, and this is not it.

Second, and this is the big one for a lot of teams, it does not work in Jupyter Labs. If your team's workflow is a notebook, this library is unusable as documented. That is not a small inconvenience, because notebooks are where a lot of exploratory backtesting happens.

Third, the drawing vocabulary is fixed to what a trading chart needs. That is an advantage if you are plotting prices, and a constraint if you are plotting something else. The library is not a general charting layer with finance presets, it is a finance layer.

Fourth, the data handling is entirely on you. The library takes a DataFrame and plots it, and does not fetch, align, or clean. In the example, yfinance supplies the data and the column names match by luck of convention, since the slice names the columns explicitly. A real backtest with a multi-asset portfolio, a timezone-aware index, and a resampling step does that work upstream.

Fifth, the packaging is old-fashioned in a way that mostly does not matter but occasionally does. setup.py with setuptools, the version read from a module attribute, and no pyproject.toml in the tree. For a pure Python package that installs fine with pip, this is invisible. It only matters if you need modern build features, or if a future numpy release forces a rebuild.

Sixth, and this one is concrete: the project documents a compatibility fix for Python 3.14. The note says a recent fix ensures compatibility with Python 3.14 by avoiding in-place numpy operations on potentially read-only arrays, and that if you encountered a read-only error during normalization you should upgrade to the latest version. If you hit that error on an older release, the error message about read-only arrays during normalization is the diagnostic, and the fix is a version bump rather than a change to your code.

Editorial conclusion

finplot fits a quant or trader who wants a fast, interactive desktop chart while backtesting, who works in a normal Python script rather than a notebook, and who wants hundreds of thousands of points on screen without waiting. It is the wrong tool for a web dashboard, for a hosted chart service, and for a Jupyter workflow, because the project states plainly that it is not a web app and does not work with Jupyter Labs. Check three things before you install: that a Qt display is available, since the package depends on PyQt6 and the library opens a window, that you are running the example scripts rather than importing into a notebook, and that you are on a recent version, since the Python 3.14 compatibility fix arrived through avoiding in-place numpy operations on read-only arrays.

Frequently asked questions

How do I install finplot and plot a candlestick chart?

Install it with `pip install finplot`, then import it as finplot, pass a DataFrame to the chart function, and show the window. The documented example downloads Apple data with yfinance and calls `fplt.candlestick_ochl(df[['Open', 'Close', 'High', 'Low']])` followed by `fplt.show()`.

Does finplot work in Jupyter notebooks?

No. The project states plainly that finplot is not a web app and does not work with Jupyter Labs, and that it is only intended for backtesting in a normal Python script. The library opens a live interactive window, which is the part that does not survive in a notebook output cell.

What are finplot's dependencies?

Five: numpy 1.23.5 or newer, pandas 1.5.2 or newer, PyQt6 6.4.0 or newer, pyqtgraph 0.13.1 or newer, and python-dateutil. PyQt6 and pyqtgraph are the rendering stack, and the library is based on pyqtgraph, which is described as fast and flexible.

How do I plot indicators like MACD or RSI with finplot?

The project points to the examples directory and the wiki, where you find how to plot MACD, Parabolic SAR, RSI, volume profile, and more, alongside a dozen example scripts. The package ships a dozen examples in the finplot examples directory.

Official sources

  1. highfestiva/finplot on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/highfestiva-finplot.svg)](https://hysenlabs.com/projects/highfestiva-finplot)

Was this useful?