Backtrader Community

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    1. Home
    2. Bo Vargas
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/
    • Profile
    • Following 0
    • Followers 1
    • Topics 5
    • Posts 13
    • Best 2
    • Controversial 0
    • Groups 0

    Bo Vargas

    @Bo Vargas

    2
    Reputation
    32
    Profile views
    13
    Posts
    1
    Followers
    0
    Following
    Joined Last Online

    Bo Vargas Unfollow Follow

    Best posts made by Bo Vargas

    • RE: Renko Indicator to address existing issues

      Here's the hack I implemented for now. It's based on Pyrenko code I found on Github. In my next(), after I pass the data, I access the brick to generate my signal.

      import numpy as np
      import matplotlib.pyplot as plt
      import matplotlib.patches as patches
      
      '''
              Formation of New Renko Bricks
              During a trend continuation, a new brick of the same color is added to the chart when the Renko Box Size value, 
              plus one tick, is met. A reversal in the Renko trend and the formation of a different color brick is formed 
              when price surpasses the Renko Box Size parameter by twice the size plus one tick.
              '''
      
      
      class Renko:
          def __init__(self, HLC_history=None, auto=False, brick_size=1.0):
              self.source_prices = []
              self.renko_prices = []
              self.renko_directions = []
      
              if auto:
                  self.brick_size = self.__get_optimal_brick_size(HLC_history.iloc[:, [0, 1, 2]])
              else:
                  self.brick_size = brick_size
      
          def __renko_rule(self, close):
              # Get the gap between two prices
              if self.brick_size == 0:
                  gap_div = 0
              else:
                  gap_div = int(float(close - self.renko_prices[-1]) / self.brick_size)
      
              is_new_brick = False
              start_brick = 0
              num_new_bars = 0
      
              # When we have some gap in prices
              if gap_div != 0:
                  # Forward any direction (up or down)
                  if (gap_div > 0 and (self.renko_directions[-1] > 0 or self.renko_directions[-1] == 0)) or (gap_div < 0 and (self.renko_directions[-1] < 0 or self.renko_directions[-1] == 0)):
                      num_new_bars = gap_div
                      is_new_brick = True
                      start_brick = 0
                  # Backward direction (up -> down or down -> up)
                  elif np.abs(gap_div) >= 2:  # Should be double gap at least
                      num_new_bars = gap_div
                      num_new_bars -= np.sign(gap_div)
                      start_brick = 2
                      is_new_brick = True
                      self.renko_prices.append(self.renko_prices[-1] + 2 * self.brick_size * np.sign(gap_div))
                      self.renko_directions.append(np.sign(gap_div))
                  #else:
                  #num_new_bars = 0
      
                  if is_new_brick:
                      # Add each brick
                      for d in range(start_brick, np.abs(gap_div)):
                          self.renko_prices.append(self.renko_prices[-1] + self.brick_size * np.sign(gap_div))
                          self.renko_directions.append(np.sign(gap_div))
      
              return num_new_bars
      
          # Getting renko on history
          def build_history(self, prices):
              if len(prices) > 0:
                  # Init by start values
                  self.source_prices = prices
                  self.renko_prices.append(prices.iloc[0])
                  self.renko_directions.append(0)
      
                  # For each price in history
                  for p in self.source_prices[1:]:
                      self.__renko_rule(p)
      
              return len(self.renko_prices)
      
          # Getting next renko value for last price
          def do_next(self, close):
              if len(self.renko_prices) == 0:
                  self.source_prices.append(close)
                  self.renko_prices.append(close)
                  self.renko_directions.append(0)
                  return 1
              else:
                  self.source_prices.append(close)
                  return self.__renko_rule(close)
      
          # Simple method to get optimal brick size based on ATR
          @staticmethod
          def __get_optimal_brick_size(HLC_history, atr_timeperiod=14):
              brick_size = 0.0
      
              # If we have enough of data
              if HLC_history.shape[0] > atr_timeperiod:
                  brick_size = np.median(talib.ATR(high=np.double(HLC_history.iloc[:, 0]),
                                                   low=np.double(HLC_history.iloc[:, 1]),
                                                   close=np.double(HLC_history.iloc[:, 2]),
                                                   timeperiod=atr_timeperiod)[atr_timeperiod:])
      
              return brick_size
      
          def evaluate(self, method='simple'):
              balance = 0
              sign_changes = 0
              price_ratio = len(self.source_prices) / len(self.renko_prices)
      
              if method == 'simple':
                  for i in range(2, len(self.renko_directions)):
                      if self.renko_directions[i] == self.renko_directions[i - 1]:
                          balance = balance + 1
                      else:
                          balance = balance - 2
                          sign_changes = sign_changes + 1
      
                  if sign_changes == 0:
                      sign_changes = 1
      
                  score = balance / sign_changes
                  if score >= 0 and price_ratio >= 1:
                      score = np.log(score + 1) * np.log(price_ratio)
                  else:
                      score = -1.0
      
                  return {'balance': balance, 'sign_changes:': sign_changes,
                          'price_ratio': price_ratio, 'score': score}
      
          def get_renko_prices(self):
              return self.renko_prices
      
          def get_renko_directions(self):
              return self.renko_directions
      
          def plot_renko(self, col_up='g', col_down='r'):
              fig, ax = plt.subplots(1, figsize=(20, 10))
              ax.set_title('Renko chart')
              ax.set_xlabel('Renko bars')
              ax.set_ylabel('Price')
      
              # Calculate the limits of axes
              ax.set_xlim(0.0,
                          len(self.renko_prices) + 1.0)
              ax.set_ylim(np.min(self.renko_prices) - 3.0 * self.brick_size,
                          np.max(self.renko_prices) + 3.0 * self.brick_size)
      
              # Plot each renko bar
              for i in range(1, len(self.renko_prices)):
                  # Set basic params for patch rectangle
                  col = col_up if self.renko_directions[i] == 1 else col_down
                  x = i
                  y = self.renko_prices[i] - self.brick_size if self.renko_directions[i] == 1 else self.renko_prices[i]
                  height = self.brick_size
      
                  # Draw bar with params
                  ax.add_patch(
                      patches.Rectangle(
                          (x, y),   # (x,y)
                          1.0,     # width
                          self.brick_size,  # height
                          facecolor=col
                      )
                  )
      
              plt.show()
      
      posted in Indicators/Strategies/Analyzers
      Bo Vargas
      Bo Vargas
    • RE: StopTrailLimit throwing issue to specify one value

      Yes. It looks like TWS automatically sets the offset for you in the Global Configuration. Another item I notice is StopTrailLimits need to explicitly have the RTH=True if you want the trail to work after hours.

      posted in General Code/Help
      Bo Vargas
      Bo Vargas

    Latest posts made by Bo Vargas

    • RE: Renko Indicator to address existing issues

      Here's the hack I implemented for now. It's based on Pyrenko code I found on Github. In my next(), after I pass the data, I access the brick to generate my signal.

      import numpy as np
      import matplotlib.pyplot as plt
      import matplotlib.patches as patches
      
      '''
              Formation of New Renko Bricks
              During a trend continuation, a new brick of the same color is added to the chart when the Renko Box Size value, 
              plus one tick, is met. A reversal in the Renko trend and the formation of a different color brick is formed 
              when price surpasses the Renko Box Size parameter by twice the size plus one tick.
              '''
      
      
      class Renko:
          def __init__(self, HLC_history=None, auto=False, brick_size=1.0):
              self.source_prices = []
              self.renko_prices = []
              self.renko_directions = []
      
              if auto:
                  self.brick_size = self.__get_optimal_brick_size(HLC_history.iloc[:, [0, 1, 2]])
              else:
                  self.brick_size = brick_size
      
          def __renko_rule(self, close):
              # Get the gap between two prices
              if self.brick_size == 0:
                  gap_div = 0
              else:
                  gap_div = int(float(close - self.renko_prices[-1]) / self.brick_size)
      
              is_new_brick = False
              start_brick = 0
              num_new_bars = 0
      
              # When we have some gap in prices
              if gap_div != 0:
                  # Forward any direction (up or down)
                  if (gap_div > 0 and (self.renko_directions[-1] > 0 or self.renko_directions[-1] == 0)) or (gap_div < 0 and (self.renko_directions[-1] < 0 or self.renko_directions[-1] == 0)):
                      num_new_bars = gap_div
                      is_new_brick = True
                      start_brick = 0
                  # Backward direction (up -> down or down -> up)
                  elif np.abs(gap_div) >= 2:  # Should be double gap at least
                      num_new_bars = gap_div
                      num_new_bars -= np.sign(gap_div)
                      start_brick = 2
                      is_new_brick = True
                      self.renko_prices.append(self.renko_prices[-1] + 2 * self.brick_size * np.sign(gap_div))
                      self.renko_directions.append(np.sign(gap_div))
                  #else:
                  #num_new_bars = 0
      
                  if is_new_brick:
                      # Add each brick
                      for d in range(start_brick, np.abs(gap_div)):
                          self.renko_prices.append(self.renko_prices[-1] + self.brick_size * np.sign(gap_div))
                          self.renko_directions.append(np.sign(gap_div))
      
              return num_new_bars
      
          # Getting renko on history
          def build_history(self, prices):
              if len(prices) > 0:
                  # Init by start values
                  self.source_prices = prices
                  self.renko_prices.append(prices.iloc[0])
                  self.renko_directions.append(0)
      
                  # For each price in history
                  for p in self.source_prices[1:]:
                      self.__renko_rule(p)
      
              return len(self.renko_prices)
      
          # Getting next renko value for last price
          def do_next(self, close):
              if len(self.renko_prices) == 0:
                  self.source_prices.append(close)
                  self.renko_prices.append(close)
                  self.renko_directions.append(0)
                  return 1
              else:
                  self.source_prices.append(close)
                  return self.__renko_rule(close)
      
          # Simple method to get optimal brick size based on ATR
          @staticmethod
          def __get_optimal_brick_size(HLC_history, atr_timeperiod=14):
              brick_size = 0.0
      
              # If we have enough of data
              if HLC_history.shape[0] > atr_timeperiod:
                  brick_size = np.median(talib.ATR(high=np.double(HLC_history.iloc[:, 0]),
                                                   low=np.double(HLC_history.iloc[:, 1]),
                                                   close=np.double(HLC_history.iloc[:, 2]),
                                                   timeperiod=atr_timeperiod)[atr_timeperiod:])
      
              return brick_size
      
          def evaluate(self, method='simple'):
              balance = 0
              sign_changes = 0
              price_ratio = len(self.source_prices) / len(self.renko_prices)
      
              if method == 'simple':
                  for i in range(2, len(self.renko_directions)):
                      if self.renko_directions[i] == self.renko_directions[i - 1]:
                          balance = balance + 1
                      else:
                          balance = balance - 2
                          sign_changes = sign_changes + 1
      
                  if sign_changes == 0:
                      sign_changes = 1
      
                  score = balance / sign_changes
                  if score >= 0 and price_ratio >= 1:
                      score = np.log(score + 1) * np.log(price_ratio)
                  else:
                      score = -1.0
      
                  return {'balance': balance, 'sign_changes:': sign_changes,
                          'price_ratio': price_ratio, 'score': score}
      
          def get_renko_prices(self):
              return self.renko_prices
      
          def get_renko_directions(self):
              return self.renko_directions
      
          def plot_renko(self, col_up='g', col_down='r'):
              fig, ax = plt.subplots(1, figsize=(20, 10))
              ax.set_title('Renko chart')
              ax.set_xlabel('Renko bars')
              ax.set_ylabel('Price')
      
              # Calculate the limits of axes
              ax.set_xlim(0.0,
                          len(self.renko_prices) + 1.0)
              ax.set_ylim(np.min(self.renko_prices) - 3.0 * self.brick_size,
                          np.max(self.renko_prices) + 3.0 * self.brick_size)
      
              # Plot each renko bar
              for i in range(1, len(self.renko_prices)):
                  # Set basic params for patch rectangle
                  col = col_up if self.renko_directions[i] == 1 else col_down
                  x = i
                  y = self.renko_prices[i] - self.brick_size if self.renko_directions[i] == 1 else self.renko_prices[i]
                  height = self.brick_size
      
                  # Draw bar with params
                  ax.add_patch(
                      patches.Rectangle(
                          (x, y),   # (x,y)
                          1.0,     # width
                          self.brick_size,  # height
                          facecolor=col
                      )
                  )
      
              plt.show()
      
      posted in Indicators/Strategies/Analyzers
      Bo Vargas
      Bo Vargas
    • RE: ATR_TrailingStop Indicator

      @Jayden-Clark said in ATR_TrailingStop Indicator:

      https://github.com/jantarktic/ATR_Trailing_Stop_Indicator/blob/master/btind ATR_TS_Long.ipynb

      Not able to view your Notebook on Github.

      posted in Indicators/Strategies/Analyzers
      Bo Vargas
      Bo Vargas
    • RE: [FIXED] Ichimoku: Unable to get Future cloud

      @Euler-Sousa Is this the only solution you have found while using live data (no preloaded)? Are you just placing this inside the next() function and computing the values each time around?

      posted in Indicators/Strategies/Analyzers
      Bo Vargas
      Bo Vargas
    • RE: StopTrailLimit throwing issue to specify one value

      Yes. It looks like TWS automatically sets the offset for you in the Global Configuration. Another item I notice is StopTrailLimits need to explicitly have the RTH=True if you want the trail to work after hours.

      posted in General Code/Help
      Bo Vargas
      Bo Vargas
    • RE: StopTrailLimit throwing issue to specify one value

      That is the error. "You must specify one value: Limit Price or Limit Price Offset Value."

      posted in General Code/Help
      Bo Vargas
      Bo Vargas
    • StopTrailLimit throwing issue to specify one value

      I have the following code.

      p1 = close
      tp = p1 - (10 * atr)
      sp = p1 + (4 * atr)
      trail = (3 * atr)
      # Parent
                  self.order = self.sell(exectype=bt.Order.Limit,
                                         size=size,
                                         price=p1,
                                         tif='GTD',
                                         goodTillDate=gtd.strftime('%Y%m%d %H:%M:%S GMT'),
                                         account=self.account,
                                         transmit=False)
      
                  logging.info('{}: Oref {} / Sell at {}'.format(self.datetime.date(), self.order.ref, p1))
      
                  # Take Profit
                  oT = self.buy(exectype=bt.Order.Limit,
                                price=tp,
                                # valid=valid3,
                                account=self.account,
                                parent=self.order,
                                size=self.order.size,
                                transmit=False)
      
                  logging.info('{}: Oref {} / Buy TP Limit at {}'.format(self.datetime.date(), oT.ref, tp))
      
                  # Stop Trail Limit
                  o3 = self.buy(exectype=bt.Order.StopTrailLimit,
                                price=p1,
                                plimit=sp,
                                trailamount=trail,
                                account=self.account,
                                parent=self.order,
                                size=self.order.size,
                                transmit=True)
      

      When I execute. I get an error saying "You must specify one value: Limit Price or Limit Price Offset Value.

      This is on IBKR. I do not specify the limit price offset. Does anyone see the issue?

      posted in General Code/Help
      Bo Vargas
      Bo Vargas
    • Stop-Loss order is getting value from Parent Order even if sized passed in

      I have the following order with a stop-loss attached. The problem is the Buy Limit order will be reverse the position from Short -> Long; But I need the Stop-Loss size should be for the balance.

      Example
      Current Position -2 (short)
      Buy 4 (long)
      New Position 2 (long)
      StopLoss Order is 4. I'm passing in the size 2. But somehow this is getting overwritten.

      Does anyone know how to fix this? I don't want to submit an order to close the existing position and then open a new order.

      self.order = self.buy(exectype=bt.Order.Limit,
                                        size=size,
                                        price=p1,
                                        tif='GTD',
                                        goodTillDate=gtd.strftime('%Y%m%d %H:%M:%S GMT'),
                                        account=self.account,
                                        transmit=False)
      
      o2 = self.sell(exectype=bt.Order.Stop,
                                 price=sp,
                                 valid=valid2,
                                 account=self.account,
                                 parent=self.order,
                                 size=stop_size,  # We want the stop loss to be half our position; meaning don't reverse
                                 transmit=True)
      
                  logging.info('{}: Oref {} / Sell Stop at {}'.format(self.datetime.date(), o2.ref, sp))
      
      posted in General Code/Help execution order
      Bo Vargas
      Bo Vargas
    • RE: Renko Indicator to address existing issues

      A new Renko class was created and I stopped using the RenkoFilter. The new Renko class didn't inherit from bt.Indicator as this open up a bunch of other issues. If you need it please fill free to ping me. I'll open it up once I get a few more unit tests around it.

      posted in Indicators/Strategies/Analyzers
      Bo Vargas
      Bo Vargas
    • RE: Bracket Order Stop and Limit Orders Not Canceled on Position Reversal

      I found a solution to the problem.

      1. You need to group the order in the parent-child relationship (this open up other issues, but another ticket for this)
      2. Using the ib_insync library to get API access to IBKR directly. Call the reqGlobalCancel(). IBKR has a security feature where the clientID who opens the order must cancel the order. The reqGlobalCancel function gets around that.
      posted in General Discussion
      Bo Vargas
      Bo Vargas
    • Renko Indicator to address existing issues

      I'm creating a new Renko Indicator to address the issues (i.e. not based on the actual price movement, atr) ...
      https://community.backtrader.com/topic/511/renko-bricks/17
      https://community.backtrader.com/topic/1694/filter-on-replaydata/4.

      class Renko(bt.Indicator):
          '''
          During a trend continuation, a new brick of the same color is added to the chart when the Renko Brick Size value,
          plus one tick is met. A reversal in the Renko trend and the formation of a different color brick is formed
          when price surpasses the Renko Brick Size parameter by twice the size plus one tick.
      
          Formula:
              atr  = SmoothedMovingAverage(TrueRange, period)
              open = open
              high = (close + size)
              low  = (close - size)
              close = close
              direction = Sum(up) - Sum(down) Notes: Neutral = 0, Up = 1, Down = -1
      
          See also:
              https://school.stockcharts.com/doku.php?id=chart_analysis:renko
          '''
      
          lines = ('open', 'high', 'low', 'close', 'volume', 'direction')
      
          '''
              Fixed = Fixed Brick Size, False, means ATR
          '''
          params = (('fixed', True), ('brick_size', 0.0001), ('period', 14), ('field', 'close'), ('movav', MovAv.Smoothed))
      
          plotinfo = dict(subplot=False)
      
          def __init__(self):
              o = self.data.open
              h = self.data.high
              l = self.data.low
              c = self.data.close
              v = self.data.volume
      
              up_count = {}
              down_count = {}
             
              # Due we need to keep track of all Bricks with OHLCV to push to Strategy after time resolution?
              total_bricks = {}
      
              (brick_lower_limit, brick_upper_limit) = (c - self.p.brick_size, c + self.p.brick_size)
      
              self.lines.atr = ATR(self.data, period=self.p.period, movav=self.p.movav)
              self.lines.close = c
              self.lines.open = o
              self.lines.high = c + self.p.brick_size
              self.lines.low = c - self.p.brick_size
              self.lines.volume = v
              self.lines.direction = sum(self.up_count) - sum(self.down_count)
      
              super(Renko, self).__init__()
      
          def prenext(self):
              print('prenext:: current period:', len(self))
      
          def nextstart(self):
              print('nextstart:: current period:', len(self))
              # emulate default behavior ... call next
              self.next()
      
          def next(self):
              print('next:: current period:', len(self))
      
          def _plotlabel(self):
              plabels = [self.p.period]
              plabels += [self.p.movav] * self.p.notdefault('movav')
              return plabels
      

      Test Cases

      1. 1-minute resolution, fixed size = 1, direction=1 (upward), price movement= 3 => Expectation = 3 green (up) bricks
      2. 1-minute resolution, fixed size = 1, direction=1, price movement = -2 => Expectation = 0 bricks; not enough price movement when changing direction
      3. 1-minute resolution, fixed size = 1, direction=1, price movement = -2.1 => Expectation = 2 red (down) bricks

      I need the Strategy to expose all three bricks in the Next(self) would need access to all three bricks given that the resolution is 1 minute.

      Is this the correct implementation strategy? What will be the issues around time resolutions?

      I had thought about just sampling at a lower resolution, which would capture the price movements and push out the bars. However, we would still need a custom Renko indicator to address the up/down logic.

      posted in Indicators/Strategies/Analyzers
      Bo Vargas
      Bo Vargas