Quick Start

This page walks through the most common usage patterns. Wickly’s API mirrors mplfinance so if you’re already familiar with that library you can jump right in.

Prepare your data

Wickly expects a pandas.DataFrame with a DatetimeIndex and columns named Open, High, Low, Close (case-insensitive), plus an optional Volume column.

import pandas as pd

df = pd.read_csv("ohlcv_data.csv", index_col=0, parse_dates=True)
print(df.head())

Basic candlestick chart

import wickly

wickly.plot(df, type="candle")

This opens an interactive window. Use the mouse wheel to zoom and click-drag to pan.

Add volume & moving averages

wickly.plot(
    df,
    type="candle",
    volume=True,
    mav=(10, 20),
    style="yahoo",
    title="My Chart",
)

Use returnfig for embedding

When building a larger PyQt6 application, use returnfig=True to get back the widget without blocking:

widget, axes = wickly.plot(df, type="candle", returnfig=True)
# widget is a QWidget you can embed in your own layout

Overlay custom data with make_addplot

Three plot types are supported:

  • ``’line’`` — polyline connecting consecutive non-NaN values. Insert NaN to create gaps / broken segments.

  • ``’scatter’`` — one marker per non-NaN value. Use NaN for bars where no marker should appear.

  • ``’segments’`` — one independent diagonal line per bar, drawn from y_start to y_end. Pass a 2-column pd.DataFrame as data. Use NaN in both columns for bars with no mark. This is the natural encoding for divergence indicators such as Knoxville Divergence, where a short slanted line is drawn at each detected divergence bar.

import numpy as np
import pandas as pd

sma = df["Close"].rolling(20).mean()
upper = sma + 2 * df["Close"].rolling(20).std()
lower = sma - 2 * df["Close"].rolling(20).std()

signal = np.where(df["Close"] < lower, df["Low"] - 0.5, np.nan)

apds = [
    wickly.make_addplot(upper, color="#9c27b0", linestyle="--"),
    wickly.make_addplot(lower, color="#9c27b0", linestyle="--"),
    wickly.make_addplot(signal, type="scatter", color="orange", markersize=90),
]

wickly.plot(df, type="candle", volume=True, addplot=apds, style="nightclouds")

Broken-line segments (e.g. Knoxville Divergence)

# Build a 2-column DataFrame: y_start and y_end for each bar.
# NaN rows produce no segment (gap).
n = len(df)
y_start = np.full(n, np.nan)
y_end   = np.full(n, np.nan)

# Mark divergence bars (your detection logic here)
for i in divergence_bar_indices:
    y_start[i] = df["High"].iloc[i] + 0.2   # top of segment
    y_end[i]   = df["High"].iloc[i] + 0.2   # horizontal → diagonal → your choice

segments_df = pd.DataFrame({"y_start": y_start, "y_end": y_end}, index=df.index)

apds = [
    wickly.make_addplot(segments_df, type="segments", color="#e91e63", width=2.5),
]

wickly.plot(df, type="candle", addplot=apds)

Save chart to file

wickly.plot(df, type="candle", savefig="chart.png")

Live / animated charts

Use live_plot() to open a non-blocking chart that you can feed new data to in real time:

widget, axes = wickly.live_plot(df, type="candle", volume=True, mav=(10, 20))

# Append a complete new bar
widget.append_data(
    dates=pd.DatetimeIndex([new_date]),
    opens=np.array([open_]),
    highs=np.array([high]),
    lows=np.array([low]),
    closes=np.array([close]),
    volumes=np.array([vol]),
)

# Update the last candle in-place (e.g. live tick)
widget.update_last(close=latest_price, high=max(old_high, latest_price))

Custom styles

my_style = wickly.make_style(
    base_mpf_style="nightclouds",
    up_color="#00ff00",
    down_color="#ff0000",
)
wickly.plot(df, style=my_style)

See Styles for the full list of built-in themes and customisation options.