code: def kdj(
      high=None,
      low=None,
      close=None,
      length=None,
      signal=None,
      offset=None,
      **kwargs,
  ):
      """Indicator: KDJ (KDJ)"""
      # Validate Arguments
      length = int(length) if length and length > 0 else 9
      signal = int(signal) if signal and signal > 0 else 3
      _length = max(length, signal)
      high = verify_series(high, _length)
      low = verify_series(low, _length)
      close = verify_series(close, _length)
      offset = get_offset(offset)
  
      if high is None or low is None or close is None:
          return
  
      # Calculate Result
      highest_high = high.rolling(length).max()
      lowest_low = low.rolling(length).min()
  
      fastk = (
          100
          * (close - lowest_low)
          / non_zero_range(highest_high, lowest_low)
      )
  
      k = rma(fastk, length=signal)
      d = rma(k, length=signal)
      j = 3 * k - 2 * d
  
      # Offset
      if offset != 0:
          k = k.shift(offset)
          d = d.shift(offset)
          j = j.shift(offset)
  
      # Handle fills
      if "fillna" in kwargs:
          k.fillna(kwargs["fillna"], inplace=True)
          d.fillna(kwargs["fillna"], inplace=True)
          j.fillna(kwargs["fillna"], inplace=True)
      if "fill_method" in kwargs:
          k.fillna(method=kwargs["fill_method"], inplace=True)
          d.fillna(method=kwargs["fill_method"], inplace=True)
          j.fillna(method=kwargs["fill_method"], inplace=True)
  
      # Name and Categorize it
      _params = f"_{length}_{signal}"
      k.name = f"K{_params}"
      d.name = f"D{_params}"
      j.name = f"J{_params}"
      k.category = d.category = j.category = "momentum"
  
      # Prepare DataFrame to return
      kdjdf = DataFrame({k.name: k, d.name: d, j.name: j})
      kdjdf.name = f"KDJ{_params}"
      kdjdf.category = "momentum"
  
      return kdjdf
  
label_desc: Use image node_id 1 for calling a global function with example usage: kdj(high, low, close, length, signal, offset) and returns: kdjdf