Building a Financial Charting SaaS: The Tech Behind the Candlesticks

Reading Time: 5 minutes

Some time ago, I began developing a web-based SaaS platform designed to help users create and customize candlestick charts for analyzing stocks and currencies.  This includes the ability to save charts directly to user accounts.  As I mapped out the project, there were several key decision points – starting with a good charting library that would best serve both our backend and interactive front end.

Backend vs. Frontend: Setting the Stage

My initial focus was on the backend using Python.  However, if I wanted to give users the ability to dynamically customize their charts on the fly, I would have to think about incorporating Javascript.  Fetching new charts via the server for each user interaction seemed inefficient—each update would trigger latency and require saving chart images to disk before rendering. That approach would quickly become cumbersome. Users would have to select their charting attributes before making a call to the server and deal with wait times.  We would have to deal with saving an image every time there is a change and then referencing that file in the HTML.

Although I had prior experience with Plotly in Python via Jupyter notebooks, I realized this project required rich front-end interactivity. JavaScript needed to take the lead in rendering responsive visuals.

Server vs. Client-side

It is apparent that one of the biggest decisions was whether charts would be rendered on the server or the client. My research kept leading me back to Plotly, which has both Javascript and Python libraries. My initial inclination was to go with server-side rendering due to processing demands of handling financial data from third-party APIs data and generating chart images via Python. I figured the server would be better because of the required processing power. On the other hand, repeated calls to generate chart images via Python every time the client makes a customization felt inefficient and slow.

Basically, Plotly’s Python library, whether on its own or via its Dash framework, would generate static images or standalone HTML files. The image byte code can be saved to the database, but the repeated calls to the server (and perhaps database) would not make this option better. I decided to use the Javascript library after seeing all the chart attributes and functionality that could be called on the fly with plotly.js. This way, we can generate the final image once the client is satisfied with his or her selections/customizations that are dynamically rendered client-side.

In short, I shifted to client-side rendering with plotly.js. This allows users to interactively customize their charts, which would only be finalized and saved once selections were complete—dramatically reducing server load and improving user experience.

Charting library considerations

Plotly provides various charting options, including embedding charts via HTML iframes hosted on Chart Studio, which itself is powered by the plotly.js library. Simultaneously, I explored D3.js—a powerful, low-level visualization library. However, D3’s steep learning curve and lack of high-level chart abstractions made me hesitant to reinvent the wheel. Plotly.js builds on top of D3 and simplifies those complexities into accessible functions.

Why Not Dash or D3?

Plotly’s Dash is a capable framework for building dashboards, but it’s Flask-based, while our project runs on Django. Dash also focuses on full dashboard experiences rather than embedded, standalone widgets. Since it’s built atop plotly.js, using Dash would add another layer -and more server communication (via callbacks) -without offering clear benefits.

Another good data visualization library seems to be D3.js. According to D3’s documentation: “Because D3 has no overarching “chart” abstraction, even a basic chart may require a few dozen lines of code. On the upside, all the pieces are laid out in front of you and you have complete control over what happens.” 

Like any other higher-level abstraction built on top of the main source, there is a tradeoff between the amount of code that needs to be written and control over what is possible. I learned that D3.js has a high learning curve and that Plotly is built on top of D3.js. So why reinvent the wheel? Why not abstract away some of those complexities? Oh yeah, and Plotly is open source as well.

D3.js is powerful but low-level. As noted in this FreeCodeCamp post, D3’s learning curve and manual chart construction make it less practical for rapid development. Plotly.js abstracts those complexities and offers financial chart types out of the box.

I briefly considered using Cufflinks—a library that further simplifies Plotly chart creation with Pandas—but its development has stagnated and adds yet another abstraction layer with the loss of flexibility that this entails. In contrast, Plotly.js remains actively maintained with open-source contributions via GitHub.

Real-World Challenges and Breakthroughs

One challenge was where I foolishly spent hours getting the input stock symbol to correctly pass to the fetch request. I moved the code and placed the input box above the chart div and it started working. It appears that the Plotly chart was interfering with my Javascript and preventing it from correctly grabbing the input value. Another challenge was changing candlestick width. As of this writing, Plotly doesn’t expose a candlestick width parameter. It depends on how many candlesticks are displayed in the figure.

