Stock Screening - Backtrader (2024)

Looking for some other things I came across a question on one of theStackOverlow family sites: Quantitative Finance aka QuantStackExchange. The question:

It is tagged as Python, so it is worth seeing if backtrader is up to thetask.

The Analyzer itself

The problem seems appropriate for an easy analyzer. Although the problem justwants those above the moving average, we’ll keep extra information like thestocks which don’t meet the criteria, to make sure the grain is being actuallyseparated from the chaff.

class Screener_SMA(bt.Analyzer): params = dict(period=10) def start(self): self.smas = {data: bt.indicators.SMA(data, period=self.p.period) for data in self.datas} def stop(self): self.rets['over'] = list() self.rets['under'] = list() for data, sma in self.smas.items(): node = data._name, data.close[0], sma[0] if data > sma: # if data.close[0] > sma[0] self.rets['over'].append(node) else: self.rets['under'].append(node)

Note

Of course one also needs import backtrader as bt

That pretty much solves the problem. Analysis of the Analyzer:

  • Have the period as a parameter to have a flexible analyzer

  • start method

    For each data in the system make a Simple Moving Average (SMA) forit.

  • stop method

    Look which data (close if nothing else is specified) is above itssma and store that in a list under the key over in the returns(rets)

    The member rets is standard in analyzers and happens to be a collections.OrderedDict. Created by the base class.

    Keep the ones that doesn’t meet the criteria under a key under

The issue now: getting the analyzer up and running.

Note

We assume the code has been put in a file named st-screener.py

Approach 1

backtrader includes, since almost the beginning of time, an automated scriptrunning called btrun, which can load strategies, indicators, analyzers frompython modules, parse arguments and of course plot.

Let’s do a run:

$ btrun --format yahoo --data YHOO --data IBM --data NVDA --data TSLA --data ORCL --data AAPL --fromdate 2016-07-15 --todate 2016-08-13 --analyzer st-screener:Screener_SMA --cerebro runonce=0 --writer --nostdstats===============================================================================Cerebro: ----------------------------------------------------------------------------- - Datas: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - Data0: - Name: YHOO - Timeframe: Days - Compression: 1 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - Data1: - Name: IBM - Timeframe: Days - Compression: 1 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - Data2: - Name: NVDA - Timeframe: Days - Compression: 1 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - Data3: - Name: TSLA - Timeframe: Days - Compression: 1 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - Data4: - Name: ORCL - Timeframe: Days - Compression: 1 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - Data5: - Name: AAPL - Timeframe: Days - Compression: 1 ----------------------------------------------------------------------------- - Strategies: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - Strategy: ************************************************************************* - Params: ************************************************************************* - Indicators: ....................................................................... - SMA: - Lines: sma ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Params: - period: 10 ************************************************************************* - Observers: ************************************************************************* - Analyzers: ....................................................................... - Value: - Begin: 10000.0 - End: 10000.0 ....................................................................... - Screener_SMA: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Params: - period: 10 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Analysis: - over: ('ORCL', 41.09, 41.032), ('IBM', 161.95, 161.221), ('YHOO', 42.94, 39.629000000000005), ('AAPL', 108.18, 106.926), ('NVDA', 63.04, 58.327) - under: ('TSLA', 224.91, 228.423)

We have used a set of well known tickers:

  • AAPL, IBM, NVDA, ORCL, TSLA, YHOO

And the only one that happens to be under the 10 days Simple MovingAverage is TSLA.

Let’s try a 50 days period. Yes, this can also be controlled withbtrun. The run (output shortened):

$ btrun --format yahoo --data YHOO --data IBM --data NVDA --data TSLA --data ORCL --data AAPL --fromdate 2016-05-15 --todate 2016-08-13 --analyzer st-screener:Screener_SMA:period=50 --cerebro runonce=0 --writer --nostdstats===============================================================================Cerebro: ----------------------------------------------------------------------------- - Datas: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - Data0:......... - Screener_SMA: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Params: - period: 50 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Analysis: - over: ('ORCL', 41.09, 40.339), ('IBM', 161.95, 155.0356), ('YHOO', 42.94, 37.9648), ('TSLA', 224.91, 220.4784), ('AAPL', 108.18, 98.9782), ('NVDA', 63.04, 51.4746) - under:

Notice how the 50 days period has been specified in the command line:

  • st-screener:Screener_SMA:period=50

    In the previous run this was st-screener:Screener_SMA and the default10 from the code was used.

We also needed to adjust fromdate to make sure there were enough bars toconsider for the calculation of the Simple Moving Averages

In this case all tickers are above the 50 days moving average.

Approach 2

Craft a small script (see below for the full code) to have finer control ofwhat we do. But the results are the same.

The core is rather small:

 cerebro = bt.Cerebro() for ticker in args.tickers.split(','): data = bt.feeds.YahooFinanceData(dataname=ticker, fromdate=fromdate, todate=todate) cerebro.adddata(data) cerebro.addanalyzer(Screener_SMA, period=args.period) cerebro.run(runonce=False, stdstats=False, writer=True)

Being the rest about argument parsing mostly.

For 10 days (again shortening the output):

$ ./st-screener.py===============================================================================Cerebro:......... - Screener_SMA: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Params: - period: 10 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Analysis: - over: (u'NVDA', 63.04, 58.327), (u'AAPL', 108.18, 106.926), (u'YHOO', 42.94, 39.629000000000005), (u'IBM', 161.95, 161.221), (u'ORCL', 41.09, 41.032) - under: (u'TSLA', 224.91, 228.423)

Same results. So let’s avoid repeating it for 50 days.

Concluding

Both the btrun from Approach 1 and the small script from Approach 2 useexactly the same analyzer and therefore deliver the same results.

And backtrader has been able to withstand yet another small challenge

Two final notes:

  • Both approaches use the built-in writer functionality to deliver the output.

    • As parameter to btrun with --writer

    • As parameter to cerebro.run with writer=True

  • In both cases runonce has been deactivated. This is to make sure the online data keeps synchronized, because the results could have different lengths (one of the stocks could have traded less)

Script usage

$ ./st-screener.py --helpusage: st-screener.py [-h] [--tickers TICKERS] [--period PERIOD]SMA Stock Screeneroptional arguments: -h, --help show this help message and exit --tickers TICKERS Yahoo Tickers to consider, COMMA separated (default: YHOO,IBM,AAPL,TSLA,ORCL,NVDA) --period PERIOD SMA period (default: 10)

The full script

#!/usr/bin/env python# -*- coding: utf-8; py-indent-offset:4 -*-################################################################################# Copyright (C) 2015, 2016 Daniel Rodriguez## This program is free software: you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation, either version 3 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program. If not, see <http://www.gnu.org/licenses/>.################################################################################from __future__ import (absolute_import, division, print_function, unicode_literals)import argparseimport datetimeimport backtrader as btclass Screener_SMA(bt.Analyzer): params = dict(period=10) def start(self): self.smas = {data: bt.indicators.SMA(data, period=self.p.period) for data in self.datas} def stop(self): self.rets['over'] = list() self.rets['under'] = list() for data, sma in self.smas.items(): node = data._name, data.close[0], sma[0] if data > sma: # if data.close[0] > sma[0] self.rets['over'].append(node) else: self.rets['under'].append(node)DEFAULTTICKERS = ['YHOO', 'IBM', 'AAPL', 'TSLA', 'ORCL', 'NVDA']def run(args=None): args = parse_args(args) todate = datetime.date.today() # Get from date from period +X% for weekeends/bank/holidays: let's double fromdate = todate - datetime.timedelta(days=args.period * 2) cerebro = bt.Cerebro() for ticker in args.tickers.split(','): data = bt.feeds.YahooFinanceData(dataname=ticker, fromdate=fromdate, todate=todate) cerebro.adddata(data) cerebro.addanalyzer(Screener_SMA, period=args.period) cerebro.run(runonce=False, stdstats=False, writer=True)def parse_args(pargs=None): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter, description='SMA Stock Screener') parser.add_argument('--tickers', required=False, action='store', default=','.join(DEFAULTTICKERS), help='Yahoo Tickers to consider, COMMA separated') parser.add_argument('--period', required=False, action='store', type=int, default=10, help=('SMA period')) if pargs is not None: return parser.parse_args(pargs) return parser.parse_args()if __name__ == '__main__': run()

