tradingview / charting-library-examples

Examples of Charting Library integrations with other libraries, frameworks and data transports
MIT License
1.33k stars 744 forks source link

I got Cannot read properties of undefined (reading 'startsWith') inside react repository #299

Open farzinft opened 2 years ago

farzinft commented 2 years ago

During implementation after getting Charting_library form trading trading everything has been good but I have Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'startsWith') error inside console and I couldn't see the chart as streaming fetching data. `

minhzc commented 1 year ago

I got the same error. Please help!

romfrancois commented 1 year ago

Would you guys have a link we could access or a sample to try to replicate the issue locally?

armanmamyan commented 1 year ago

@romfrancois, @edew Here is the example code which throws the same error.

const history = {};

export default function historyProvider(trades) {
  return {
    history: history,

    getBars: function (symbolInfo, resolution, from, to, first, limit) {
      let split_symbol = symbolInfo.name.split(/[:/]/);
      if (trades?.length) {
        console.log({ trades });
        let bars = trades.map((el) => {
          return {
            time: new Date(el.timeInterval.minute).getTime(),
            low: el.minimum_price,
            high: el.maximum_price,
            open: el.open_price,
            close: el.close_price,
            volume: el.baseAmount,
          };
        });
        if (first) {
          let lastBar = bars[bars.length - 1];
          history[symbolInfo.name] = { lastBar: lastBar };
        }
        return bars;
      } else {
        return [];
      }
    },
  };
} 

import historyProvider from "./historyProvider";

const supportedResolutions = [
  "1",
  "3",
  "5",
  "15",
  "30",
  "60",
  "120",
  "240",
  "D",
];

const config = {
  supported_resolutions: supportedResolutions,
};

export default function Datafeed(data) {
  return {
    onReady: (cb) => {
      console.log("=====onReady running");
      setTimeout(() => cb(config), 0);
    },
    searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {
      console.log("====Search Symbols running");
    },
    resolveSymbol: (
      symbolName,
      onSymbolResolvedCallback,
      onResolveErrorCallback
    ) => {
      // expects a symbolInfo object in response
      console.log("======resolveSymbol running");
      // console.log('resolveSymbol:',{symbolName})
      let split_data = symbolName.split(/[:/]/);
      // console.log({split_data})
      let symbol_stub = {
        name: symbolName,
        description: "",
        session: "24x7",
        ticker: symbolName,
        timezone: "America/New_York",
        exchange: split_data[0],
        full_name: symbolName,
        minmov: 1,
        pricescale: 100000000,
        volume: 1000,
        has_intraday: true,
        intraday_multipliers: ["1", "60"],
        supported_resolution: supportedResolutions,
        volume_precision: 8,
        pro_name: symbolName,
      };

      if (split_data[2].match(/USD|EUR|JPY|AUD|GBP|KRW|CNY/)) {
        symbol_stub.pricescale = 100;
      }

      setTimeout(function () {
        onSymbolResolvedCallback(symbol_stub);
        console.log("Resolving that symbol....", symbol_stub);
      }, 0);

      // onResolveErrorCallback("Not feeling it today");
    },
    getBars: function (
      symbolInfo,
      resolution,
      from,
      to,
      onHistoryCallback,
      onErrorCallback,
      firstDataRequest
    ) {
      console.log("=====getBars running");
      // console.log(`Requesting bars between ${new Date(from * 1000).toISOString()} and ${new Date(to * 1000).toISOString()}`)
      const getBarData = historyProvider(data.dexTrades).getBars(
        symbolInfo,
        resolution,
        from,
        to,
        firstDataRequest
      );
      if (getBarData.length) {
        onHistoryCallback(getBarData, { noData: false });
      } else {
        onHistoryCallback(getBarData, { noData: true });
      }
    },
    subscribeBars: (
      symbolInfo,
      resolution,
      onRealtimeCallback,
      subscribeUID,
      onResetCacheNeededCallback
    ) => {
      console.log("=====subscribeBars runnning");
      // stream.subscribeBars(
      //   symbolInfo,
      //   resolution,
      //   onRealtimeCallback,
      //   subscribeUID,
      //   onResetCacheNeededCallback
      // );
    },
    unsubscribeBars: (subscriberUID) => {
      console.log("=====unsubscribeBars running");

      // stream.unsubscribeBars(subscriberUID);
    },
    calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {
      //optional
      console.log("=====calculateHistoryDepth running");
      // while optional, this makes sure we request 24 hours of minute data at a time
      // CryptoCompare's minute data endpoint will throw an error if we request data beyond 7 days in the past, and return no data
      return resolution < 60
        ? { resolutionBack: "D", intervalBack: "1" }
        : undefined;
    },
    getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {
      //optional
      console.log("=====getMarks running");
    },
    getTimeScaleMarks: (
      symbolInfo,
      startDate,
      endDate,
      onDataCallback,
      resolution
    ) => {
      //optional
      console.log("=====getTimeScaleMarks running");
    },
    getServerTime: (cb) => {
      console.log("=====getServerTime running");
    },
  };
}
import {RefObject, useRef, useState, useEffect} from 'react';
import { Box } from '@mui/material';
import {
    widget
  } from '/public/static/charting_library/';
  import Datafeed from './tweekGraphData'
  import styles from '../index.module.css'

