σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademySkills
Ctrl K
AO
+1.2k Learners
LoginJoin ↗
Skills
AO
+1.2k Learners
Login
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python skill›Module 2 · NumPy & pandas for market data›Topic 2.18·~35 minIntermediate

Line plots with matplotlib

Skill positionModule 2 of 11 · Topic 18 of 20
2.18 Line plots with matplotlib
—Lab score— / 100Total XP—Streak—

A figure, an Axes, a line

A chart is the quickest way to see that a price series is clean, trending or broken. In matplotlib a Figure is the whole canvas and an Axes is one chart on it, with its lines, labels and legend. The object-oriented way is fig, ax = plt.subplots() followed by calls on ax: ax.plot(x, y) draws a line, ax.set_title, ax.set_xlabel and ax.set_ylabel name the chart. Drawing on an explicit Axes, and returning it, makes a plotting function easy to reuse and to test.

import matplotlib
matplotlib.use("Agg")            # draw without a window (no screen needed)
import matplotlib.pyplot as plt
import pandas as pd

prices = pd.Series([100.0, 102, 101, 105, 107, 106, 110], index=pd.bdate_range("2026-03-02", periods=7))

fig, ax = plt.subplots()
ax.plot(prices.index, prices.values, label="AAPL")
ax.set_title("Closing price")
ax.set_xlabel("Date")
ax.set_ylabel("Price (USD)")

print(ax.get_title(), "|", ax.get_xlabel(), "|", ax.get_ylabel())   # Closing price | Date | Price (USD)
print(len(ax.lines), ax.lines[0].get_ydata().tolist())               # 1 [100.0, 102.0, 101.0, 105.0, 107.0, 106.0, 110.0]

Labels and the legend

With several lines on one chart, each needs a name. Pass label="..." to ax.plot and call ax.legend() once at the end: the legend lists the labels in the order the lines were drawn. A chart without labels, a title and units is a picture, not a result. Lines also have style: linestyle="--" makes a dashed line, handy for an average that should not hide the prices, and color, linewidth and marker refine it further.

ma = prices.rolling(3).mean()
ax.plot(ma.index, ma.values, label="MA3", linestyle="--")
ax.legend()

print([line.get_label() for line in ax.lines])                  # ['AAPL', 'MA3']
print([text.get_text() for text in ax.get_legend().get_texts()])   # ['AAPL', 'MA3']
print(ax.lines[1].get_linestyle(), ax.lines[1].get_ydata().tolist()[:3])   # -- [nan, nan, 101.0]   NaN points are simply not drawn

Reference lines, and charts you cannot see

A horizontal line marks a level such as a strike, a stop or the average: ax.axhline(105, linestyle="--") draws it across the whole chart (axvline does the same vertically). Matplotlib can also draw with no window at all: with the Agg backend, fig.savefig("chart.png") writes the chart to a file, which is how reports and servers produce charts. Because everything you draw stays on the Axes object, a program (or a test) can read it back: lines with ax.lines, their data with get_ydata(), labels with get_label(), the title with get_title().

ax.axhline(105, linestyle=":", label="level")

level_line = ax.lines[-1]
print(list(level_line.get_ydata()), level_line.get_linestyle(), level_line.get_label())   # [105, 105] : level

fig.savefig("prices.png")   # writes the chart to a file; no window, no plt.show() needed
plt.close(fig)              # release the figure when you are done with it
def plot_prices(prices):
    fig, ax = plt.subplots()
    ax.plot(prices.index, prices.values)
    ax.set_title("Closing price")
    return ax                                   # the caller can add lines, save the chart or inspect it

ax = plot_prices(prices)
print(len(ax.lines), ax.get_title())            # 1 Closing price
plt.close("all")
Close the figures you createEvery plt.subplots() keeps its figure in memory until you call plt.close(fig). In a loop that draws hundreds of charts, or in a server, forgetting this leaks memory and eventually triggers a warning. Create the Figure inside the function, return what the caller needs and let the caller close it.
  • fig, ax = plt.subplots() then ax.plot(x, y); name the chart with set_title, set_xlabel and set_ylabel.
  • Give each line a label= and call ax.legend(); linestyle="--" draws a dashed line; ax.axhline(y) a horizontal one.
  • Draw on an Axes and return it: ax.lines, get_ydata() and get_label() read the chart back; use savefig and plt.close instead of show in programs.

Next up: candlestick charts, drawing open, high, low and close for each day.

Lab · what's graded

  • Draw the price line with plot_prices25 pts
  • Compare two series on one chart with plot_comparison25 pts
  • Add a dashed moving average with plot_with_average25 pts
  • Mark a price level with plot_with_level25 pts
Explorer · lab-51-1
▾ lab-51-1
…
bash · in-browser
learner@quantcraft:~/lab-51-1$
Python not loaded yetPythonLn 1, Col 1Spaces: 4UTF-8

Reset this topic?

Everything in lab-51-1 goes back to the starter files and the terminal is cleared. Your current solution will be lost — this can't be undone.

Will be reset
  • main.py → starter code
  • Terminal history and test output
  • Unsubmitted changes
Will be kept
  • Best lab score
  • Your XP and streak
  • Lecture progress and notes

Log in to run your code.

Every lecture is free to read. Create an account or log in to run code, run tests and submit this lab.

  • In-browser IDE with a bash terminal — nothing to install
  • Instant grading, XP and your place on the skill
Create an accountLog in
OR
Continue with GitHub