├── .gitignore ├── ESGGraphPlot.ipynb ├── LICENSE.md ├── README.md ├── esggraphplot.py ├── images ├── bargraphmsft.png ├── barhco2.png ├── barhwomanmanager.png └── linegraphmsft.png └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.suo 2 | *.user 3 | _ReSharper.* 4 | bin 5 | obj 6 | publish 7 | packages 8 | .vs 9 | .idea 10 | .vscode 11 | -------------------------------------------------------------------------------- /ESGGraphPlot.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Using Data Platform API to request ESG data on Jupyter Notebook\n", 8 | "\n", 9 | "## INTRODUCTION\n", 10 | "\n", 11 | "Environmental, Social and Governance (ESG) is a set of standards for a company's operations that investors use to evaluate corporate behavior, determine the future financial performance and decide whether it will be beneficial to invest in a company or not. The ESG information from Refinitv enables our clients to benchmark, compare and integrate extra-financial information into their investment processes to identify companies with quality management and reduced risk exposure. Please refer to the [ESG Learning Section](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis/quick-start#quickstart-guide-for-esg) on the [Developer Community](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis/documentation#esg-user-guide) for more details about the ESG data and its coverage provided by LSEG.\n", 12 | "\n", 13 | "This article will demonstrate how we can retrieve [ESG data](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis/documentation#esg-data-guide) from [Data Platform (RDP)](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis/quick-start#quickstart-guide-for-refinitiv-data-platform). We will be using Python with RDP API to request ESG data on the [Jupyter Notebook](https://jupyter.org/index.html). The notebook allows the user to create and share documents that contain live code, narrative text, visualizations and we can also plot the graph on the notebook.\n", 14 | "\n", 15 | "The Jupyter Notebook with Python codes will be provided on GitHub.\n", 16 | "\n", 17 | "## PRE-REQUISITES:\n", 18 | "\n", 19 | "* Python 3.9 or later version.\n", 20 | "* Required Python Packages: getpass, json, requests, pandas, numpy, matplotlib.\n", 21 | "* [Jupyter Notebook](https://jupyter.org/install). You can install Jupyter Notebook on your local machine and then test the example on the machine. Alternate choice is a free Juputer Notebook on cloud environment such as [Azure Notebook](https://notebooks.azure.com/) provided by Microsoft. You can find more details from [this tutorial](https://docs.microsoft.com/en-us/azure/notebooks/tutorial-create-run-jupyter-notebook).If you are not familiar with Jupyter Notebook, the following [tutorial](https://www.datacamp.com/community/tutorials/tutorial-jupyter-notebook?utm_source=adwords_ppc&utm_campaignid=1455363063&utm_adgroupid=65083631748&utm_device=c&utm_keyword=&utm_matchtype=b&utm_network=g&utm_adpostion=1t1&utm_creative=332602034364&utm_targetid=aud-748597547652:dsa-473406581035&utm_loc_interest_ms=&utm_loc_physical_ms=1012728&gclid=CjwKCAjwiZnnBRBQEiwAcWKfYtOonT1GbauG4cpg4BYnMowI6EOcYxUAUTz_ywny2KjyBchUeULgGxoCkoEQAvD_BwE) created by DataCamp may help.\n", 22 | "* DP account with a permission to access ESG basic or premium data. \n", 23 | "\n", 24 | "## IMPREMENTATIONS\n", 25 | "\n", 26 | "There are two main steps for the implementation according to [the tutorial](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis/tutorials#esg-data-in-python).\n", 27 | "\n", 28 | "* Get Access Token from RDP Authentication Endpoint.\n", 29 | "* Get specific ESG data like the basic score from the REST endpoint. \n", 30 | "* Display data and plot a graph.\n" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "### Get Access Token\n", 38 | "\n", 39 | "__Get RDP Username and Password__\n", 40 | "\n", 41 | "The user must have a valid RDP account with a permission to access ESG data. The application will use getpass to get the username and password from user." 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "import getpass as gp\n", 51 | "\n", 52 | "username=input('Enter RDP username:')\n", 53 | "password=gp.getpass('Enter RDP Password:')\n", 54 | "client_id=input('Enter client id or appKey:')" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "from json import dumps, loads, load\n", 64 | "from requests import post,get\n", 65 | "\n", 66 | "#Get access token from RDP server \n", 67 | "getTokenEndpoint=\"https://api.refinitiv.com/auth/oauth2/v1/token\"\n", 68 | "refreshToken=None\n", 69 | "accessToken=None\n", 70 | "_header= {}\n", 71 | "_header['Accept']='application/json'\n", 72 | "_params={}\n", 73 | "\n", 74 | "if refreshToken is None:\n", 75 | " _params={\n", 76 | " \"username\": username,\n", 77 | " \"password\": password,\n", 78 | " \"client_id\": client_id,\n", 79 | " \"grant_type\": \"password\",\n", 80 | " \"scope\": \"trapi\",\n", 81 | " \"takeExclusiveSignOnControl\": \"true\"\n", 82 | " }\n", 83 | "else:\n", 84 | " _params={\n", 85 | "\t\t\t\"refresh_token\": refreshToken,\n", 86 | "\t\t\t\"username\": username,\n", 87 | "\t\t\t\"grant_type\": \"refresh_token\"\n", 88 | " }\n", 89 | "\n", 90 | "resp=post(url=getTokenEndpoint,data=_params,headers=_header,auth=(username,\"\"))" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": {}, 96 | "source": [ 97 | "If the returned status code from HTTP response is not 200 (OK), we assume that there is an error occurred, therefore, the application will print the status code and the response status message then exit the application. Otherwise, get the Refresh Token and Access Token from the HTTP response message and print it out." 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [ 106 | "if resp.status_code!=200:\n", 107 | " print(\"Status Code:\",resp.status_code,\" Text:\",dumps(loads(resp.text),indent=4))\n", 108 | " exit()\n", 109 | "else:\n", 110 | " #print(dumps(loads(resp.text),indent=4))\n", 111 | " from collections import OrderedDict\n", 112 | " auth_object=loads(resp.text,object_pairs_hook=OrderedDict)\n", 113 | " accessToken=auth_object[\"access_token\"]\n", 114 | " refreshToken=auth_object[\"refresh_token\"]\n", 115 | "\n", 116 | "print(\"Refresh Token:\",refreshToken)\n", 117 | "print(\"Access Token:\",accessToken)" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "### Retreive ESG score\n", 125 | "\n", 126 | "In this example, we want to retrieve the ESG Score standard. The score standard operation returns all available scores for a company with three years of historical data. Application has to use the following Endpoint to retrieve the data.\n", 127 | "\n", 128 | "```html\n", 129 | "https://api.lseg.com/data/environmental-social-governance/v2/views/scores-standard\n", 130 | "```\n", 131 | "There is an alternate option for a professional account to get ESG data with full score and it returns scores with full history. The user can use the following Endpoint instead.\n", 132 | "\n", 133 | "```html\n", 134 | "https://api.lseg.com/data/environmental-social-governance/v2/views/scores-full\n", 135 | "```\n", 136 | "The application has to send the server certain GET parameters through the requested endpoint/URL. In this case, it has to pass a universe as HTTP get parameters. The universe could be RIC name or ISIN or any other supported value. \n", 137 | "The application needs to set a Bearer access token in the Authorization header of the HTTP request message. See below snippet of codes for the API usage to request full ESG score for the RIC MSFT.O." 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": null, 143 | "metadata": {}, 144 | "outputs": [], 145 | "source": [ 146 | "ricList=\"MSFT.O\"\n", 147 | "esgScoreFullEndpoint=\"https://api.refinitiv.com/data/environmental-social-governance/v2/views/scores-full?universe=\"\n", 148 | "resp=get(url=esgScoreFullEndpoint+ricList,headers={\"Authorization\": \"Bearer \" + accessToken})\n", 149 | "\n", 150 | "if resp.status_code!=200:\n", 151 | " print(\"Status Code:\",resp.status_code,\" Text:\",dumps(loads(resp.text),indent=4))\n", 152 | " exit()\n", 153 | "\n", 154 | "esg_object=loads(resp.text)" 155 | ] 156 | }, 157 | { 158 | "cell_type": "markdown", 159 | "metadata": {}, 160 | "source": [ 161 | "To process the ESG data, we need to convert the data from JSON object to a pandas data frame. The application need to get the data and column name from JSON object and then re-construct a new dataframe. The applicaiton need to converts the title from a header to numpy arrary and convert data array to numpy array as well. " 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": null, 167 | "metadata": {}, 168 | "outputs": [], 169 | "source": [ 170 | "import pandas as pd\n", 171 | "import numpy as np\n", 172 | "headers=esg_object['headers']\n", 173 | "#Get column headers/titles using lambda\n", 174 | "titles=map(lambda header:header['title'], headers)\n", 175 | "\n", 176 | "dataArray=np.array(esg_object['data'])\n", 177 | "df=pd.DataFrame(data=dataArray,columns=titles)\n" 178 | ] 179 | }, 180 | { 181 | "cell_type": "markdown", 182 | "metadata": {}, 183 | "source": [ 184 | "It should return the data like the following sample output." 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": null, 190 | "metadata": {}, 191 | "outputs": [], 192 | "source": [ 193 | "if df.empty is False:\n", 194 | " print(df.head(10))" 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "metadata": {}, 200 | "source": [ 201 | "### Plot Graph from ESG Score\n", 202 | "\n", 203 | "To compare specific ESG data between the years, Jupyter Notebook user may use the mathplotlib to plot the graph.\n", 204 | "\n", 205 | "For this example, we want to compare columns \"ESG Score\",\"ESG Combined Score\" and \"Innovation Score\" between the years. I have to create a new data frame from the origina data frame df using the following codes." 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": null, 211 | "metadata": {}, 212 | "outputs": [], 213 | "source": [ 214 | "dataPlot=pd.DataFrame(df,columns=['Instrument','Period End Date','ESG Score','ESG Combined Score','Innovation Score'])" 215 | ] 216 | }, 217 | { 218 | "cell_type": "markdown", 219 | "metadata": {}, 220 | "source": [ 221 | "The data for the Y-axis is a Period End Date and the X-axis is the ESG scores. We want to display only the year (eg \"2017\", \"2016\") therefore we need to reformat the data in \"Period End Date\" column using below codes. The example also sorting the year ascending. \n", 222 | "\n", 223 | "Note that you can change the column in dataPlot to plot the graph for specific data you want. If you have permission to request only a basic score you might need to change the column accordingly." 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": null, 229 | "metadata": {}, 230 | "outputs": [], 231 | "source": [ 232 | "dataPlot['Period End Date']= dataPlot['Period End Date'].str.split('-').str[0]\n", 233 | "dataPlot.sort_values('Period End Date',ascending=True,inplace=True)" 234 | ] 235 | }, 236 | { 237 | "cell_type": "markdown", 238 | "metadata": {}, 239 | "source": [ 240 | "It will be displaying the following sample graphs on the notebook." 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": null, 246 | "metadata": {}, 247 | "outputs": [], 248 | "source": [ 249 | "dataPlot.plot(x='Period End Date',y=['ESG Score','ESG Combined Score','Innovation Score'],figsize=(14,7))\n", 250 | "dataPlot.plot(x='Period End Date',y=['ESG Score','ESG Combined Score','Innovation Score'],kind='bar',figsize=(14,7))" 251 | ] 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "metadata": {}, 256 | "source": [ 257 | "### Compare ESG Score for multiple universe\n", 258 | "\n", 259 | "The next step, I'm interested in comparing the value of a number of Woman Manager and CO2 Emission Total used by a top tech company such as Microsoft, IBM, Facebook, Google/Alphabet, and Amazon. \n", 260 | "\n", 261 | "Based on the details from EDP Swagger page, we can get the data using basic score endpoint and we just need to pass a list of RIC for each company as a universe parameters. Below are a snippet of codes to demonstrate the API usage." 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": null, 267 | "metadata": {}, 268 | "outputs": [], 269 | "source": [ 270 | "ricList=\"IBM,AMZN.O,MSFT.O,GOOGL.O,FB.O,APPL.O\"\n", 271 | "esgฺBasicEndpoint=\"https://api.refinitiv.com/data/environmental-social-governance/v1/views/basic?universe=\"\n", 272 | "resp=get(url=esgฺBasicEndpoint+ricList,headers={\"Authorization\": \"Bearer \" + accessToken})\n", 273 | "if resp.status_code!=200:\n", 274 | " print(\"Status Code:\",resp.status_code,\" Text:\",dumps(loads(resp.text),indent=4))\n", 275 | " exit()\n", 276 | "\n", 277 | "esg_BasicObject=loads(resp.text)\n", 278 | "\n", 279 | "headers=esg_BasicObject['headers']\n", 280 | "\n", 281 | "#Get column headers/titles using lambda\n", 282 | "titles=map(lambda header:header['title'], headers)\n", 283 | "\n", 284 | "basicDataArray=np.array(esg_BasicObject['data'])\n", 285 | "basicDf=pd.DataFrame(data=basicDataArray,columns=titles)" 286 | ] 287 | }, 288 | { 289 | "cell_type": "markdown", 290 | "metadata": {}, 291 | "source": [ 292 | "Print sample basic score result." 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "execution_count": null, 298 | "metadata": {}, 299 | "outputs": [], 300 | "source": [ 301 | "if basicDf.empty is False:\n", 302 | " print(basicDf.head(10))" 303 | ] 304 | }, 305 | { 306 | "cell_type": "markdown", 307 | "metadata": {}, 308 | "source": [ 309 | "__Display Componay Name__\n", 310 | "\n", 311 | "We have an additional requirement to display Company Name rather than using RIC codes. Basically, the data returned by the ESG basic score has only an Instrument name but it does not have a company named. Therefore, I need to create a function for getting the company name from ESG universe data. I found that the ESG universe endpoint can provide the company names that I want. I will use it later when I plot the graph. Anyway, we found that we can't find some RIC code using the universe Endpoint so it will return the original RIC name instead.\n" 312 | ] 313 | }, 314 | { 315 | "cell_type": "code", 316 | "execution_count": null, 317 | "metadata": {}, 318 | "outputs": [], 319 | "source": [ 320 | "esgUniverseEndpoint=\"https://api.refinitiv.com/data/environmental-social-governance/v2/universe\"\n", 321 | "\n", 322 | "resp=get(url=esgUniverseEndpoint,headers={\"Authorization\": \"Bearer \" + accessToken})\n", 323 | "if resp.status_code!=200:\n", 324 | " print(\"Status Code:\",resp.status_code,\" Text:\",dumps(loads(resp.text),indent=4))\n", 325 | " exit()\n", 326 | "\n", 327 | "esg_universe = loads(resp.text)\n", 328 | "\n", 329 | "def GetRicName(ricName):\n", 330 | " if 'data' in esg_universe:\n", 331 | " searchItem = list(filter(lambda data: data[1]==ricName, list(esg_universe['data'])))\n", 332 | " if len(searchItem)>0:\n", 333 | " return searchItem[0][2]\n", 334 | " return None\n", 335 | "\n" 336 | ] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "metadata": {}, 341 | "source": [ 342 | "Display Company Name for MSFT.O ric." 343 | ] 344 | }, 345 | { 346 | "cell_type": "code", 347 | "execution_count": null, 348 | "metadata": {}, 349 | "outputs": [], 350 | "source": [ 351 | "if GetRicName('MSFT.O') is not None:\n", 352 | " print(\"MSFT.O is \\\"\"+ GetRicName(\"MSFT.O\")+\"\\\"\")\n", 353 | "else:\n", 354 | " print(\"Unable to find name for MSFT.O\")" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "metadata": {}, 360 | "source": [ 361 | "Next step we will be using the data from a **basicDf** dataframe to plot horizontal bar chart for comparing a **Woman Managers** and **CO2 Emission Total** from each company. Base on a result from a dataframe, we found that column number 5 is a data for \"**CO2 Equivalents Emission Total**\" and column number 6 is a data for \"**Women Managers**\", then we will use the index to extract the data. Below are the codes we use to extract both data from the data frame." 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": null, 367 | "metadata": {}, 368 | "outputs": [], 369 | "source": [ 370 | "# Extract CO2, Woman Manager and Instrument from the dataframe and convert to numpy array\n", 371 | "co2= [val for sublist in np.array(basicDf.iloc[:,5:6]) for val in sublist]\n", 372 | "\n", 373 | "woman=[val for sublist in np.array(basicDf.iloc[:,6:7]) for val in sublist] \n", 374 | "\n", 375 | "instrument=[val for sublist in np.array(basicDf.iloc[:,0:1]) for val in sublist] \n" 376 | ] 377 | }, 378 | { 379 | "cell_type": "markdown", 380 | "metadata": {}, 381 | "source": [ 382 | "Print data inside co2,woman and instrument variable." 383 | ] 384 | }, 385 | { 386 | "cell_type": "code", 387 | "execution_count": null, 388 | "metadata": {}, 389 | "outputs": [], 390 | "source": [ 391 | "print(co2)\n", 392 | "print(woman)\n", 393 | "print(instrument)" 394 | ] 395 | }, 396 | { 397 | "cell_type": "markdown", 398 | "metadata": {}, 399 | "source": [ 400 | "Next step we need to get a company name for each instrument from the instrument list." 401 | ] 402 | }, 403 | { 404 | "cell_type": "code", 405 | "execution_count": null, 406 | "metadata": {}, 407 | "outputs": [], 408 | "source": [ 409 | "instrumentorg=np.array([])\n", 410 | "\n", 411 | "for val in instrument:\n", 412 | " if GetRicName(val) is None:\n", 413 | " instrumentorg=np.append(instrumentorg,val)\n", 414 | " else:\n", 415 | " instrumentorg=np.append(instrumentorg,GetRicName(val))" 416 | ] 417 | }, 418 | { 419 | "cell_type": "markdown", 420 | "metadata": {}, 421 | "source": [ 422 | "Display instrument name." 423 | ] 424 | }, 425 | { 426 | "cell_type": "code", 427 | "execution_count": null, 428 | "metadata": {}, 429 | "outputs": [], 430 | "source": [ 431 | "print(instrumentorg)" 432 | ] 433 | }, 434 | { 435 | "cell_type": "markdown", 436 | "metadata": {}, 437 | "source": [ 438 | "The last step we construct dataframe for plotting the graph for displaying a data for **CO2 Emission Total** with a **Woman Managers** separately because of the difference between the scale of each data. We will be using the company name as an index." 439 | ] 440 | }, 441 | { 442 | "cell_type": "code", 443 | "execution_count": null, 444 | "metadata": {}, 445 | "outputs": [], 446 | "source": [ 447 | "df1 = pd.DataFrame({\"Woman Managers\":woman}, index=instrumentorg)\n", 448 | "df1.plot.barh(y='Woman Managers')" 449 | ] 450 | }, 451 | { 452 | "cell_type": "markdown", 453 | "metadata": {}, 454 | "source": [ 455 | "It looks like currently we do not have \"Woman Managers\" report for IBM." 456 | ] 457 | }, 458 | { 459 | "cell_type": "code", 460 | "execution_count": null, 461 | "metadata": {}, 462 | "outputs": [], 463 | "source": [ 464 | "df2 = pd.DataFrame({\"CO2 Emission Total\":co2}, index=instrumentorg)\n", 465 | "df2.plot.barh(y='CO2 Emission Total',color=(0.5, 0.25, 0.15, 1))" 466 | ] 467 | }, 468 | { 469 | "cell_type": "markdown", 470 | "metadata": {}, 471 | "source": [ 472 | "For CO2 Emision Totla, it looks like currently we do not have a CO2 report for Amazon.\n", 473 | "You can change or modify Python codes in this notebook to displaying data from other columns of the dataframe for basic or full ESG Score." 474 | ] 475 | }, 476 | { 477 | "cell_type": "markdown", 478 | "metadata": {}, 479 | "source": [ 480 | "## REFERENCES\n", 481 | "\n", 482 | "* [Data Platform Document](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis/documentation)\n", 483 | "* [Data Platform Tutorial](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis/tutorials)\n", 484 | "* [ESG User Guide](https://developers.lseg.com/en/api-catalog/refinitiv-data-platform/refinitiv-data-platform-apis/documentation#esg-data-guide)\n", 485 | "\n", 486 | "## DOWNLOADS\n", 487 | "* [Github](https://github.com/LSEG-API-Samples/Example.RDP.Python.ESGGraphPlot)" 488 | ] 489 | }, 490 | { 491 | "cell_type": "code", 492 | "execution_count": null, 493 | "metadata": {}, 494 | "outputs": [], 495 | "source": [] 496 | } 497 | ], 498 | "metadata": { 499 | "kernelspec": { 500 | "display_name": "Python 3 (ipykernel)", 501 | "language": "python", 502 | "name": "python3" 503 | }, 504 | "language_info": { 505 | "codemirror_mode": { 506 | "name": "ipython", 507 | "version": 3 508 | }, 509 | "file_extension": ".py", 510 | "mimetype": "text/x-python", 511 | "name": "python", 512 | "nbconvert_exporter": "python", 513 | "pygments_lexer": "ipython3", 514 | "version": "3.11.4" 515 | } 516 | }, 517 | "nbformat": 4, 518 | "nbformat_minor": 4 519 | } 520 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2021 Refinitiv 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Using RDP API to request ESG data on Jupyter Notebook](https://developers.lseg.com/en/article-catalog/article/using-rdp-api-request-esg-data-jupyter-notebook) 2 | -------------------------------------------------------------------------------- /esggraphplot.py: -------------------------------------------------------------------------------- 1 | import getpass as gp 2 | 3 | username=input('Enter RDP username:') 4 | clientid=input('Enter client id/app id:') 5 | password=gp.getpass('Enter RDP Password:') 6 | 7 | from json import dumps, loads, load 8 | from requests import post,get 9 | 10 | #Get access token from EDP server 11 | getTokenEndpoint="https://api.refinitiv.com/auth/v1/beta1/token" 12 | refreshToken=None 13 | accessToken=None 14 | _header= {} 15 | _header['Accept']='application/json' 16 | _params={} 17 | 18 | if refreshToken is None: 19 | _params={ 20 | "username": username, 21 | "password": password, 22 | "client_id": clientid, 23 | "grant_type": "password", 24 | "scope": "trapi", 25 | "takeExclusiveSignOnControl": "true" 26 | } 27 | else: 28 | _params={ 29 | "refresh_token": refreshToken, 30 | "username": username, 31 | "grant_type": "refresh_token" 32 | } 33 | 34 | resp=post(url=getTokenEndpoint,data=_params,headers=_header,auth=(username,"")) 35 | if resp.status_code!=200: 36 | print("Status Code:",resp.status_code," Text:",dumps(loads(resp.text),indent=4)) 37 | exit() 38 | else: 39 | #print(dumps(loads(resp.text),indent=4)) 40 | from collections import OrderedDict 41 | auth_object=loads(resp.text,object_pairs_hook=OrderedDict) 42 | accessToken=auth_object["access_token"] 43 | refreshToken=auth_object["refresh_token"] 44 | 45 | print("Refresh Token:",refreshToken) 46 | print("Access Token:",accessToken) 47 | 48 | esgUniverseEndpoint="https://api.refinitiv.com/data/environmental-social-governance/v2/universe" 49 | resp=get(url=esgUniverseEndpoint,headers={"Authorization": "Bearer " + accessToken}) 50 | if resp.status_code!=200: 51 | print("Status Code:",resp.status_code," Text:",dumps(loads(resp.text),indent=4)) 52 | exit() 53 | 54 | esg_universe = loads(resp.text) 55 | 56 | def GetRicName(ricName): 57 | if 'data' in esg_universe: 58 | searchItem = list(filter(lambda data: data[1]==ricName, list(esg_universe['data']))) 59 | if len(searchItem)>0: 60 | return searchItem[0][2] 61 | return None 62 | 63 | 64 | if GetRicName('MSFT.O') is not None: 65 | print("MSFT.O is \""+ GetRicName("MSFT.O")+"\"") 66 | else: 67 | print("Unable to find name for MSFT.O") 68 | 69 | ricList="MSFT.O" 70 | esgScoreFullEndpoint="https://api.refinitiv.com/data/environmental-social-governance/v2/views/scores-full?universe=" 71 | resp=get(url=esgScoreFullEndpoint+ricList,headers={"Authorization": "Bearer " + accessToken}) 72 | if resp.status_code!=200: 73 | print("Status Code:",resp.status_code," Text:",dumps(loads(resp.text),indent=4)) 74 | exit() 75 | 76 | esg_object=loads(resp.text) 77 | 78 | 79 | import pandas as pd 80 | import numpy as np 81 | headers=esg_object['headers'] 82 | 83 | #Get column headers/titles using lambda 84 | titles=map(lambda header:header['title'], headers) 85 | dataArray=np.array(esg_object['data']) 86 | df=pd.DataFrame(data=dataArray,columns=titles) 87 | print(df) 88 | 89 | dataPlot=pd.DataFrame(df,columns=['Instrument','Period End Date','ESG Score','ESG Combined Score','Innovation Score']) 90 | dataPlot['Period End Date']= dataPlot['Period End Date'].str.split('-').str[0] 91 | #By default sorting pandas data frame using sort_values() or sort_index() creates a new data frame. 92 | #If you don’t want create a new data frame after sorting and just want to do the sort in place, 93 | #you can use the argument “inplace = True”. 94 | dataPlot.sort_values('Period End Date',ascending=True,inplace=True) 95 | dataPlot 96 | 97 | dataPlot.plot(x='Period End Date',y=['ESG Score','ESG Combined Score','Innovation Score'],figsize=(14,7)) 98 | dataPlot.plot(x='Period End Date',y=['ESG Score','ESG Combined Score','Innovation Score'],kind='bar',figsize=(14,7)) 99 | 100 | ricList="IBM,AMZN.O,MSFT.O,GOOGL.O,FB.O,APPL.O" 101 | esgฺBasicEndpoint="https://api.refinitiv.com/data/environmental-social-governance/v2/views/basic?universe=" 102 | resp=get(url=esgฺBasicEndpoint+ricList,headers={"Authorization": "Bearer " + accessToken}) 103 | if resp.status_code!=200: 104 | print("Status Code:",resp.status_code," Text:",dumps(loads(resp.text),indent=4)) 105 | exit() 106 | 107 | esg_BasicObject=loads(resp.text) 108 | 109 | import pandas as pd 110 | import numpy as np 111 | headers=esg_BasicObject['headers'] 112 | 113 | #Get column headers/titles using lambda 114 | titles=map(lambda header:header['title'], headers) 115 | 116 | basicDataArray=np.array(esg_BasicObject['data']) 117 | basicDf=pd.DataFrame(data=basicDataArray,columns=titles) 118 | 119 | if basicDf.empty is False: 120 | print(basicDf) 121 | 122 | 123 | co2= [val for sublist in np.array(basicDf.iloc[:,5:6]) for val in sublist] 124 | woman=[val for sublist in np.array(basicDf.iloc[:,6:7]) for val in sublist] 125 | instrument=[val for sublist in np.array(basicDf.iloc[:,0:1]) for val in sublist] 126 | print(co2) 127 | print(woman) 128 | print(instrument) 129 | instrumentorg=np.array([]) 130 | 131 | for val in instrument: 132 | if GetRicName(val) is None: 133 | instrumentorg=np.append(instrumentorg,val) 134 | else: 135 | instrumentorg=np.append(instrumentorg,GetRicName(val)) 136 | 137 | print(instrumentorg) 138 | 139 | #Uncomment below to plotgraph on supported environment. 140 | #df1 = pd.DataFrame({"Woman Managers":woman}, index=instrumentorg) 141 | #df1.plot.barh(y='Woman Managers') 142 | 143 | #df2 = pd.DataFrame({"CO2 Emission Total":co2}, index=instrumentorg) 144 | #df2.plot.barh(y='CO2 Emission Total',color=(0.5, 0.25, 0.15, 1)) 145 | -------------------------------------------------------------------------------- /images/bargraphmsft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LSEG-API-Samples/Example.RDP.Python.ESGGraphPlot/0e5589c331cf35ce7f19349a415f03b7b91d0ccd/images/bargraphmsft.png -------------------------------------------------------------------------------- /images/barhco2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LSEG-API-Samples/Example.RDP.Python.ESGGraphPlot/0e5589c331cf35ce7f19349a415f03b7b91d0ccd/images/barhco2.png -------------------------------------------------------------------------------- /images/barhwomanmanager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LSEG-API-Samples/Example.RDP.Python.ESGGraphPlot/0e5589c331cf35ce7f19349a415f03b7b91d0ccd/images/barhwomanmanager.png -------------------------------------------------------------------------------- /images/linegraphmsft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LSEG-API-Samples/Example.RDP.Python.ESGGraphPlot/0e5589c331cf35ce7f19349a415f03b7b91d0ccd/images/linegraphmsft.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.16.* 2 | matplotlib==3.* 3 | pandas --------------------------------------------------------------------------------