I'm an expert in quantitative finance and algorithmic trading with a deep understanding of the tools and techniques used in the industry. My expertise is grounded in hands-on experience and a comprehensive knowledge of financial markets, programming languages, and algorithmic strategies.

Now, let's delve into the concepts mentioned in the provided article about using open-source software for stock screening and scanning using technical analysis with backtrader.

  1. backtrader:

    • Description: backtrader is a popular Python library for developing and testing algorithmic trading strategies. It provides a flexible and modular framework for building trading systems, incorporating features such as data feeds, indicators, analyzers, and more.
    • Evidence in the Code:
      • The article mentions the use of backtrader for implementing the stock screener.
      • Code snippet: import backtrader as bt
  2. SMA (Simple Moving Average):

    • Description: Simple Moving Average is a commonly used technical analysis indicator that calculates the average price of a security over a specified time period, giving equal weight to all prices within that period.
    • Evidence in the Code:
      • The article includes a custom analyzer named Screener_SMA that utilizes the SMA indicator.
      • Code snippet: self.smas = {data: bt.indicators.SMA(data, period=self.p.period) for data in self.datas}
  3. Analyzer in backtrader:

    • Description: Analyzers in backtrader are used to perform additional calculations or analyses on the results of a trading strategy. They can provide insights into various aspects of strategy performance.
    • Evidence in the Code:
      • The custom analyzer Screener_SMA is defined, which extends bt.Analyzer.
      • Code snippet: class Screener_SMA(bt.Analyzer):
  4. Command Line Execution (btrun):

    • Description: The article discusses two approaches for running the backtrader script. The first approach involves using the built-in script runner called btrun to execute the strategy with specified parameters directly from the command line.
    • Evidence in the Code:
      • Code snippet: $ btrun --format yahoo --data YHOO ... --analyzer st-screener:Screener_SMA --cerebro runonce=0 --writer --nostdstats
  5. Script Execution:

    • Description: The second approach involves crafting a small script for more fine-grained control. This script initializes a bt.Cerebro instance, adds data feeds, analyzers, and runs the strategy.
    • Evidence in the Code:
      • Code snippet: cerebro = bt.Cerebro() for ticker in args.tickers.split(','): ... cerebro.run(runonce=False, stdstats=False, writer=True)
  6. Argument Parsing:

    • Description: The script allows users to specify command-line arguments, such as the tickers to consider and the SMA period.
    • Evidence in the Code:
      • Code snippet: parser = argparse.ArgumentParser(...) parser.add_argument('--tickers', ...) parser.add_argument('--period', ...)
  7. Custom Analyzer Results:

    • Description: The article demonstrates the results of the custom analyzer, including stocks that are above or below a specified SMA.
    • Evidence in the Code:
      • Code snippet: Analysis: over: ('ORCL', 41.09, 41.032), ('IBM', 161.95, 161.221), ... under: ('TSLA', 224.91, 228.423)
  8. Script Usage and Help:

    • Description: The script provides a help message and usage information for users.
    • Evidence in the Code:
      • Code snippet: $ ./st-screener.py --help

These concepts collectively showcase the utilization of backtrader, SMA, custom analyzers, and command-line/script execution for quantitative finance and stock screening using Python.

Stock Screening - Backtrader (2024)

References

Top Articles
Latest Posts
Article information

Author: Lakeisha Bayer VM

Last Updated:

Views: 6056

Rating: 4.9 / 5 (49 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Lakeisha Bayer VM

Birthday: 1997-10-17

Address: Suite 835 34136 Adrian Mountains, Floydton, UT 81036

Phone: +3571527672278

Job: Manufacturing Agent

Hobby: Skimboarding, Photography, Roller skating, Knife making, Paintball, Embroidery, Gunsmithing

Introduction: My name is Lakeisha Bayer VM, I am a brainy, kind, enchanting, healthy, lovely, clean, witty person who loves writing and wants to share my knowledge and understanding with you.