Reading a day from price bars
A daily bar sums up a whole session in five numbers: open, high, low, close and volume. From them you can rebuild the story of a day: how far the price moved overnight (the gap between yesterday's close and today's open), how wide the session's range was, and whether the volume was unusual. Each of these is a one-line calculation on whole columns of a table.
import pandas as pd
bars = pd.read_csv("data/AAPL.csv", index_col="date", parse_dates=True)
prev_close = bars["close"].shift(1) # yesterday's close, lined up with today's row
gap = bars["open"] / prev_close - 1 # the overnight gapWhen you ask whether today's volume is unusual, compare it only with the sessions before today. rolling(20).mean() on its own includes today, so the day is partly compared with itself; calling shift(1) first moves the window back by one day. Using information from the day you are judging is look-ahead, the most common way for a backtest to fool you.
Showing the story
The qc_chart helper turns bars into an interactive chart. Pass it lists of series (candles, lines, histograms) and optional markers; the chart appears in the Charts tab, and the tests read the same data you passed, not the picture.
import qc_chart
qc_chart.show(
[qc_chart.candles(recent, name="Price"), qc_chart.line(average, name="20-day average")],
markers=qc_chart.markers({"2026-05-12": "+4.1%"}),
)Lab · what's graded
- Daily features25 pts
- The biggest gaps25 pts
- Volume spikes without look-ahead25 pts
- Chart the story25 pts