Quant Ladder

Python for Quant Interviews: Idioms That Signal Fluency

3 min read

Python is the lingua franca of quant research, and interviewers read your Python the way they read your arithmetic: fluency signals practice. This lesson is the short list of idioms that make solutions shorter, faster, and obviously written by someone who uses the language daily.

Comprehensions and generators

The basic fluency marker:

returns = [(p1 - p0) / p0 for p0, p1 in zip(prices, prices[1:])]
big_moves = {d: r for d, r in daily.items() if abs(r) > 0.02}

Know the difference between a list comprehension (materializes everything) and a generator expression (lazy, constant memory):

total = sum(x * x for x in stream)   # no intermediate list

For tick-data-sized inputs, "I'd use a generator so it streams" is precisely the sentence interviewers are listening for.

The standard library does the work

Three modules solve a disproportionate share of interview prompts:

  • collectionsCounter (frequencies in one line: most active symbol, mode of a stream), defaultdict (grouping without key-existence boilerplate), deque (O(1)O(1) appends/pops both ends — the rolling-window container).
  • heapq — heaps for "top-k largest" (heapq.nlargest(k, xs)) and the two-heap running median.
  • itertoolsaccumulate (cumulative P&L), groupby, pairwise (consecutive price pairs), combinations (small brute forces).
from collections import Counter
most_traded = Counter(symbols).most_common(3)

Reaching for these instead of hand-rolling loops is the difference between "knows Python" and "knows of Python."

Vectorized thinking (NumPy / pandas)

Research-flavored screens test whether you think in arrays:

rets = prices[1:] / prices[:-1] - 1          # all returns at once
sharpe = rets.mean() / rets.std() * np.sqrt(252)
drawdown = prices / np.maximum.accumulate(prices) - 1

That third line — running maximum via accumulate, then an elementwise ratio — computes the entire drawdown series with no loop, and drawdown.min() is the max drawdown. Presenting it (versus a for-loop) is often the whole point of the question. The general rule: loops over rows are a smell in NumPy/pandas; the library's C internals are ~100× a Python loop.

Sharp edges they love to probe

  • Mutable default arguments: def f(x, acc=[]) — the list is created once and shared across calls. The classic Python gotcha; fix with acc=None + create inside.
  • Floats: 0.1 + 0.2 != 0.3. Compare with math.isclose; use integers (cents, ticks) or decimal.Decimal for money. Any pricing-system question wants this said aloud.
  • Copy semantics: assignment binds names, it never copies (b = a; b.append(...) mutates the object a sees). Know list(a) / slicing for shallow copies and when deepcopy is actually needed.
  • is vs ==: identity vs equality — is is for None, and using it for numbers or strings works only by accident of interning.
  • Sorting with keys: sorted(trades, key=lambda t: (t.symbol, -t.size)) — multi-field sorts via tuple keys; sorted is stable, and stability is occasionally the intended trick.

The interview version

A representative prompt: "Given a list of (timestamp, price) ticks, return the 5 largest 1-minute returns." A fluent answer buckets with a defaultdict, computes bucket returns with zip(buckets, buckets[1:]) or pandas resample, and finishes with heapq.nlargest(5, ...) — three idioms from this lesson composed in under ten lines, with the complexity (O(nlogk)O(n \log k) for the top-k step) stated unprompted. Practice composing small tools quickly; that composition speed is what the screen measures.