pythonpandaschartslightweight-charts

Error occurred in update_chart_lines: Can only use .str accessor with string values


I am struggling to get the .update to work on my line objects. I am pretty sure I have the correct format for the pd.Series and have followed the docs to the best of my ability.

terminal output states:

Received avg_series_high: 2024-03-05 3693.797625 dtype: float64

I then receive the following error:

Error occurred in update_chart_lines: Can only use .str accessor with string values!

I have never seen this error before whilst use pd and all examples of this error i have found online seem to indicate that the name of the series may not automatically be being treated as a string?

Any help or pointers would be greatly appreciated.

Code example

async def update_chart_lines(self, avg_line_high, avg_line_low, avg_line_high2, avg_line_low2, queue):
        print("Starting update_chart_lines function")
        avg_data = None

        while True:
            try:
                avg_data = await queue.get()

                if avg_data is not None and 'date' in avg_data:

                    avg_data['date'] = pd.to_datetime(avg_data['date'], unit='ms')
                    # Create a pandas Series for each line
                    avg_series_high_data = pd.Series([avg_data['avg_last_candles_high']], index=[avg_data['date']])
                    avg_series_low_data = pd.Series([avg_data['avg_last_candles_low']], index=[avg_data['date']])
                    avg_series_high2_data = pd.Series([avg_data['avg_last_candles_high2']], index=[avg_data['date']])
                    avg_series_low2_data = pd.Series([avg_data['avg_last_candles_low2']], index=[avg_data['date']])

                    print(f"Received avg_series_high: {avg_series_high_data}")

                    # Update each line with the corresponding pandas Series
                    avg_line_high.update(avg_series_high_data)
                    avg_line_low.update(avg_series_low_data)
                    avg_line_high2.update(avg_series_high2_data)
                    avg_line_low2.update(avg_series_low2_data)
                else:
                    print("No avg candle ticks to process.")
                    continue
            except Exception as e:
                print(f"Error occurred in update_chart_lines: {e}")

This generates a dataframe continuously and sends it to update_chart_lines:

async def last_candles_cont(df, n, timeframe, queue):

  timeframe = timeframe

  """ print(f"Calculating average of last {n} candles for {timeframe} timeframe") """

  multipliers = {
    '1d': 1.025,
    '4h': 1.015,
    '1h': 1.01,
    '15m': 1.005,
    '5m': 1.001,
    '1m': 1.00
  }

  while True:
    try:  

      avg_data = None
          
      tick= await queue.get()

      print(f"Received tick: {tick}")

      tick_df = pd.DataFrame(tick, index=[0])

      df = pd.concat([df, tick_df], ignore_index=True)

      """ df['diff'] = df['close'] - df['close'].shift(1)
      print (df['diff'])

      # Calculate the rate of change as a percentage
      df['roc'] = df['diff'] / df['close'].shift(1) * 100
      print (df['roc']) """

      multiplier = multipliers[timeframe]

      df['avg_last_candles_high'] = (df['high']*multiplier).shift(1).rolling(n).mean()
      df['avg_last_candles_low'] = (df['low']/multiplier).shift(1).rolling(n).mean()

      df['avg_last_candles_high2'] = (df['high']*multiplier).rolling(n).mean()
      df['avg_last_candles_low2'] = (df['low']/multiplier).rolling(n).mean()

      avg_data = pd.DataFrame({
              'date': (df['date']),
              'avg_last_candles_high': df['avg_last_candles_high'],
              'avg_last_candles_low': df['avg_last_candles_low'],
              'avg_last_candles_high2': df['avg_last_candles_high2'],
              'avg_last_candles_low2': df['avg_last_candles_low2'],
          }).dropna()
      
      current_candle = avg_data.tail(1).squeeze()
      print(f"Current candle: {current_candle}")
      # Put the current candle into the queue
      await queue.put(current_candle)

      await asyncio.sleep(1)

      """ return avg_data """

    except Exception as e:
      print(f"Error in avg candle function: {e}")
      return pd.DataFrame()  # Return an empty DataFrame in case of error

Solution

  • I don't have experience with lightweight-charts, but your problem seems related to the data you're passing to .update.

    Problem

    You're creating pandas series like this:

    avg_series_high_data = pd.Series([avg_data['avg_last_candles_high']], index=[avg_data['date']])
    

    Which effectively creates a series with dates as index and corresponding values for each date. Something similar to this:

    2024-03-11    1
    2024-03-12    2
    2024-03-13    3
    2024-03-14    4
    

    The issue is lightweight-charts is expecting pandas series in a different format, i.e., a series for each row of the dataframe you're plotting, with values for an index 'date', another index 'some_value'... and so on. So something more along the lines of:

    date      2016-12-28 00:00:00
    open                  14.6667
    high                    14.92
    low                     14.48
    close                  14.616
    volume             48715005.0
    

    Error message

    The error you're seeing happens because lightweight-charts is expecting date or time to be in the series index. If it isn't, it assumes these words may be in uppercase and calls .str.lower() on it.

    In the series you're passing it, the index values are of type datetime, so it raises the error:

    Error occurred in update_chart_lines: Can only use .str accessor with string values!

    What to do

    You need to create pandas series in the format suggested above. I don't have access to your data, so it's hard to recommend anything more concrete. Since it's a line, I assume each series would look something like this:

    date      2016-12-28 00:00:00
    open                  14.6667