Python for Investing
Learn Python from the beginning using financial examples. Every lesson works on prices, returns, positions or portfolios, and every code block on the page has been run.
38 lessons, about six hours in total. Start at Lesson 1 and work down. If you already write Python, start at the level that matches you.
- Beginner, 11 lessons, about 1.5 hours. Variables, arithmetic, lists, slicing, loops, conditions, functions, dictionaries and classes. Lesson 8 turns prices into returns.
- Intermediate, 14 lessons, about 2 hours. numpy and pandas: arrays, Series, DataFrames, loading a CSV, returns in one call, moving averages, lags, equity curves, grouping, joins and panels.
- Advanced, 13 lessons, about 2.5 hours. Moving averages and RSI, turning an indicator into a position, lagging the signal so it cannot see the future, trading costs, drawdown, Sharpe, a backtest in one function, and then the same job again using the
btandffnpackages.
By the end you can load a price file, build a signal from it, run a backtest that does not look ahead, and report what it earned after costs.
To check what stuck, the quiz draws ten questions at random from any level.
From Lesson 16 on, the lessons read a simulated prices.csv from disk. To fill the same table from a broker, connect Python to an Interactive Brokers paper account: the connection is read-only, and ib_async returns daily bars as a pandas DataFrame. How do I get market data into Python? covers the other sources and which one fits which test.
What is a variable?
Name a price, a ticker and a share count, then value a position and a three-stock portfolio.
How do I do maths and print a result?
Do arithmetic in Python and print the result with an f-string.
What is True and False?
Compare two numbers, store the answer, and build a buy rule out of it.
What is a list?
Hold many values under one name, count them, pick them out by position, and add new ones.
How do I slice a list?
Slice a list with x[start:stop], and turn the last few closes into a moving average.
What is a for loop?
Run the same lines once for every item in a list, and add the results up as you go.
What are if, elif and else?
Pick one outcome with if, elif and else, and see how the order of the tests decides which one you get.
How do I turn prices into returns?
Build a list of returns in a loop, then compound them into the return for the whole stretch.
What is a function?
Give a calculation a name with def, feed it inputs, and get an answer back.
What is a dictionary?
Map a key to a value, look it up by name, and use two dictionaries keyed by ticker to value a portfolio.
What is a class?
Write your own class, build two objects from it, and read what self means on every line.
What is a numpy array?
Hold many numbers in one array and do maths on all of them at once, without writing a loop.
How do I filter with a condition?
Turn a comparison into an array of True and False, use it to select elements, count them, and switch it into a position of 1 or 0.
What is a pandas Series?
Build a Series of closes, select by label and by position, and see arithmetic line up two price series on their dates.
What is a DataFrame?
Build a table from a dictionary of lists, select columns from it, add a computed column, sort it, and filter its rows.
How do I load a CSV file?
Read a CSV into a DataFrame with pd.read_csv, parse the dates, and index the rows by date.
How do I compute returns in pandas?
Turn a column of prices into a column of returns with pct_change, and handle the NaN it leaves in the first row.
Why is an array operation faster than a loop?
Time a Python loop against the same calculation written as one array operation, and see where the gap comes from.
What is a moving average?
Take the mean of the last n values at every row with .rolling(n).mean(), and put a 5-day and a 10-day average on a price column.
How do I use yesterday's value?
Move a column down one row with .shift(1) so every row can read the row above it.
How do I build an equity curve?
Turn a column of returns into the growth of one unit of money with (1 + r).cumprod().
How do I do the same thing per ticker?
Split a stacked table into one group per ticker, run a calculation inside each group, and get the answers back.
How do I stack two tables?
Glue DataFrames together with pd.concat, top to bottom by default and side by side with axis=1.
How do I join two tables on a key?
Line two tables up on a shared column with pd.merge, and choose which rows survive with inner, left, right and outer.
What is a panel?
Put a date and a ticker in the index, pull out one date or one ticker, and switch between the long and wide shapes.
What is the difference between an SMA and an EMA?
Compute a simple and an exponential moving average, and see how each one weights the past.
How do I compute RSI?
Build the relative strength index from daily changes, Wilder smoothing, and the 0 to 100 formula.
What are Bollinger bands?
Draw a moving average with a band two standard deviations above and below it, and measure where the close sits inside that band.
How do I turn an indicator into a position?
Read an indicator with a rule to get a signal, then lag the signal by one row to get the position you hold.
Why do I lag the signal?
Shift a signal down one row so it sits in front of the return it earns, and see how much the total changes.
How do I charge trading costs?
Charge a cost every time the position changes, using turnover = position.diff().abs() times a rate.
What is a drawdown?
Measure how far an equity curve sits below its own running peak, and how long it stays there.
How do I measure return and risk?
Compute CAGR, annualised volatility, Sharpe and Sortino on a return series, then put all of them in one function.
How do I put a backtest in one function?
Wrap the lag, the costs, the compounding and the metrics into one function that takes prices and a signal and hands back a table.
How do I test many parameters at once?
Run the backtest function once for every value in a list of parameters and collect the results in one table.
How certain is a Sharpe ratio?
Resample a return series with replacement a few thousand times to see the range of Sharpe ratios the same data could have produced.
How do I backtest with a package?
Run the Lesson 34 rule through the bt package and check its numbers against the hand built ones.
How do I get the performance stats without writing them?
Call ffn.calc_stats on a price series to get CAGR, volatility, Sharpe, Sortino, drawdown and forty more, and check them against the ones you built by hand.