6. NumPy: arrays and vectorized computation on prices
Level 2: Python from Scratch for Finance
Python lists are flexible, but they have a problem for quantitative work: they are slow for numerical computation and do not support direct mathematical operations between them. If you have two lists of prices and want to subtract them element by element, Python will not let you write list1 - list2 directly — you would have to write a loop. NumPy solves exactly that problem.
import numpy as np
prices = np.array([182.52, 184.10, 179.88, 181.45, 183.20])
type(prices) # numpy.ndarrayA NumPy array behaves like a mathematical vector: arithmetic operations are applied element by element automatically, with no explicit loop needed — this is called vectorization, and it is why NumPy is fast: internally it runs the computation in compiled C code, not in interpreted Python.
prices_yesterday = np.array([180.00, 183.50, 178.00, 180.90, 182.00])
difference = prices - prices_yesterday # element-wise subtraction, with no loop
returns = (prices - prices_yesterday) / prices_yesterday # each day's percentage return, vectorizedTo create arrays without typing every number by hand, NumPy offers several generator functions. arange(start, stop, step) generates a numerical sequence, just like range() but returning an array directly:
days = np.arange(0, 10, 1) # [0, 1, 2, ..., 9]linspace(start, stop, count) generates an exact number of evenly spaced points between two values — very useful, for example, for generating a continuous time axis for a simulation:
horizon = np.linspace(0, 1, 252) # 252 points between 0 and 1: the trading days of a yearzeros and ones create arrays filled with zeros or ones, typically used to initialize a structure you will later fill with the results of a simulation:
simulation_results = np.zeros(1000) # space reserved for 1000 results, all at 0 for nowAnd diag creates a diagonal matrix from a list of values — useful, for example, when building a covariance matrix where you only care about the individual variances:
variances = np.diag([0.04, 0.09, 0.01]) # 3x3 diagonal matrix with those three variancesIndexing a NumPy array works just as it does with lists, but with extra power: you can select elements using a condition directly, with no loop and no list comprehension. This is called boolean indexing, and it is one of the most used tools in financial analysis.
daily_returns = np.array([0.02, -0.01, 0.005, -0.03, 0.015])
losing_days = daily_returns[daily_returns < 0] # array([-0.01, -0.03]) - only the negative ones
mask = daily_returns < 0
daily_returns[mask].mean() # the average return of the losing daysNumPy also comes with the most basic descriptive statistics you will be computing constantly on a return series already built in:
daily_returns.mean() # average return
daily_returns.std() # standard deviation (volatility)
daily_returns.max() # the best day
daily_returns.min() # the worst day
daily_returns.cumsum() # cumulative sum, useful for seeing the cumulative return day by dayThe general rule when working with NumPy is: if you find yourself writing a for loop to walk through an array doing an element-by-element calculation, there is almost always a vectorized way to do the same thing, and it will be considerably faster once the data series has thousands or millions of prices instead of five.