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()
orisinstance()
. (Note, however, that duck-typing can be complemented with abstract base classes.) Instead, it typically employshasattr()
tests or EAFP programming.
You can't use duck-typing to add members to regular C# types.
You can use duck-typing to add attributes to all non-primitive types in Python
// Duck-typing doesn't work on regular C# types. class Duck { } var duck = new Duck(); duck.quacks = "Quack!" // This yields a compilation error. dynamic duck = new Duck(); duck.quacks = "Quack!" // This yields a runtime error.
# Duck-typing allows adding attributes to non-primitive types in Python. class Duck: pass duck = Duck() duck.quacks = "Quack!" print(duck.quacks)
LEAN allows duck-typing in the Security
type.
Custom Security Properties
You can add propertiesattributes to the Security
object. For example, you can add an exponential moving average.
// Cast the Equity to a dynamic object to add an EMA indicator to it. dynamic equity = AddEquity("SPY"); equity.ema = EMA(equity.Symbol, 10, Resolution.Daily);
# 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
securities
object.
// Get the SPY Equity object from Securities to get the EMA indicator. var ema = (decimal)(Securities["SPY"] as dynamic).ema.Current.Value;
# Get the SPY Equity object from Securities to get the EMA indicator. ema = self.securities["SPY"].ema.current.value
To avoid casting to and from the dynamic
type, you can use the Get<T>
method to access the dynamic member and return the object with its type.
// Get the SPY Equity object from Securities to get the EMA indicator and its current value var ema = Securities["SPY"].Get<ExponentialMovingAverage>("ema"); // The type of ema is ExponentialMovingAverage var emaValue = ema.Current.Value; // The type of emaValue is decimal
If the type or the member name is incorrect, the Get<T>
method causes a runtime error.
Other Types
You can only add properties to the Security
type.
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