Skip to content

Functional programming

Build quantitative calculations from explicit inputs and composable functions, with effects kept at a clear boundary.

Functional programming is an approach to building software by composing functions that transform inputs into outputs, while limiting changes to shared state. In quantitative work, this makes a valuation easier to replay: the positions, market snapshot and model settings can be supplied explicitly instead of being hidden in the running process. Python supports this style alongside procedural and object-oriented code; it does not enforce a purely functional language's restrictions. Python's functional-programming HOWTO explains this distinction.

A valuation with visible dependencies

Suppose a fictional portfolio holds two units priced at USD 100 each and three units priced at USD 50 each. The position values are USD 200 and USD 150, giving a total of USD 350. There are no fees, cash balances or currency conversions in this example.

The following Python example stores each position as (quantity, price_in_usd). One function values a position; another combines that calculation with a sum.
def position_value(position: tuple[int, int]) -> int: """Return USD value for a (quantity, USD unit price) pair.""" quantity, price = position return quantity * price def portfolio_value(positions: tuple[tuple[int, int], ...]) -> int: """Sum position values without changing the input positions.""" return sum(map(position_value, positions)) positions = ((2, 100), (3, 50)) values = tuple(map(position_value, positions)) print(values) # (200, 150) print(portfolio_value(positions)) # 350 print(positions) # ((2, 100), (3, 50))
Here position_value is pure for the stated integer-pair inputs: its result depends on the supplied pair, and it changes no externally visible state. The same is true of portfolio_value for a tuple of these pairs. The printing happens afterward, outside the calculations.
map is a higher-order function: it accepts another function as an argument. It returns an iterator that applies that function to the input elements; tuple collects the individual values, while sum aggregates them. See the official map reference. A comprehension would also be a reasonable way to express this calculation.
An explicit-input valuation pipeline: a snapshot of two units at USD 100 and three at USD 50 passes through pure calculations to USD 200 and USD 150, then USD 350 total; loading and reporting sit outside the calculation boundary.
An explicit-input valuation pipeline: a snapshot of two units at USD 100 and three at USD 50 passes through pure calculations to USD 200 and USD 150, then USD 350 total; loading and reporting sit outside the calculation boundary.
Fictional USD positions. Data loading and reporting have effects; the calculation receives a snapshot and returns values without altering it.

Put changing information at the boundary

A valuation function that reads a global prices dictionary has a dependency its call does not reveal. A function that fetches a live quote can return a different number even when its explicit arguments are unchanged. A function that updates a shared positions dictionary can also change what the next calculation sees.

A useful design is to load and validate a market snapshot first, pass it into the calculation, then save or display the returned result. Real applications need these effects; keeping them at a clear boundary helps isolate numerical logic. For research reproducibility, retain the input snapshot, configuration and code/environment versions as well. A pure calculation cannot recover yesterday's missing market data.

What the syntax does not guarantee

Using map or a lambda does not make a calculation pure. The function passed to map can still mutate an object; a lambda can still read a changing global. Python describes lambda expressions as small function expressions, with access to surrounding names, in its lambda tutorial.
Immutability helps protect inputs, but its scope matters. A tuple prevents replacement of its elements; a list stored inside a tuple can still change. This example uses tuples containing only integers, so it avoids that nested-mutation problem. See Python's object model.
Functional style is a design choice, not a speed guarantee. Choose readable transformations, test their contracts, and measure performance on the actual workload. The Functions lesson, available with a free signed-in account, develops explicit parameters, composition and the separation of calculation from display.

Sources

Last updated
  • functional programming
  • python
  • software design
  • reproducibility
← Back to the glossaryBack to top ↑