Skip to content

Object-oriented programming

Object-oriented programming combines state and operations in objects. A position example shows instance identity, shared-state pitfalls and useful quant interfaces.

Object-oriented programming (OOP) organises software around objects that combine state with operations on that state. In quant work, a position can hold a quantity and a market mark, then expose an operation that returns its value. The design question is who owns each input and which operations callers may rely on.

A class describes behaviour; instances hold positions

A class defines a type of object. An instance is a particular object of that type. An attribute stores or exposes data; a method is an operation called through an object. Python supplies the instance as self when a bound method is called. These distinctions are described in the Python classes tutorial.

Here is a fictional long equity position. Quantity is in shares, the mark is in USD per share, and value is in USD. Integer-valued marks keep the arithmetic transparent; fees, FX and corporate actions are outside this example.

class Position: def __init__(self, quantity: int, mark_usd: float) -> None: self.quantity = quantity self.mark_usd = mark_usd def value_usd(self) -> float: return self.quantity * self.mark_usd position = Position(2, 100.0) other = Position(1, 100.0) print(position.value_usd()) # 200.0 alias = position alias.mark_usd = 110.0 print(position.value_usd(), other.value_usd()) # 220.0 100.0 print(alias is position) # True

Both positions use the same method definition, but their attributes are separate. Updating the first position's mark changes its value from USD 200 to USD 220; the second remains worth USD 100. The USD 20 difference is a mark-to-market gain under these fixed-holding assumptions, not a cash receipt.

alias = position creates another name for the same object, so the update through alias is visible through position. It does not create a snapshot. This distinction between identity and changing state matters when saving backtest history. Python's data model explains object identity and mutability.
Two names, position and alias, refer to the same Position: 2 shares marked at USD 100 then USD 110, giving USD 200 then USD 220. A separate other instance holds 1 share at USD 100 and remains worth USD 100.
Two names, position and alias, refer to the same Position: 2 shares marked at USD 100 then USD 110, giving USD 200 then USD 220. A separate other instance holds 1 share at USD 100 and remains worth USD 100.
One shared method definition, separate instance state. Fictional equity marks are USD per share; position values are USD.

Shared state is a separate choice

A mutable attribute placed on the class can accidentally connect independent books:

class BadBook: positions = [] first = BadBook() second = BadBook() first.positions.append("ABC") print(second.positions) # ['ABC']
Both instances find the same class-level list. Create self.positions = [] inside __init__ when each book needs its own list. Sharing a curve or reference-data object can be intentional; sharing an order list by accident can contaminate a simulation. See the official distinction between class and instance variables.

An interface is a promise about meaning

The useful interface here is value_usd(): callers expect a value in USD. A matching method name alone cannot establish currency, valuation time or whether accrued amounts are included. Those belong in the contract and its tests. With duck typing, unrelated classes can supply the same useful interface without inheriting from a common parent.
The example exposes writable attributes to make mutation visible. A reusable position API would need explicit validation and rules for updates. Python's type annotations are not enforced by the runtime; mark_usd: float does not reject a missing, nonfinite or incorrectly denominated mark. Encapsulation means organising access around a supported interface; an underscore convention is not a security boundary.
Composition connects cooperating objects: a bond uses a discount curve supplied to its pricing method. Inheritance derives a class from a base class and can replace inherited methods. A bond needs a curve; it is not a kind of curve. The owned Object-Oriented Model Design lesson develops this separation of contract terms, market data and model parameters. Its public preview outlines the lesson; the full lesson requires membership.

Use classes when persistent identity, controlled state or interchangeable behaviour helps organise the problem. A small payoff calculation may be clearer as a function, and a large simulation may keep its numerical data in arrays. OOP by itself guarantees neither faster execution nor a better financial model.

Sources

The examples were executed with Python 3.14.4 using the standard library.

Last updated
  • python
  • software design
  • objects
  • state
← Back to the glossaryBack to top ↑