Module 6 · Lesson 6

Capstone: Analyzing a Stock Price Series

We’ll model a daily closing-price series as a random walk: start at some price, then repeatedly add a small random daily change. This is synthetic data (seeded, so it’s reproducible), but the analysis below is exactly what you’d run on a real price series.

One technique here hasn’t been taught yet: a rolling mean without pandas. np.convolve(prices, kernel, mode="valid"), with kernel = np.ones(window) / window, slides a length-window averaging kernel across the series and keeps only the positions where the kernel fully overlaps the data (mode="valid") — so the result has length len(prices) - window + 1. It’s a vectorized way to compute a moving average with zero explicit loops.

rng = np.random.default_rng(seed=42)

n_days = 250
daily_changes = rng.normal(loc=0.05, scale=1.0, size=n_days)
prices = 100 + np.cumsum(daily_changes)

plt.plot(prices)
plt.title("Synthetic daily closing price")
plt.xlabel("day")
plt.ylabel("price")
plt.show()

window = 10
kernel = np.ones(window) / window
rolling = np.convolve(prices, kernel, mode="valid")
print("prices:", prices.shape, "rolling mean:", rolling.shape)

Output:

plot output
prices: (250,) rolling mean: (241,)
6.1

Returns, worst day, and a rolling mean

Write analyze_prices(prices, window) that performs three chained computations on a 1-D array of daily closing prices:

  1. "daily_returns": a vectorized array of length len(prices) - 1 where daily_returns[i] = prices[i+1] / prices[i] - 1 (no Python loop).
  2. "worst_day_index" and "worst_day_return": the index into daily_returns of the single worst (most negative) daily return, and that return's value.
  3. "rolling_mean": the simple moving average of prices over window days, computed with np.convolve and mode="valid" as described above (length len(prices) - window + 1).

Return a dict with exactly the keys "daily_returns", "worst_day_index", "worst_day_return", and "rolling_mean".

💡 Hint

daily_returns = prices[1:] / prices[:-1] - 1. Use np.argmin for the worst index, then index back into daily_returns for its value. For the rolling mean, build kernel = np.ones(window) / window and call np.convolve(prices, kernel, mode="valid").

✅ Solution
def analyze_prices(prices, window):
    daily_returns = prices[1:] / prices[:-1] - 1
    worst_day_index = int(np.argmin(daily_returns))
    worst_day_return = float(daily_returns[worst_day_index])
    kernel = np.ones(window) / window
    rolling_mean = np.convolve(prices, kernel, mode="valid")
    return {
        "daily_returns": daily_returns,
        "worst_day_index": worst_day_index,
        "worst_day_return": worst_day_return,
        "rolling_mean": rolling_mean,
    }

🎯 Key Takeaways


🎓 Course Complete!

You’ve made it through the whole course:

  1. NumPy Fundamentals & Array Creation — what an array is, and every way to build one.
  2. Indexing, Slicing & Views — selecting exactly the data you want, and knowing when you get a view vs. a copy.
  3. Array Operations & Broadcasting — vectorized math and the broadcasting rules that make it work across shapes.
  4. Aggregations, Statistics & Sorting — summarizing and ordering data along any axis.
  5. Linear Algebra & Random — vectors, matrices, and reproducible randomness.
  6. Performance, I/O & Mini-Projects — memory layout, persistence, and two real mini-projects tying it all together.

Where to go next:

Nicely done — go build something with it. 🎉