export const TradingGraph = ({data, dexName}) => {
    const [tvWidget, setTvWidget] = useState<IChartingLibraryWidget | null>(null)
    const TVRef = useRef<RefObject<HTMLDivElement>>(null);

    useEffect(() => {
        if(typeof window !== 'undefined' && data?.dexTrades.length > 0) {
            const options = {
                symbol: `${dexName}:${data.dexTrades[0].baseCurrency.symbol}/${data.dexTrades[0].quoteCurrency.symbol}`,
                datafeed: Datafeed(data),
                interval: 'D' ,
                session: '24x7',
                timezone: 'America/New_York',
                container: TVRef.current ,
                library_path: '/static/charting_library/',
                locale: 'en',
                disabled_features: ['left_toolbar'],
                client_id: 'tradingview.com',
                theme: 'Dark',
                user_id: 'public_user_id',
                fullscreen: false,
                autosize: true,
                studiesOverrides: {},
            }
            const tvWidgetInit = new widget(options);
            setTvWidget(tvWidgetInit)

            tvWidgetInit.onChartReady(() => {
                tvWidgetInit.headerReady().then(() => {
                const button = tvWidgetInit.createButton();
                button.setAttribute(
                    'title',
                    'Click to show a notification popup',
                );
                button.classList.add('apply-common-tooltip');
                button.addEventListener('click', () =>
                    tvWidgetInit.showNoticeDialog({
                    title: 'Notification',
                    body: 'TradingView Charting Library API works correctly',
                    callback: () => {
                    },
                    }),
                );
                button.innerHTML = 'Check API';
                });
          });
        }

        return () => {
            if (tvWidget !== null) {
                tvWidget.remove();
              }
        }
    },[data?.dexTrades]);

    return (
        <Box ref={TVRef} className={styles['tv--container']} />
    )

}

And here are the props, that I'm passing to draw the bars:

{
close: "0.00012344146769585802",
high: 0.00012344146769585802,
low: 0.00012344146769585802,
open: "0.00012344146769585802",
time: 1670823300000,
volume:  8.101005429260255
}
armanmamyan commented 1 year ago

@farzinft any updates?

73k05 commented 1 year ago

I'm facing the same issue, is there any update about this?

romfrancois commented 1 year ago

@armanmamyan would you have full logs (by activating debug: true in widget constructor) to share (in a separate file please)?

Second question: it's probably a typo but some of your data have double quotes and others don't.

