Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    Qs about behavior of once_via_next and runonce

    General Discussion
    2
    3
    170
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • JasonTam
      JasonTam last edited by

      Hi, new user here trying to better understand the control flow of indicators when runonce=True

      Consider a simple indicator that just copies a signal using a next method:

      class Copy(bt.Indicator):
          lines = ('copy',)
          
          def __init__(self):
              self.x = self.datas[0]
          def next(self):
              self.lines.copy[0] = self.x[0]
      

      If I use this copy indicator on some indicator with a non-zero period and run cerebro with runonce=True , the ouput of the indicator becomes all nans.

      class TestStrategy(bt.Strategy):
      
          def __init__(self):
              self.signal = bt.ind.PercentChange(
                  self.datas[0], period=1)
              self.signal_copy = Copy(self.signal)
      
      cerebro = bt.Cerebro(runonce=True)
      cerebro.adddata(data)
      cerebro.addstrategy(TestStrategy)
      
      strats_out = cerebro.run()
      strat = strats_out[0]
      
      # Id expect these two to be the same
      strat.signal.array[:10]
      strat.signal_copy.array[:10]
      

      (However, with run_once=False, the results are as expected.)

      After reading https://community.backtrader.com/topic/242/is-backtrader-event-driven-or-vectorized/2 and realizing there is a once_via_next method in Indicator, I thought that even if run_once=True, the signal would be copied batch-wise after the nested signal finishes evaluating.
      (Q1) Why is this copy indicator using next evaluating to all nans when run_once=True. It feels like maybe dependencies in nested indicators are not resolved as I'd hoped(?).
      I thought it might have to do with _minperiod not being carried over properly, but it seems _minperiod for both the signal and signal_copy are both 2 as expected.

      So then I thought, OK, let me override the once method instead of relying on once_via_next like so:

      class Copy(bt.Indicator):
          lines = ('copy',)
          
          def __init__(self):
              self.x = self.datas[0]
          
          def next(self):
              self.lines.copy[0] = self.x[0]
              
          def once(self, start, end):
              print(f'running once: {start},{end}')
              for i in range(start, end):
                  self.lines.copy.array[i] = self.x[i]
      

      And this works... kind of. The signal_copy now has values from signal; however, the signal is shifted by 1. Where signal begins with 1 nan, signal_copy begins with 2. I have a debug statement that prints the start and end arguments outputting:

      running once: 1,2
      running once: 2,1000
      

      This hints at why signal_copy has 2 nans, but (Q2) I'm wondering why once is ran before the minimum period. In the docs I see that:
      once(self, start, end)
      Called when the minimum period has been met. The internal array must be processed between start and end which are zero based from the start of the internal array

      And writing the copy indicator using the __init__ method works as expected...

      class Copy(bt.Indicator):
          lines = ('copy',)
          
          def __init__(self):
              self.x = self.datas[0]
              self.lines.copy = self.x
      

      but of course, I'm actually trying to write something more complex that requires the usage of next.

      Any hints would be much appreciated!

      1 Reply Last reply Reply Quote 0
      • JasonTam
        JasonTam last edited by

        Sorry, meant to post this in general-code-help

        1 Reply Last reply Reply Quote 0
        • A
          ab_trader last edited by

          Looks like if you want to run your indicator in the vectorized mode, you need __init__() and once() methods to be present in the indicator. next() is not processed in the vectorized mode.

          • If my answer helped, hit reputation up arrow at lower right corner of the post.
          • Python Debugging With Pdb
          • New to python and bt - check this out
          1 Reply Last reply Reply Quote 0
          • 1 / 1
          • First post
            Last post
          Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors