# Integrating Tradingview’s Technical Analysis Charts with Bitquery GraphQL API using VueJS

**URL:** https://community.bitquery.io/t/integrating-tradingview-s-technical-analysis-charts-with-bitquery-graphql-api-using-vuejs/343
**Category:** GraphQL Tutorials
**Tags:** tradingview, vuejs
**Created:** [July 22, 2021, 8:54am UTC](https://community.bitquery.io/t/integrating-tradingview-s-technical-analysis-charts-with-bitquery-graphql-api-using-vuejs/343 "2021-07-22T08:54:15Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![sayon](https://avatars.discourse-cdn.com/v4/letter/s/b2d939/32.png) [@sayon](https://community.bitquery.io/u/sayon)
#### Post date: [July 22, 2021, 8:54am UTC](https://community.bitquery.io/t/integrating-tradingview-s-technical-analysis-charts-with-bitquery-graphql-api-using-vuejs/343/1 "2021-07-22T08:54:15Z")

</div>

This article focuses on integrating **Tradingview’s Technical Analysis charts** with **Bitquery’s GraphQL API** in a **VueJS** web application and using the **Moving Average Exponential indicator** within the integrated chart to get vital insights of the data. In this article, we will be integrating the Technical Analysis Charts with VueJS and adding an Moving Average Exponential indicator later.

**Technical Analysis Charts is a powerful, scalable and informative charting library provided by Tradingview only to regulated brokers and public project websites.**

 ![Screenshot (181)](https://us1.discourse-cdn.com/flex016/uploads/bitquery/original/1X/b983981d39dbae9af5ade1bbece8f5d6ebb2a34a.png)

The above is an example of Tradingview’s Technical Analysis chart. Technical Analysis charts can be a great help to investors and traders for all purposes. Now, on that note Bitquery’s GraphQL API gets easily integrated even with Technical Analysis charts. One can obtain data through running a GraphQL query through Bitquery GraphQL API and can visualize the data on the Technical Analysis Charts.

> **Integrating Bitquery GraphQL API with Tradingview’s Technical Analysis Chart**

Before we can move on to the complex stuff, you need to make sure that you have  
the access to the charting library code in github. If you are new to Tradingview’s Technical Analysis charts, please go through this link **[Getting Access to Technical Analysis Charts from Tradingview - Google Docs](https://docs.google.com/document/d/1KBE-Zyak_Intaj8eV4UWj2OWZAlkGuVnCeIvfcnK3hQ/edit?usp=sharing)** which guides you through the process of obtaining access to the charting library from Tradingview.

> **Installing Dependencies**

Installing Axios for making calls to Bitquery GraphQL API

```auto
npm install axios

```

Installing Vue CLI to start off our web application

```auto
npm install -g @vue/cli

```

Alas! Initiating our VueJS application

```auto
vue create Tradingview-three-VueJS

```

> **Copying necessary files in the project folder**

After getting the access to the charting library, you need to copy two folders from [Tradingview Charting Library Github](https://github.com/tradingview/charting_library), **charting\_library** and **datafeed** into the **./src** folder of your VueJS project and in the **./public** folder as well.

 ![Screenshot (183)](https://us1.discourse-cdn.com/flex016/uploads/bitquery/original/1X/5922360f5eb424495578b8e9cb9516c1d633ad0f.png)

> **Adding a DOM container**

You need to have some DOM container that will be used to display the chart. In the HTML file **index.html** in your project’s **./public** folder and add the following code

```auto
<body style="background-color: #171717;">
    <header style="background-color: #171717;;">
        <h1 style="color: white; text-align: center; font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', sans-serif;">Bitquery & Tradingview Integration</h1>
    </header>
    <div id="app"></div>
</body>

```

In the above code the `<div id='app'>` tag acts as a container to display the chart.

> **Setting components**

In the **./src** folder, make a separate folder named **./components** to keep all the components used in this project separately so it’s easy for us to identify them later on. We will then make a **./TVChartContainer/Bitquery.js** file inside the **./components** folder. In this particular VueJS web application, we have made a separate folder named **./api** to house the **index.js**.

> **Bitquery.js**

In this file, we’ll be initializing the Bitquery GraphQL API’s endpoint as shown below.

```auto
export const endpoint = 'https://graphql.bitquery.io';

```

> **.api/index.js**

This file will create a Charting Library Widget. The Charting Library is used to display financial data, but it doesn’t contain any data itself. Whatever you have, a web API, a database or a CSV file, you can display your data in the Charting Library. **Datafeed** is an Object you supply to the **TradingView Widget**. It has a set of methods like **“getBars”** or **“resolveSymbol”** that are called by the Charting Library in certain cases. The **datafeed** returns results using callback functions.

In the first line of the datafeed.js, we need to **import Axios** and in the second line we will reference the endpoint created in **./TVChartContainer/Bitquery**.

We will then set the resolution of the charts. In this example we are allowing the options of 1m, 5m, 15m, 30m, 60m, 1D, 1W, and 1M. The code below explains the above.

```auto
import axios from 'axios';
import * as Bitquery from './../TVChartContainer/Bitquery';

const configurationData = {
    supported_resolutions: ['1','5','15','30', '60','1D', '1W', '1M']
};

```

_onReady_  
We’ll then start with initializing the **onReady method**. onReady is used by the charting library to get a configuration of your datafeed (eg: supported resolutions, exchanges and so on). This is the first method in the export default section.

```auto
export default(baseCurrency) => ({
    onReady: (callback) => {
        setTimeout(() => callback(configurationData));
    },

```

_resolveSymbol_  
This method is used by the library to retrieve information about a specific symbol (exchange, price scale, full symbol etc.). It is an asynchronous function which takes 3 arguments/parameters; symbolName, onSymbolResolvedCallback & onResolveErrorCallback.

Then, we would use Axios to make a **POST** request to **Bitquery GraphQL API** inside the resolveSymbol method. We will reference the **endpoint** from **Bitquery.js** file made earlier and put up our GraphQL query in the **query** field of the API call method.

Remember to setup `mode: 'cors',` in order to avoid ‘CORS’ error while compilation of the code.

```auto
 resolveSymbol: async (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) =>{

        const response = await axios.post(
            Bitquery.endpoint, {
                query: `
                        {
                          ethereum(network: bsc) {
                            dexTrades(
                              options: {desc: ["block.height", "transaction.index"], limit: 1}
                              exchangeAddress: {is: "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73"}
                              baseCurrency: {is: "${baseCurrency}"}
                              quoteCurrency: {is: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c"}
                            ) 
                            {
                              block {
                                height
                                timestamp {
                                  time(format: "%Y-%m-%d %H:%M:%S") 
                                }
                              }
                              transaction {
                                index
                              }
                              baseCurrency {
                                name
                                symbol
                                decimals
                              }
                              quotePrice
                            }
                          }
                        }
                        `,
                variables: {
                    "tokenAddress": symbolName
                },
                mode: 'cors',
            }, {
                headers: {
                    "Content-Type": "application/json",
                    "X-API-KEY": "YOUR UNIQUE API KEY"
                }
            }
        );

        const coin = response.data.data.ethereum.dexTrades[0].baseCurrency;

        if(!coin){
            onResolveErrorCallback();
        }else{
            const symbol = {
                ticker: symbolName,
                name: `${coin.symbol}/BNB`,
                session: '24x7',
                timezone: 'Etc/UTC',
                minmov: 1,
                pricescale: 10000000,
                has_intraday: true,
                intraday_multipliers: ['1', '5', '15', '30', '60'],
                has_empty_bars: true,
                has_weekly_and_monthly: false,
                supported_resolutions: configurationData.supported_resolutions,
                volume_precision: 1,
                data_status: 'streaming',
            }
            onSymbolResolvedCallback(symbol)
        }
    },

```

If you are not familiar with how to generate your unique API key through Bitquery GraphQL API, **[Getting your Bitquery API key](https://bitquery.io/blog/graphql-with-python-javascript-and-ruby#Getting_API_Key)** is a must read. After the POST request is successful, we’ll store the value from the API in a variable ‘coin’ as shown above. If the API call is succesful and the value of ‘coin’ is not null then you need to set **data\_status** attribute’s value to **‘streaming’** as shown in the above.

**Additional configuration of the resolveSymbol could be found in the documentation of the charting\_library**

_getBars_  
Our next step would be to implement the **getBars method**. This method is used by the Charting Library to get historical data for our symbol. It basically calls the **OHLC data** and formats the return data for the charts to be able to process it.

Just like **onResolve** , **getBars** is also an asynchronous function which takes **symbolInfo** , **resolution** , **periodParams** , **onHistoryCallback** , **onErrorCallback** & first as it’s parameters/arguments. Inside the getBars method, we’ll be making a try and catch block and making a POST request call using Axios to Bitquery GraphQL API to process the following query

```auto
{
  ethereum(network: bsc) {
    dexTrades(
      options: {asc: "timeInterval.minute"}
      date: {since: "2021-06-20T07:23:21.000Z", till: "${new Date().toISOString()}"}
      exchangeAddress: {is: "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73"}
      baseCurrency: {is: "${baseCurrency}"},
      quoteCurrency: {is: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c"},
      tradeAmountUsd: {gt: 10}
    ) 
    {
      timeInterval {
        minute(count: 15, format: "%Y-%m-%dT%H:%M:%SZ")  
      }
      volume: quoteAmount
      high: quotePrice(calculate: maximum)
      low: quotePrice(calculate: minimum)
      open: minimum(of: block, get: quote_price)
      close: maximum(of: block, get: quote_price) 
    }
  }
}

```

in order to obtain OHLC data which can be set into a candlesticks format to show in the final product.

We’ll save the response which we got from the API call in a variable called ‘bars’ and we’ll implement the map( ) function to set the data for the opening, closing, maximum and minimum prices of a candlestick. The below code is the complete getBars method.

```auto
getBars: async(symbolInfo, resolution, periodParams, onHistoryCallback, onErrorCallback) =>{
        try{
            if (resolution==='1D') {
                resolution = 1440;
            }
            const response2 = await axios.post(Bitquery.endpoint, {
                query: `
                        {
                          ethereum(network: bsc) {
                            dexTrades(
                              options: {asc: "timeInterval.minute"}
                              date: {since: "2021-06-20T07:23:21.000Z", till: "${new Date().toISOString()}"}
                              exchangeAddress: {is: "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73"}
                              baseCurrency: {is: "${baseCurrency}"},
                              quoteCurrency: {is: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c"},
                              tradeAmountUsd: {gt: 10}
                            ) 
                            {
                              timeInterval {
                                minute(count: 15, format: "%Y-%m-%dT%H:%M:%SZ")  
                              }
                              volume: quoteAmount
                              high: quotePrice(calculate: maximum)
                              low: quotePrice(calculate: minimum)
                              open: minimum(of: block, get: quote_price)
                              close: maximum(of: block, get: quote_price) 
                            }
                          }
                        }
                        `,
                variables: {
                    "from": new Date("2021-06-20T07:23:21.000Z").toISOString(),
                    "to": new Date("2021-06-23T15:23:21.000Z").toISOString(),
                    "interval": Number(resolution),
                    "tokenAddress": symbolInfo.ticker
                },
                mode: 'cors',

            }, {
                headers: {
                    "Content-Type": "application/json",
                    "X-API-KEY": "YOUR UNIQUE API KEY"
                }
            })

            const bars = response2.data.data.ethereum.dexTrades.map(el => ({
                time: new Date(el.timeInterval.minute).getTime(), // date string in api response
                low: el.low,
                high: el.high,
                open: Number(el.open),
                close: Number(el.close),
                volume: el.volume
            }))

            if (bars.length){
                onHistoryCallback(bars, {noData: false});
            }else{
                onHistoryCallback(bars, {noData: true});
            }

        } catch(err){
            console.log({err})
        }
    },

```

> **Inserting the contents of the ./api/index.js file in TVChartContainer.vue**

```auto
mounted() {
        const widgetOptions = {
            symbol: this.symbol,
            datafeed: api(this.baseCurrency),
            interval: this.interval,
            container_id: this.containerId,
            library_path: this.libraryPath,
            theme: 'Dark',
            locale: 'en',
            disabled_features: ['use_localstorage_for_settings'],
            charts_storage_url: this.chartsStorageUrl,
            charts_storage_api_version: this.chartsStorageApiVersion,
            client_id: this.clientId,
            user_id: this.userId,
            fullscreen: this.fullscreen,
            autosize: this.autosize,
            studies_overrides: this.studiesOverrides,
            timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
        }
},

```

For the above snippet, in **line-4** the **datafeed attribute** gets a value of **api(this.baseCurrency)**. The complete code for the TVChartContainer.vue file is as follows.

```auto
<template>
    <div>
        <div class="TVChartContainer" id="tv_chart_container"/>
    </div>
</template>

<script>
import api from './api/index'
export default {
    name: 'TVChartContainer',
    props: {
        symbol: {
            default: 'BITQUERY',
            type: String,
        },
        interval: {
            default: 'D',
            type: String,
        },
        containerId: {
            default: 'tv_chart_container',
            type: String,
        },
        datafeedUrl: {
            default: 'https://demo-feed-data.tradingview.com',
            type: String,
        },
        libraryPath: {
            default: '/charting_library/charting_library/',
            type: String,
        },
        chartsStorageUrl: {
            default: 'https://saveload.tradingview.com',
            type: String,
        },
        chartsStorageApiVersion: {
            default: '1.2',
            type: String,
        },
        clientId: {
            default: 'tradingview.com',
            type: String,
        },
        fullscreen: {
            default: false,
            type: Boolean,
        },
        autosize: {
            default: true,
            type: Boolean,
        },
        studiesOverrides: {
            type: Object,
        }
    },
    tvWidget: null,
    data() {
        return {
            baseCurrency: '0x2170ed0880ac9a755fd29b2688956bd959f933f8',
            addressInfo: {},
            searchValue: "",
            getSearchAddress: [],
            getAllAddressValue: [],
            showSearchChild: false,
        }
    },
    mounted() {
        const widgetOptions = {
            symbol: this.symbol,
            datafeed: api(this.baseCurrency),
            interval: this.interval,
            container_id: this.containerId,
            library_path: this.libraryPath,
            theme: 'Dark',
            locale: 'en',
            disabled_features: ['use_localstorage_for_settings'],
            charts_storage_url: this.chartsStorageUrl,
            charts_storage_api_version: this.chartsStorageApiVersion,
            client_id: this.clientId,
            user_id: this.userId,
            fullscreen: this.fullscreen,
            autosize: this.autosize,
            studies_overrides: this.studiesOverrides,
            timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
        }
        this.tvWidget = new TradingView.widget(widgetOptions)
    },
    methods: {
        getCoinInfo() {
            const query = `
                        {
                          ethereum(network: bsc) {
                            dexTrades(
                              options: {desc: ["block.height", "transaction.index"], limit: 1}
                              exchangeAddress: {is: "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73"}
                              baseCurrency: {is: "${this.baseCurrency}"}
                              quoteCurrency: {is: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c"}
                            )
                            {
                              block {
                                height
                                timestamp {
                                  time(format: "%Y-%m-%d %H:%M:%S")
                                }
                              }
                              transaction {
                                index
                              }
                              baseCurrency {
                                name
                                symbol
                                decimals
                              }
                              quotePrice
                            }
                          }
                        }
                        `;
            const url = "https://graphql.bitquery.io/";
            const opts = {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                    "X-API-KEY": "YOUR UNIQUE API KEY"
                },
                body: JSON.stringify({
                    query
                })
            };
            fetch(url, opts)
                .then(res => res.json())
                .then(response => {
                    this.addressInfo = response.data.ethereum.dexTrades[0].baseCurrency;
                })
                .catch(console.error);
        },
    },
}
</script>

<style>
.TVChartContainer {
    position: absolute;
    width: 100%;
    height: 80%;
}
</style>

```

> **Injecting Component to Home.vue and Tradingview.vue**

Now, after creating the TVChartContainer.vue, in order to display the same in our VueJS application, we need to make a Home.vue file inside ./views folder and call the TVChartContainer.vue file’s contents inside it.  
The following code snippet would make this more clear.

```auto
<template>
    <TVChartContainer :symbol="'BITQUERY'" :interval="'60'"></TVChartContainer>
</template>

<script>
import TVChartContainer from "../components/TVChartContainer";
export default {
    name: "Home",
    components: {TVChartContainer}
}
</script>

<style scoped>
</style>

```

**NOTE!**  
**In the attached project, we have used VueJS Router. What it does is that when the user starts the VueJS application in his/her local browser, if a request like [https://localhost:8080/](https://localhost:8080/) is made, then Home.vue file’s contents will be displayed and if [https://localhost:8080/trading-view](https://localhost:8080/trading-view) is made, then Tradingview.vue file’s contents will be displayed!**

Furthermore, in the **App.vue** the `<router-view />` component would render the **Home.vue** or **Tradingview.vue** component as per the request made by the user as shown below.

```auto
<template>
    <div id="app">
        <router-view />
    </div>
</template>

<script>
export default {
    name: 'App'
};
</script>

<style scoped></style>

```

> **Running the VueJS project**

In the root folder of your project, run the following command in the terminal to run the VueJS application.

```auto
npm run serve

```

Open your browser and move to **[https://localhost:8080/](https://localhost:8080/)** and you’ll see a similar screen as shown below.

 ![Screenshot (181)](https://us1.discourse-cdn.com/flex016/uploads/bitquery/original/1X/b983981d39dbae9af5ade1bbece8f5d6ebb2a34a.png)

Using the indicator markdown in the Technical Chart, select **Moving Average Exponential indicator** and you’ll notice a blue line passing through the candlesticks.

 ![Screenshot (184)](https://us1.discourse-cdn.com/flex016/uploads/bitquery/original/1X/e96625f1e234137b56005745f1b67dc2a2442e64.png)

This is the Exponential Moving Average criteria which is a type of weighted moving average that gives more weighting or importance to recent price data.

 ![Screenshot (182)](https://us1.discourse-cdn.com/flex016/uploads/bitquery/original/1X/9e6a2114e76e8c5d66a258d40973e4e589ee4749.png)

You can use some other Indicators and some other form of data representation (other than candlesticks) for example

**Area Graph**

 ![Screenshot (186)](https://us1.discourse-cdn.com/flex016/uploads/bitquery/original/1X/763cb8370f827bda0deae1f564732885c7662aa4.png)

**Line Graph**

 ![Screenshot (187)](https://us1.discourse-cdn.com/flex016/uploads/bitquery/original/1X/a5686724df8c3e43c83e2bc8a0185daf903ce77d.png)

> **GitHub Repository**

> **[GitHub - sayon-bitquery/tradingview-three-vuejs-final](https://github.com/sayon-bitquery/tradingview-three-vuejs-final)**
>
> Contribute to sayon-bitquery/tradingview-three-vuejs-final development by creating an account on GitHub.

Don’t forget to check out

> **[TradingView Charts for PancakeSwap Tokens](https://abskmj.github.io/notes/posts/trading-view-charts/pancakeswap-tokens/)**

---

<div class="post-metadata">

### Author: ![cryptoMav](https://avatars.discourse-cdn.com/v4/letter/c/dfb087/32.png) [@cryptoMav](https://community.bitquery.io/u/cryptoMav)
#### Post date: [August 5, 2021, 3:20pm UTC](https://community.bitquery.io/t/integrating-tradingview-s-technical-analysis-charts-with-bitquery-graphql-api-using-vuejs/343/2 "2021-08-05T15:20:29Z")

</div>

Do you have any information on how to properly use the subscribeBars() method in the datafeed to properly update the chart with live data? This seems to be the biggest hurdle while using bitQuery as an endpoint for the chart data. Thanks

---

<div class="post-metadata">

### Author: ![sayon](https://avatars.discourse-cdn.com/v4/letter/s/b2d939/32.png) [@sayon](https://community.bitquery.io/u/sayon)
#### Post date: [August 5, 2021, 3:46pm UTC](https://community.bitquery.io/t/integrating-tradingview-s-technical-analysis-charts-with-bitquery-graphql-api-using-vuejs/343/3 "2021-08-05T15:46:08Z")

</div>

At the present moment Realtime updates are not implemented but it will be implemented ASAP. Meanwhile you can checkout this documentation provided by Tradingview themselves regarding Realtime updates using Web Sockets

> <https://github.com/tradingview/charting-library-tutorial/blob/master/documentation/streaming-implementation.md>