{ close: "0.00012344146769585802", high: 0.00012344146769585802, low: 0.00012344146769585802, open: "0.00012344146769585802", time: 1670823300000, volume: 8.101005429260255 }

armanmamyan commented 1 year ago

@romfrancois thank you for your quick response. Here are the logs.

Event "panes_order_changed", arguments: []

Symbol resolved: 'QUICKSWAP:NST/WMATIC', SymbolInfo in server response {"name":"QUICKSWAP:NST/WMATIC","description":"","session":"24x7","ticker":"QUICKSWAP:NST/WMATIC","timezone":"America/New_York","exchange":"QUICKSWAP","full_name":"QUICKSWAP:NST/WMATIC","minmov":1,"pricescale":100000000,"volume":1000,"has_intraday":true,"intraday_multipliers":["1","60"],"supported_resolution":["1","3","5","15","30","60","120","240","D"],"volume_precision":8,"pro_name":"QUICKSWAP:NST/WMATIC"}

Symbol info after post-processing: "QUICKSWAP:NST/WMATIC", SymbolInfo {"name":"QUICKSWAP:NST/WMATIC","description":"","session":"24x7","ticker":"QUICKSWAP:NST/WMATIC","timezone":"America/New_York","exchange":"QUICKSWAP","full_name":"QUICKSWAP:NST/WMATIC","minmov":1,"pricescale":100000000,"volume":1000,"has_intraday":true,"intraday_multipliers":["1","60"],"supported_resolution":["1","3","5","15","30","60","120","240","D"],"volume_precision":8,"pro_name":"QUICKSWAP:NST/WMATIC","base_name":["QUICKSWAP:NST/WMATIC"],"legs":["QUICKSWAP:NST/WMATIC"],"data_status":"streaming"}

Event "series_properties_changed", arguments: ["BZz33z"]

Event "symbol", arguments: [{"category":"Symbol","label":"QUICKSWAP:NST/WMATIC","value":""}]

Event "symbol_type", arguments: [{"category":"Symbol Type","value":""}]

Event "study_event", arguments: ["uNVnNK","price_scale_changed"]

FEED [QUICKSWAP:NST/WMATIC|1D]: Processing pending subscribers, count=2

FEED [QUICKSWAP:NST/WMATIC|1D]: Leftmost subscriber requires 329 bars prior 2022-12-16T00:00:00.000Z

FEED [QUICKSWAP:NST/WMATIC|1D]: Requesting data: [2022-01-21T00:00:00.000Z ... 2022-12-16T00:00:00.000Z, 329 bars]

FEED [QUICKSWAP:NST/WMATIC|1D]: Processing pending subscribers, count=2

FEED [QUICKSWAP:NST/WMATIC|1D]: Return error: [object Object],[object Object],[object Object],[object Object]

Series error: [object Object],[object Object],[object Object],[object Object]

library.1fbbf36d35f97ccfbd00.js:629 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'startsWith')

armanmamyan commented 1 year ago

Double quotes fixed, still no result

romfrancois commented 1 year ago

FEED [QUICKSWAP:NST/WMATIC|1D]: Return error: [object Object],[object Object],[object Object],[object Object] Series error: [object Object],[object Object],[object Object],[object Object]

You can see here that the library doesn't receive values but object. That's most likely the issue.

armanmamyan commented 1 year ago

But where can be a problem? Here is bars data that I'm passing to Datafeed. Am I missing some properties ?

image
armanmamyan commented 1 year ago

@romfrancois can you share an actual example of TV with custom data for next or react js, please ?

romfrancois commented 1 year ago

But where can be a problem? Here is bars data that I'm passing to Datafeed. Am I missing some properties ? image

Where is that screenshot coming from? Is it what the datafeed returns ?

@romfrancois can you share an actual example of TV with custom data for next or react js, please ?

The datafeed is independent from the framework that's why in the documentation we refer it as JS-API.

armanmamyan commented 1 year ago

This is the data that I'm creating from getBars method for custom Datafeed