From a loop to one expression
A very common loop starts with an empty list and appends one result per item. A list comprehension says the same thing in one expression, inside square brackets: [what_to_build for item in collection]. Read it from left to right as "build this, for each item in that". It is shorter, and it shows at a glance that the whole thing is a new list.
prices = [184.0, 185.0, 183.0]
# The loop way
notionals = []
for price in prices:
notionals.append(price * 100)
print(notionals) # [18400.0, 18500.0, 18300.0]
# The comprehension way: the same list in one line
notionals = [price * 100 for price in prices]
print(notionals) # [18400.0, 18500.0, 18300.0]Keeping only some items: if
Add if condition at the end to keep only the items that pass a test. This is how you filter: positive returns, orders above a size, symbols that match. Items that fail the test are simply left out, and the order of the rest is kept.
# Keep only the items that pass a test
returns = [0.01, -0.02, 0.005, -0.001, 0.03]
gains = [r for r in returns if r > 0]
print(gains) # [0.01, 0.005, 0.03]Positions and pairs
The for part works like a normal loop: it can walk through range(...) to use positions, and it can name both halves of a pair (for symbol, price in quotes). Use positions when each result depends on a neighbour, such as a return from the previous price; use pairs when each item holds several fields.
# Simple returns from a price series, using positions
prices = [100.0, 102.0, 101.0]
returns = [prices[i] / prices[i - 1] - 1 for i in range(1, len(prices))]
print([round(r, 4) for r in returns]) # [0.02, -0.0098]
# Pairs can be unpacked, and the result can be transformed
quotes = [("aapl", 184.5), ("msft", 410.2), ("goog", 171.0)]
above = [symbol.upper() for symbol, price in quotes if price > 180]
print(above) # ['AAPL', 'MSFT']if/else belongs in front
A trailing if removes items. If you want to change each item depending on a condition, use the conditional expression a if condition else b as the first part. Mixing the two up is a common mistake: if alone goes after the for, if ... else goes before it.
# if/else changes each item; a plain if (at the end) drops items
returns = [0.01, -0.02, 0.005, -0.001, 0.03]
signals = ["long" if r > 0 else "flat" for r in returns]
print(signals) # ['long', 'flat', 'long', 'flat', 'long']for loop. If a comprehension gets long or nested, split it into a loop or into a helper function: readability beats cleverness.[expression for item in items]: one result per item.... if conditionat the end: keep only some items.a if condition else bat the front: change each item.
Next up: lists, the collection these loops and comprehensions have been working on: indexing, slicing, adding, removing and sorting.
Lab · what's graded
- Value every trade in one expression with
notionals25 pts - Turn prices into returns with
simple_returns25 pts - Keep only the gains with
positive_returns25 pts - Filter and clean symbols together with
symbols_above25 pts