---
title: "Duck Typing"
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/duck-typing
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/duck-typing.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/01%20Key%20Concepts/09%20Duck%20Typing
modified: 2026-10-31
index: https://www.quantconnect.com/llms.txt
---

# Duck Typing

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Writing Algorithms](https://www.quantconnect.com/docs/v2/writing-algorithms.md) > Key Concepts > Duck Typing

> Code examples are shown in Python. Append `?lang=csharp` to this URL for the C# version of this page.

## Introduction

Duck typing is popular type system in Python. The language documentation defines [duck typing](https://docs.python.org/3/glossary.html#term-duck-typing) as follows:

> A programming style which does not look at an object's type to determine if it has the right interface; instead, the method or attribute is simply called or used (“If it looks like a duck and quacks like a duck, it must be a duck.”) By emphasizing interfaces rather than specific types, well-designed code improves its flexibility by allowing polymorphic substitution.
>
> Duck-typing avoids tests using [`type()`](https://docs.python.org/3/library/functions.html#type) or [`isinstance()`](https://docs.python.org/3/library/functions.html#isinstance). (Note, however, that duck-typing can be complemented with [abstract base classes](https://docs.python.org/3/glossary.html#term-abstract-base-class).) Instead, it typically employs [`hasattr()`](https://docs.python.org/3/library/functions.html#hasattr) tests or [EAFP](https://docs.python.org/3/glossary.html#term-EAFP) programming.

You can use duck-typing to add attributes to all non-primitive types in Python

```python
# Duck-typing enables you to add attributes to non-primitive types in Python.
class Duck:
    pass

duck = Duck()
duck.quacks = "Quack!"
print(duck.quacks)
```

## Custom Security Properties

You can add attributes to the `Security` object. For example, you can add an [exponential moving average](https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/supported-indicators/exponential-moving-average.md).

```python
# Add an EMA indicator to the SPY Equity object.
equity = self.add_equity("SPY")
equity.ema = self.ema(equity.symbol, 10, Resolution.DAILY)
```

This feature is helpful because you can get the `Security` object from the `securities` object.

```python
# Get the SPY Equity object from the securities object to get the EMA indicator.
ema = self.securities["SPY"].ema.current.value
```

## Other Types

You can add properties to all types. However, these properties live in the Python space, so you can't access them without a reference. The following example demonstrates that you can add an [exponential moving average](https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/supported-indicators/exponential-moving-average.md) to the `symbol` attribute of a `Security` object.

```python
# Add an EMA to the SPY security.
equity = self.add_equity("SPY")
self._symbol = equity.symbol
self._symbol.ema = self.ema(self._symbol, 10)
ema = self._symbol.ema.current.value

ema = self.securities["SPY"].symbol.ema.current.value
```

## Examples

The following examples demonstrate some common practices for duck typing.

### Example 1: Store EMA Indicator

The following example implements a trend-following strategy using the EMA indicator for the top 20 liquid equities. It uses duck typing to store the EMA indicator in each [Security object](https://www.quantconnect.com/docs/v2/writing-algorithms/securities/key-concepts.md) , so the indicator is discarded together with the `Security` when it is removed from the universe.

```python
class DuckTypingAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 12, 31)
        # Weekly renewal on the universe to allow time to capitalize on the trend.
        self.universe_settings.schedule.on(self.date_rules.week_start())
        # Trade on the top 20 liquid equities since they have higher volume and hence price movements.
        self._universe = self.add_universe(self.universe.top(20))

    def on_data(self, slice: Slice) -> None:
        for kvp in self._universe.members:
            symbol, security = kvp.key, kvp.value

            # Trade on updated price data.
            bar = slice.bars.get(symbol)
            if bar:
                ema = security.ema.current.value
                # Switch to long if the current price is above EMA, suggesting an uptrend.
                if bar.close > ema and not self.portfolio[symbol].is_long:
                    self.set_holdings(symbol, 0.025)
                elif bar.close < ema and not self.portfolio[symbol].is_short:
                    self.set_holdings(symbol, -0.025)

    def on_securities_changed(self, changes: SecurityChanges) -> None:
        for removed in changes.removed_securities:
            # Liquidate if it is not in the top 50 liquidity stocks anymore.
            self.liquidate(removed.symbol)
            # Release resources that update automatic indicators
            self.deregister_indicator(removed.ema)

        for added in changes.added_securities:
            # Use duck typing to create an EMA indicator for trend trading.
            # Discarded together when the security is removed from the universe, you won't need to handle it.
            added.ema = self.ema(added.symbol, 60, Resolution.DAILY)
            # Warm up the EMA indicator to ensure its readiness for immediate usage.
            self.warm_up_indicator(added.symbol, added.ema, Resolution.DAILY)
```