Another major consideration was how to access the financial market data.  I had a chosen an API in mind with sufficiently high rate limits on historical data for testing.

Data Manipulation: Finding Harmony Between Pandas and JavaScript

For API integration and technical indicator calculations, I relied on Pandas to process JSON data and compute moving averages. Sending pre-processed data via fetch requests made the front-end leaner. However, I found that JavaScript could handle many calculations instantly—highs, lows, price variance—based on user selections. For more advanced indicators, I may revert to Pandas, especially given its clarity and power.

The decision to transform API data server-side using Pandas was strategic. It allowed me to hide the API key from the client, control rate limits per user, and prepare arrays suitable for the frontend charting logic. Date slicing, filtering, and calculating indicators were much easier with Pandas than with raw JavaScript.

As soon as I wanted to do calculations and manipulate the data, it became evident how Pandas Dataframes made things simpler. I wanted most of the rendering to be client-side. However, calculations and annotations on the client-side would require more of my own JS coding and possibly the help of other JS libraries. For example, the stock price API can either return the last 100 data points or 20+ years of historical data, but I am looking to chart YTD or the last 52 weeks. Specifying the date range and performing other actions is easier with Pandas.

From Interaction to Image: The Final Piece

At the beginning of the project. I did not know whether the user can dynamically re-render the chart with js or whether the final customized chart would be rendered on the server. By now, we have data pre-processed once on the server while all the customization and finalized charting happens on the client side and sent to the database as static image byte code.

The turning point came with discovering Plotly’s toImage() function. This allowed users to customize charts in the browser and save them as base64-encoded static images to our database. It neatly closed the loop from data to display to persistence.

Plotly.js also offers configuration settings—like {scrollZoom: true} and {editable: true}—that make charts more responsive and user-friendly.

Conclusion

What ultimately tipped the scales toward Plotly.js was its blend of simplicity, power, and seamless fit with our Django-based stack. While D3.js offers unmatched low-level flexibility, its steep learning curve and the need to handcraft every chart element can slow development—especially when you want candlesticks and financial annotations out of the box. Plotly.js leverages D3 under the hood, but abstracts away complexities. Dash, by contrast, is optimized for full dashboards on Flask rather than individual widgets in Django, and Plotly Chart Studio’s cloud-based GUI and external storage model felt like overkill for our real-time SaaS. Plotly.js’s free, open-source codebase—with an active GitHub community for issues and contributions—delivered exactly the high-level API and performance footprint I needed.

This journey clarified not just which charting tool to use, but how architectural decisions reverberate across performance, usability, and developer experience. Plotly.js ultimately offered the best mix: high-level abstractions built atop D3, seamless integration with JavaScript, and flexible enough to pair with Python’s Pandas backend. By choosing the right layers of abstraction and keeping client-side interactivity at the core, the project remains lightweight, scalable, and intuitive for end users.

References

  1. FreeCodeCamp. (n.d.). D3.js tutorial – Data visualization for beginners. https://www.freecodecamp.org/news/d3js-tutorial-data-visualization-for-beginners/
  2. Mesquita, D. (2021, May 14). How and why I used Plotly (instead of D3) to visualize my Lollapalooza data. FreeCodeCamp. https://www.freecodecamp.org/news/how-and-why-i-used-plotly-instead-of-d3-to-visualize-my-lollapalooza-data-d48345e2ca68/
  3. Plotly. (n.d.). Plotly.js GitHub repository. https://github.com/plotly/plotly.js
  4. CodeFile. (2020, November 23). An interactive web dashboard with Plotly and Flask. Medium. https://medium.com/codefile/an-interactive-web-dashboard-with-plotly-and-flask-c365cdec5e3f
  5. Kalani, Y. (2022, February 20). The simplest way to create an interactive candlestick chart in Python. Towards Data Science. https://towardsdatascience.com/the-simplest-way-to-create-an-interactive-candlestick-chart-in-python-ee9c1cde50d8/
  6. Plotly. (n.d.). Dash in 20 minutes tutorial. https://dash.plotly.com/tutorial
  7. GeeksforGeeks. (n.d.). Introduction to Dash in Python. https://www.geeksforgeeks.org/data-science/introduction-to-dash-in-python/

Leave a Comment