Customising TradingView for Mobile applications

Posted By : Asheesh Bhuria | 05-May-2020

TradingView is a charting library. From plotting basic price charts to complex spread symbols with overlayed strategy backtesting, it provides the tools and data one needs. Anyone can buy the license and build interactive applications.

Recently, in one of our projects we needed to implement TradingView library to render charts inside mobile applications. One of the major challenges was TradingView fetches data from url, and is not based on datafeed system. It only accepts data in a specific format. This means if we are receiving the chart data in any other format then TradingView will fail to plot the chart. In our scenario, the data format from the server wasn’t in the format required by the Trading View library. Further it was difficult to make changes at the backend since the same backend API was being used to serve a number of different applications and changing the response format could have resulted in the breakdown of functionality for those apps. Hence we had to find a way to convert the response from the server into one that was acceptable by the TradingView library and also make changes to the implementation of the library to ensure it accepts a direct datafeed instead of a remote server url.

 

Original approach

The charting library calls a function GetBars() whenever it needs historic data. GetBars makes use of JavaScript’s Fetch API to fetch the chart data, after being fetched this data is loaded into the chart.

 

Need for a new approach

As discussed earlier the charting library calls GetBars() whenever the chart needs historic data. The problem with the initial approach is not all APIs (for getting chart data) have  Access-Control-Allow-Origin in the header. This means that we cannot fetch the data from JavaScript the way we were doing earlier.

Our initial approach was to use a middleware and use JavaScript Fetch API to fetch the data from the middleware. When requesting the data from middleware, session id (generated when the user logins) of the end-user was also passed, which was then used to fetch the chart data from the API. After the middleware fetches the data it is returned as json object, but this time allowing the data to be shared with the code requesting it. But this caused expiration of end-user’s session.

 

Use of promises

One workaround is to receive the chart data from the mobile application. The biggest challenge for us was to make the communications between javascript (TradingView) and mobile application synchronized such that we do not tamper with the workflow of the charting library.

 

Let’s have a look at the workflow,

When GetBars() is called, it calls a function “initCallToMobile()” which is defined in index.html (inline javacript).

    getBars(symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) {
      // Code
      const getKlines = (from, to) => {
        appFunc(periodId, symbolName,beforeDate, rowsNumber) 
          promise.then((chartData) => {
            //Process the date (stringified 
            JSON to JSON object)
              finishKlines(Data)
        }
      }
    }

 

Below in the code inside Index.html (inline javascript)

   function returnPromise() {
      let res, rej;
      let promiseX = new Promise((resolve, reject) => {
        res = resolve
        rej = reject
      });
      promiseX.resolve = res
      promiseX.reject = rej
      return promiseX
    }
     
    var promise 

    // initCallToMobile() makes call to mobile application whenever chart data is needed
    function initCallToMobile(interval, symbol, beforeDate, rowsNumber) {
        promise =  returnPromise() // Promise Created
        AppInterface.onChartDragged(interval, symbol, beforeDate,rowsNumber)
    }

 

The initCallToMobile() makes calls onChartDragged() function in the mobile application. When onChartDragged() is called, the mobile application requests chart data from the API. Note that the variable “promise” is declared outside the initCallToMobile() function and defined inside the function. returnPromise() returns a promise object which can be resolved externally. Also, it is not recommended to return chart data when onChartDragged() is called, as the API calls in the mobile app need to run in a synchronous order.

 

When the mobile application receives the data it calls postChartData() function which is defined inside index.html (inline JavaScript). This function resolves the global variable “promise” with the chart data (received as an argument.)

    function postChartData(chartData) {
      // Process chart date 
      promise.resolve(chartDataProcessed)   
    }

 

When the global variable “promise” is resolved with the data received from mobile application, the data can be loaded after processing it.

    getBars(symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) {
      // Code
      const getKlines = (from, to) => {
        appFunc(periodId, symbolName,beforeDate, rowsNumber) 
          promise.then((chartData) => {
            //Process the date (stringified 
            JSON to JSON object)
              finishKlines(Data)
        }
      }
    }

 

Conclusion

I am sure this blog introduced you to a very unique and efficient approach to manipulating the charting library. By using this approach the chart loading time was decreased by approximately 15%. We also saw how we can resolve promises externally and use it to synchronize the workflow of any application.

 

References

http://lea.verou.me/2016/12/resolve-promises-externally-with-this-one-weird-trick/
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin

 

About Author

Author Image
Asheesh Bhuria

Asheesh Bhuria is a software engineer. With his knowledge in new technologies he excels in MEAN Stack development.

Request for Proposal