Building a Real-Time Stock Candlestick Chart Tool with Django

Mathur Danduprolu
4 min readJun 10, 2024

--

In this tutorial, we will build a real-time stock candlestick chart tool using Django. The application will fetch real-time stock data, display candlestick charts with technical indicators (such as Moving Averages, RSI, and MACD), and allow users to specify the refresh rate for the data.

Django Stock Tehcnicals Webapp (Image generated by AI)

Before starting, ensure you have the following installed:

  • Python
  • Django
  • requests
  • pandas
  • pandas_ta
  • mplfinance

You can install these libraries using pip:

pip install django requests pandas pandas_ta mplfinance

Step 1: Set Up the Django Project

First, create a new Django project and app:

django-admin startproject stock_project
cd stock_project
django-admin startapp stock_app

Add stock_app to your INSTALLED_APPS in settings.py:

# stock_project/settings.py
INSTALLED_APPS = [
...
'stock_app',
]

Step 2: Fetch Stock Data

Create a function to fetch real-time stock data from Alpha Vantage API:

# stock_app/views.py
from django.shortcuts import render
from django.http import JsonResponse
import requests
import pandas as pd
import pandas_ta as ta
import mplfinance as mpf
from datetime import datetime
from io import BytesIO
import base64

def fetch_stock_data(symbol):
api_key = 'YOUR_ALPHA_VANTAGE_API_KEY'
url = f'https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol={symbol}&interval=5min&apikey={api_key}'
response = requests.get(url)
data = response.json()
if 'Time Series (5min)' not in data:
return None
time_series = data['Time Series (5min)']
stock_data = []
for time, values in time_series.items():
stock_data.append({
'timestamp': datetime.strptime(time, '%Y-%m-%d %H:%M:%S'),
'open': float(values['1. open']),
'high': float(values['2. high']),
'low': float(values['3. low']),
'close': float(values['4. close']),
'volume': int(values['5. volume'])
})
return stock_data

Step 3: Plot Candlestick Chart with Technical Indicators

Create a function to plot candlestick charts with technical indicators:

def plot_candlestick(data):
if not data:
return None
df = pd.DataFrame(data)
df.set_index('timestamp', inplace=True)

# Calculate Moving Averages
df['SMA20'] = ta.sma(df['close'], length=20)
df['SMA50'] = ta.sma(df['close'], length=50)

# Calculate RSI
df['RSI'] = ta.rsi(df['close'], length=14)

# Calculate MACD
macd = ta.macd(df['close'], fast=12, slow=26, signal=9)
df['MACD'] = macd['MACD_12_26_9']
df['MACD_Signal'] = macd['MACDs_12_26_9']
df['MACD_Hist'] = macd['MACDh_12_26_9']

# Plotting
mc = mpf.make_marketcolors(up='g', down='r', inherit=True)
s = mpf.make_mpf_style(marketcolors=mc)

fig, axes = mpf.plot(
df,
type='candle',
style=s,
title='Stock Price with Technical Indicators',
ylabel='Price',
volume=True,
mav=(20, 50),
addplot=[
mpf.make_addplot(df['SMA20'], color='blue'),
mpf.make_addplot(df['SMA50'], color='red'),
mpf.make_addplot(df['RSI'], panel=2, color='purple', ylabel='RSI'),
mpf.make_addplot(df['MACD'], panel=3, color='blue', ylabel='MACD'),
mpf.make_addplot(df['MACD_Signal'], panel=3, color='red'),
mpf.make_addplot(df['MACD_Hist'], type='bar', panel=3, color='gray')
],
returnfig=True,
figsize=(14, 10) # Increase graph size
)

buf = BytesIO()
fig.savefig(buf, format='png')
buf.seek(0)
image_png = buf.getvalue()
buf.close()
image_b64 = base64.b64encode(image_png).decode('utf-8')
return image_b64

Step 4: Create the View

Create a view to handle the stock chart rendering and refresh rate:

def stock_chart(request):
symbol = request.GET.get('symbol', 'AAPL') # Default to AAPL if no symbol provided
stock_data = fetch_stock_data(symbol)
chart = plot_candlestick(stock_data) if stock_data else None
if request.headers.get('x-requested-with') == 'XMLHttpRequest':
return JsonResponse({'chart': chart, 'error': 'Invalid stock symbol or data not available.' if not chart else ''})
return render(request, 'stock_app/stock_chart.html', {'chart': chart, 'symbol': symbol})

Step 5: Create the Template

Update stock_chart.html to include the input for refresh rate and the chart container:

<!-- stock_app/templates/stock_app/stock_chart.html -->
{% extends "base.html" %}

{% block title %}Stock Candlestick Chart{% endblock %}

{% block content %}
<h1 class="text-2xl font-semibold mb-4">Stock Candlestick Chart</h1>
<form id="stock-form" method="get" action="{% url 'stock_chart' %}" class="mb-4">
<label for="symbol" class="block text-lg mb-2">Enter Stock Symbol:</label>
<input type="text" id="symbol" name="symbol" class="border p-2 rounded w-full mb-2" placeholder="e.g., TSLA" value="{{ symbol }}" required>
<label for="refresh-rate" class="block text-lg mb-2">Refresh Rate (seconds):</label>
<input type="number" id="refresh-rate" name="refresh_rate" class="border p-2 rounded w-full mb-2" value="300" required>
<button type="submit" class="bg-blue-600 text-white p-2 rounded">Get Chart</button>
</form>
<div id="chart" style="height: 600px;">
{% if chart %}
<img src="data:image/png;base64,{{ chart }}" alt="Stock Candlestick Chart" style="width: 100%; height: 100%;"/>
{% elif not chart and symbol %}
<p class="text-red-600">Invalid stock symbol or data not available.</p>
{% endif %}
</div>
{% endblock %}

{% block extra_js %}
<script>
const form = document.getElementById('stock-form');
form.addEventListener('submit', function(event) {
event.preventDefault();
fetchChart();
});

let refreshInterval;

function fetchChart() {
const symbol = document.getElementById('symbol').value;
const refreshRate = document.getElementById('refresh-rate').value * 1000; // Convert to milliseconds
clearInterval(refreshInterval); // Clear previous interval
fetch(`/stock/chart/?symbol=${symbol}`)
.then(response => response.json())
.then(data => {
const chartDiv = document.getElementById('chart');
if (data.chart) {
chartDiv.innerHTML = `<img src="data:image/png;base64,${data.chart}" alt="Stock Candlestick Chart" style="width: 100%; height: 100%;"/>`;
} else {
chartDiv.innerHTML = `<p class="text-red-600">${data.error}</p>`;
}
});
refreshInterval = setInterval(fetchChart, refreshRate);
}

fetchChart(); // Initial chart fetch
</script>
{% endblock %}

Step 6: Configure URLs

Configure your URLs to include the new view:

# stock_app/urls.py
from django.urls import path
from . import views

urlpatterns = [
path('chart/', views.stock_chart, name='stock_chart'),
]

Include these URLs in the main project urls.py:

# stock_project/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('stock/', include('stock_app.urls')),
]

Step 7: Run the Application

Run the following commands to apply migrations and start the server:

python manage.py makemigrations
python manage.py migrate
python manage.py runserver

Open your browser and navigate to:

http://127.0.0.1:8000/stock/chart/

Enter a stock symbol (e.g., TSLA) and a refresh rate (e.g., 60 for 1 minute) in the input fields, then submit to see the candlestick chart with Moving Averages, RSI, and MACD. The chart will automatically refresh at the specified interval.

App showing the output of AAPL stock with MACD/RSI and Volume 30

Conclusion

In this tutorial, we built a real-time stock candlestick chart tool using Django, pandas_ta, and mplfinance. We covered how to fetch real-time stock data, plot candlestick charts with technical indicators, and create an interactive user interface with customizable refresh rates. This tool provides a robust foundation for further enhancements, such as adding more technical indicators, improving the user interface, or integrating with additional data sources. Happy coding!

If you enjoyed this tutorial and found it helpful, please follow my Medium blog for more articles like this. Happy coding!

--

--