Guide and Pro tips

Getting started

Installation and setup

  1. Install prerequisite framework dependencies

    Stock Indicators for Python has dependency on PythonNet, which uses CLR(Common Language Runtime). Check that you’ve installed the following prerequisite software:

    Use the latest Python and .NET SDK for best performance.

    Installer Min Latest Download
    Python 3.8 3.12 @python.org
    .NET SDK 6.0 8.0 @microsoft.com

    Note: we do not support the open source Mono .NET Framework.

  2. Find and install the stock-indicators Python package into your environment.

     # pip example
     pip install stock-indicators
    

    See Python documentation for more help with installing packages.

Prerequisite data

Most indicators require that you provide historical quote data and additional configuration parameters.

You must get historical quotes from your own market data provider. For clarification, the get_history_from_feed() method shown in the example below and throughout our documentation is not part of this library, but rather an example to represent your own acquisition of historical quotes.

Historical price data can be provided as an Iterable(such as List or an object having __iter__()) of the Quote class or its sub-class (see below); Be aware that you have to inherit Quote class when you make custom quote class.

For additional configuration parameters, default values are provided when there is an industry standard. You can, of course, override these and provide your own values.

Example usage

All indicator methods will produce all possible results for the provided historical quotes as a time series dataset – it is not just a single data point returned. For example, if you provide 3 years worth of historical quotes for the SMA method, you’ll get 3 years of SMA result values.

from stock_indicators import indicators

# fetch historical quotes from your feed (your method)
quotes = get_historical_quotes("MSFT")

# calculate 20-period SMA
results = indicators.get_sma(quotes, 20)

# use results as needed for your use case (example only)
for r in results:
    print(f"SMA on {r.date.date()} was ${r.sma or 0:.4f}")

SMA on 2018-04-19 was $255.0590
SMA on 2018-04-20 was $255.2015
SMA on 2018-04-23 was $255.6135
SMA on 2018-04-24 was $255.5105
SMA on 2018-04-25 was $255.6570
SMA on 2018-04-26 was $255.9705
..

See individual indicator pages for specific usage guidance.

More examples available:

Historical quotes

You must provide historical price quotes to the library in the standard OHLCV Iterable[Quote](such as a list of Quote) format. It should have a consistent period frequency (day, hour, minute, etc).

from stock_indicators.indicators.common.quote import Quote

class Quote(date, open=None, high=None, low=None, close=None, volume=None) [source]

name type notes
date datetime.datetime Date
open decimal.Decimal, Optional Open price
high decimal.Decimal, Optional High price
low decimal.Decimal, Optional Low price
close decimal.Decimal, Optional Close price
volume decimal.Decimal, Optional Volume

Note that

  1. date is always required, while each ohlcv values are optional.
  2. ohlcv can be provided by float, Decimal and str representing number, but these are always stored as Decimal.

Where can I get historical quote data?

There are many places to get stock market data. Check with your brokerage or other commercial sites. If you’re looking for a free developer API, see our ongoing discussion on market data for ideas.

How much historical quote data do I need?

Each indicator will need different amounts of price quotes to calculate. You can find guidance on the individual indicator documentation pages for minimum requirements; however, most use cases will require that you provide more than the minimum. As a general rule of thumb, you will be safe if you provide 750 points of historical quote data (e.g. 3 years of daily data). A BadQuotesException will be thrown if you do not provide sufficient historical quotes to produce any results.

🚩 IMPORTANT! Some indicators use a smoothing technique that converges to better precision over time. While you can calculate these with the minimum amount of quote data, the precision to two decimal points often requires 250 or more preceding historical records.

For example, if you are using daily data and want one year of precise EMA(250) data, you need to provide 3 years of historical quotes (1 extra year for the lookback period and 1 extra year for convergence); thereafter, you would discard or not use the first two years of results. Occassionally, even more is required for optimal precision.

Using Pandas.Dataframe

If you are using Pandas.Dataframe to hold quote data, you have to convert it into our Quote instance. That means you must iterate them row by row. There’s an awesome article that introduces the best-efficiency way to iterate Dataframe.

Here’s an example we’d like to suggest: Use list comprehension

# Suppose that you have dataframe like the below.
#             date    open    high     low   close     volume
# 0     2018-12-31  244.92  245.54  242.87  245.28  147031456
# 1     2018-12-28  244.94  246.73  241.87  243.15  155998912
# 2     2018-12-27  238.06  243.68  234.52  243.46  189794032
# ...          ...     ...     ...     ...     ...        ...

from stock_indicators import Quote

