book
Checkout our new book! Hands on AI Trading with Python, QuantConnect, and AWS Learn More arrow

Key Concepts

Duck Typing

Introduction

Duck typing is popular type system in Python. The language documentation defines 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() or isinstance(). (Note, however, that duck-typing can be complemented with abstract base classes.) Instead, it typically employs hasattr() tests or EAFP programming.


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

Select Language:
# 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.

Select Language:
# 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.

Select Language:
# 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 to the symbol attribute of a Security object.

# 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 , so the indicator is discarded together with the Security when it is removed from the universe.

Select Language:
class DuckTypingAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2022, 1, 1)
        self.set_end_date(2022, 6, 1)
        # 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.dollar_volume.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)

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: