Visualizing Indicators with Plotly example
A full example combining Centaur Technical Indicators with pandas and Plotly visualization from tutorial 1 and tutorial 2.
Full code
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from centaur_technical_indicators import moving_average as ma
from centaur_technical_indicators import candle_indicators as ci
from centaur_technical_indicators import momentum_indicators as mi
from centaur_technical_indicators import other_indicators as oi
df = pd.read_csv("prices.csv", parse_dates=["Date"])
df = df.sort_values("Date").reset_index(drop=True)
close = df["Close"].astype(float).tolist()
high = df["High"].astype(float).tolist()
low = df["Low"].astype(float).tolist()
open_ = df["Open"].astype(float).tolist()
# Bulk simple moving average (20-period)
period = 20
sma_series = ma.bulk.moving_average(close, period=period, moving_average_type="simple")
# Align back to DataFrame: last len(sma_series) rows correspond to rolling results
df.loc[df.index[-len(sma_series):], f"SMA_{period}"] = sma_series
# Bulk Bollinger Bands (20-period)
bands = ci.bulk.moving_constant_bands(
close,
constant_model_type="exponential_moving_average",
deviation_model="standard_deviation",
deviation_multiplier=2.0,
period=period
)
# Unpack and assign (align to tail)
lower_vals, ema_vals, upper_vals = zip(*bands)
tail_index = df.index[-len(bands):]
df.loc[tail_index, "MCB_Lower"] = lower_vals
df.loc[tail_index, "MCB_EMA"] = ema_vals
df.loc[tail_index, "MCB_Upper"] = upper_vals
# Bulk RSI
rsi_values = mi.bulk.relative_strength_index(
close,
constant_model_type="smoothed_moving_average",
period=20
)
df.loc[df.index[-len(rsi_values):], "RSI"] = rsi_values
# Bulk ATR
atr_series = oi.bulk.average_true_range(
close=close,
high=high,
low=low,
constant_model_type="exponential_moving_average",
period=period
)
df.loc[df.index[-len(atr_series):], f"ATR_{period}"] = atr_series
# Create multi-panel Plotly figure
fig = make_subplots(
rows=3,
cols=1,
shared_xaxes=True,
vertical_spacing=0.02,
row_heights=[0.6, 0.2, 0.2],
subplot_titles=("Price & Overlays", "RSI", "ATR")
)
# --- Row 1: Candlestick ---
fig.add_trace(
go.Candlestick(
x=df["Date"],
open=df["Open"],
high=df["High"],
low=df["Low"],
close=df["Close"],
name="Price",
increasing_line_color="#26a69a",
decreasing_line_color="#ef5350",
showlegend=True
),
row=1, col=1
)
# --- Row 1: SMA ---
sma_col = "SMA_20"
if sma_col in df.columns:
fig.add_trace(
go.Scatter(
x=df["Date"], y=df[sma_col],
name=sma_col,
line=dict(color="orange", width=1.3),
hovertemplate="SMA %{y:.2f}<extra></extra>"
),
row=1, col=1
)
# --- Row 1: Moving Constant Bands (shaded) ---
if {"MCB_Lower", "MCB_Upper", "MCB_EMA"}.issubset(df.columns):
fig.add_trace(
go.Scatter(
x=df["Date"], y=df["MCB_Upper"],
name="MCB Upper",
line=dict(color="royalblue", width=1),
hovertemplate="Upper %{y:.2f}<extra></extra>",
opacity=0.7
),
row=1, col=1
)
fig.add_trace(
go.Scatter(
x=df["Date"], y=df["MCB_Lower"],
name="MCB Lower",
line=dict(color="royalblue", width=1),
fill="tonexty",
fillcolor="rgba(65,105,225,0.15)",
hovertemplate="Lower %{y:.2f}<extra></extra>",
opacity=0.7
),
row=1, col=1
)
fig.add_trace(
go.Scatter(
x=df["Date"], y=df["MCB_EMA"],
name="MCB Mid",
line=dict(color="royalblue", width=0.8, dash="dot"),
hovertemplate="Mid %{y:.2f}<extra></extra>",
opacity=0.6
),
row=1, col=1
)
# --- Row 2: RSI ---
if "RSI" in df.columns:
fig.add_trace(
go.Scatter(
x=df["Date"], y=df["RSI"],
name="RSI (20)",
line=dict(color="purple"),
hovertemplate="RSI %{y:.2f}<extra></extra>"
),
row=2, col=1
)
# Overbought / Oversold reference lines
fig.add_hline(y=70, line_dash="dash", line_color="red", row=2, col=1)
fig.add_hline(y=30, line_dash="dash", line_color="green", row=2, col=1)
# --- Row 3: ATR ---
atr_col = "ATR_20"
if atr_col in df.columns:
fig.add_trace(
go.Bar(
x=df["Date"], y=df[atr_col],
name=atr_col,
marker_color="gray",
hovertemplate="ATR %{y:.2f}<extra></extra>",
opacity=0.7
),
row=3, col=1
)
fig.update_layout(
title=f"Technical Indicators Dashboard",
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
xaxis_rangeslider_visible=False,
template="plotly_white",
margin=dict(l=40, r=40, t=60, b=40),
hovermode="x unified"
)
# Improve y-axis titles
fig.update_yaxes(title_text="Price", row=1, col=1)
fig.update_yaxes(title_text="RSI", row=2, col=1, range=[0,100])
fig.update_yaxes(title_text="ATR", row=3, col=1)
fig.show()
# Optional: static export
# fig.write_image("technical_dashboard.png", scale=2, width=1400, height=900)
Run the code
python3 your_file_name.py
Expected output
An interactive Plotly chart will open in your browser showing: - Candlestick chart with price data - SMA overlay on the price chart - Moving Constant Bands (shaded area) on the price chart - RSI indicator in a separate panel with 70/30 threshold lines - ATR indicator in a third panel
The chart will be interactive, allowing you to zoom, pan, and hover over data points.
If you're using the sample data you should see a chart similar to the following:
