text: #!/usr/bin/env python
  # -*- coding: utf-8; py-indent-offset:4 -*-
  ###############################################################################
  #
  # Copyright (C) 2015-2020 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)
  
  # Reference
  # https://estrategiastrading.com/oro-bolsa-estadistica-con-python/
  
  import argparse
  import datetime
  
  import scipy.stats
  
  import backtrader as bt
  
  
  class PearsonR(bt.ind.PeriodN):
      _mindatas = 2  # hint to the platform
  
      lines = ('correlation',)
      params = (('period', 20),)
  
      def next(self):
          c, p = scipy.stats.pearsonr(self.data0.get(size=self.p.period),
                                      self.data1.get(size=self.p.period))
  
          self.lines.correlation[0] = c
  
  
  class MACrossOver(bt.Strategy):
      params = (
          ('ma', bt.ind.MovAv.SMA),
          ('pd1', 20),
          ('pd2', 20),
      )
  
      def __init__(self):
          ma1 = self.p.ma(self.data0, period=self.p.pd1, subplot=True)
          self.p.ma(self.data1, period=self.p.pd2, plotmaster=ma1)
          PearsonR(self.data0, self.data1)
  
  
  def runstrat(args=None):
      args = parse_args(args)
  
      cerebro = bt.Cerebro()
  
      # Data feed kwargs
      kwargs = dict()
  
      # Parse from/to-date
      dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
      for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
          if a:
              strpfmt = dtfmt + tmfmt * ('T' in a)
              kwargs[d] = datetime.datetime.strptime(a, strpfmt)
  
      if not args.offline:
          YahooData = bt.feeds.YahooFinanceData
      else:
          YahooData = bt.feeds.YahooFinanceCSVData
  
      # Data feeds
      data0 = YahooData(dataname=args.data0, **kwargs)
      # cerebro.adddata(data0)
      cerebro.resampledata(data0, timeframe=bt.TimeFrame.Weeks)
  
      data1 = YahooData(dataname=args.data1, **kwargs)
      # cerebro.adddata(data1)
      cerebro.resampledata(data1, timeframe=bt.TimeFrame.Weeks)
      data1.plotinfo.plotmaster = data0
  
      # Broker
      kwargs = eval('dict(' + args.broker + ')')
      cerebro.broker = bt.brokers.BackBroker(**kwargs)
  
      # Sizer
      kwargs = eval('dict(' + args.sizer + ')')
      cerebro.addsizer(bt.sizers.FixedSize, **kwargs)
  
      # Strategy
      if True:
          kwargs = eval('dict(' + args.strat + ')')
          cerebro.addstrategy(MACrossOver, **kwargs)
  
      cerebro.addobserver(bt.observers.LogReturns2,
                          timeframe=bt.TimeFrame.Weeks,
                          compression=20)
  
      # Execute
      cerebro.run(**(eval('dict(' + args.cerebro + ')')))
  
      if args.plot:  # Plot if requested to
          cerebro.plot(**(eval('dict(' + args.plot + ')')))
  
  
  def parse_args(pargs=None):
  
      parser = argparse.ArgumentParser(
          formatter_class=argparse.ArgumentDefaultsHelpFormatter,
          description=(
              'Gold vs SP500 from '
              'https://estrategiastrading.com/oro-bolsa-estadistica-con-python/')
      )
  
      parser.add_argument('--data0', required=False, default='SPY',
                          metavar='TICKER', help='Yahoo ticker to download')
  
      parser.add_argument('--data1', required=False, default='GLD',
                          metavar='TICKER', help='Yahoo ticker to download')
  
      parser.add_argument('--offline', required=False, action='store_true',
                          help='Use the offline files')
  
      # Defaults for dates
      parser.add_argument('--fromdate', required=False, default='2005-01-01',
                          help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
  
      parser.add_argument('--todate', required=False, default='2016-01-01',
                          help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
  
      parser.add_argument('--cerebro', required=False, default='',
                          metavar='kwargs', help='kwargs in key=value format')
  
      parser.add_argument('--broker', required=False, default='',
                          metavar='kwargs', help='kwargs in key=value format')
  
      parser.add_argument('--sizer', required=False, default='',
                          metavar='kwargs', help='kwargs in key=value format')
  
      parser.add_argument('--strat', required=False, default='',
                          metavar='kwargs', help='kwargs in key=value format')
  
      parser.add_argument('--plot', required=False, default='',
                          nargs='?', const='{}',
                          metavar='kwargs', help='kwargs in key=value format')
  
      return parser.parse_args(pargs)
  
  
  if __name__ == '__main__':
      runstrat()
  