quotes_list = [
    Quote(d,o,h,l,c,v) 
    for d,o,h,l,c,v 
    in zip(df['date'], df['open'], df['high'], df['low'], df['close'], df['volume'])
]

You can also use numpy.vectorize(), its gain is too slight and hard to apply in this case.

Using custom quote classes

If you would like to use your own custom MyCustomQuote quote class, you have to inherit Quote class. The Quote class is a special class which converts OHLCV properties existing as Python objects to C# objects and which is concrete class of IQuote of C# implementation. It enables Pythonnet to work with our C# implementation using generics.

from stock_indicators.indicators.common import Quote

class MyCustomQuote(Quote):
    def foo(self): ...
    ... add your own attributes.

from stock_indicators import indicators

# fetch historical quotes from your favorite feed
quotes: Iterable[MyCustomQuote] = get_history_from_feed("MSFT");

# example: get 20-period simple moving average
results = indicators.get_sma(quotes, 20);

Using custom quote property names

If you have a model that has different properties names, but the same meaning, you only need to map them. Each properties is property object, so you can just reference them.

Suppose your class has a property called close_date instead of date, it could be represented like this:

from stock_indicators.indicators.common.quote import Quote

class MyCustomQuote(Quote):
    close_date = Quote.date

Note that the property date now can be accessed by both close_date and date.

Using derived results classes

The indicator result (e.g. EMAResult) classes can be extended in your code.

Here’s an example of how you’d set that up:

from stock_indicators import indicators
from stock_indicators.indicators.ema import EMAResult

class ExtendedEMA(EMAResult):
    def __str__(self):
        return f"EMA on {self.date.date()} was ${self.ema or 0:.4f}"
    
# compute indicator
quotes = get_history_from_feed("MSFT")
results = indicators.get_ema(quotes, 20)

# 1. list[ExtendedEMA]
extended_results = [ ExtendedEMA(r._csdata) for r in results ]
for r in extended_results:
    print(r)

Be aware that If you want to use helper functions, use wrapper class(e.g. EMAResults).

# 2. use wrapper for helper function
from stock_indicators.indicators.ema import EMAResults

extended_results = EMAResults[ExtendedEMA](results._csdata, ExtendedEMA)
pruned_results = extended_results.remove_warmup_periods()
for r in pruned_results:
    print(r)

Generating indicator of indicators

If you want to compute an indicator of indicators, such as an SMA of an ADX or an RSI of an OBV, all you need to do is to take the results of one, reformat into a synthetic historical quotes, and send it through to another indicator.

from stock_indicators import indicators

# fetch historical quotes from your feed (your method)
quotes = get_history_from_feed("MSFT")

# calculate EMA
results = indicators.get_ema(quotes, 20)

# convert to synthetic quotes
quotes_from_ema = [ Quote(date=r.date, close=r.ema) for r in results ]

# calculate SMA of EMA
sma_of_ema = indicators.get_sma(quotes_from_ema, 20)

Candlestick patterns

Candlestick Patterns are a unique form of indicator and have a common output model.

CandleResult

name type notes
date datetime Date
price decimal, Optional Price of the most relevant OHLC candle element when a match is present
match Match Generated Match type
candle CandleProperties Candle properties

Match

When a candlestick pattern is recognized, it produces a match. In some cases, an intrinsic confirmation is also available. In cases where previous bars were used to identify a pattern, they are indicated as the basis for the match. Documentation for each candlestick pattern will indicate whether confirmation and/or basis information is produced.

from stock_indicators.indicators.common.enums import Match
type description
Match.BULL_CONFIRMED Confirmation of a prior bull Match
Match.BULL_SIGNAL Matching bullish pattern
Match.BULL_BASIS Bars supporting a bullish Match
Match.NEUTRAL Matching for non-directional patterns
Match.NONE No match
Match.BEAR_BASIS Bars supporting a bearish Match
Match.BEAR_SIGNAL Matching bearish pattern
Match.BEAR_CONFIRMED Confirmation of a prior bear Match

Candle

The CandleProperties class is an extended version of Quote, and contains additional calculated properties.

name type notes
date datetime Date
open Decimal Open price
high Decimal High price
low Decimal Low price
close Decimal Close price
volume Decimal Volume
size Decimal, Optional high-low
body Decimal, Optional |open-close|
upper_wick Decimal, Optional Upper wick size
lower_wick Decimal, Optional Lower wick size
body_pct float, Optional body/size
upper_wick_pct float, Optional upper_wick/size
lower_wick_pct float, Optional lower_wick/size
is_bullish bool close>open direction
is_bearish bool close<open direction

Utilities

See Utilities and helper functions for additional tools.