Historical Pricing

Tutorial Source Code

Python

Examples referenced

Last Update June 2024
Interpreter Python 3.11.x or greater
Pre-requisites

Familiarity with Python and a basic understanding of Jupyter Notebook.

Access Credentials

Quick Start

If accessing content from:

  • Desktop (Eikon 4.0.36 or greater / LSEG Workspace 1.8 or greater) 
  • Deployed Environment (ADS 3.2 or greater)

The majority of the examples are built to work within Jupyter Notebook.  Ensure this package is installed.


Overview

Whether accessing from the desktop or directly from the cloud, the LSEG Data Libraries provide ease-of-use interfaces to retrieve content defined within standard web-based APIs.  Built on top of the request-response paradigm, the library includes HistoricalPricing interfaces that allow developers to retrieve Intraday and Interday time-series historical pricing data available within the platform.

The following tutorial demonstrates the retrieval of time series pricing data defined within LDP Historical Pricing services.  Specifically, we'll show basic retrieval of Interday, intraday summaries data, as well as pricing events (i.e. trades, quotes) and discuss how the response data is collected and extracted. 

Time Series Intraday and Interday Summaries

The Historical Pricing Summaries interface defines an Interval specification that determines the time scale of data to retrieve from the back-end.  For example, if we're interested in Intraday intervals, we are presented with the options to choose 1-minute, 5-minute, 10-minute, 1-hour, etc time buckets.  Alternatively, if the interest is to select Interday intervals, we can choose 1-day, 1-week, 1-month, 1-year, etc.

    	
            

// Retrieve Intraday Summaries with 5-minute interval.  Specify to return only 2 rows. If count is committed it will default to 20

response = historical_pricing.summaries.Definition(

    "VOD.L", 

    count=2,

    interval=historical_pricing.Intervals.FIVE_MINUTES).get_data()

# Extract in DataFrame format

response.data.df

When the above cell is executed, the output should look something like this:

HIGH_1 LOW_1 OPEN_PRC TRDPRC_1 NUM_MOVES ACVOL_UNS HIGH_YLD LOW_YLD OPEN_YLD YIELD ... BID_NUMMOV ASK_HIGH_1 ASK_LOW_1 OPEN_ASK ASK ASK_NUMMOV MID_HIGH MID_LOW MID_OPEN MID_PRICE
2021-06-21 12:20:00 129.04 128.92 128.96 129.0 76 193249 None None None None ... 781 129.06 128.94 128.96 129.02 781 129.03 128.92 128.95 129.01
2021-06-21 12:25:00 129.06 128.98 129.0 129.0477 36 111281 None None None None ... 205 129.08 129.0 129.02 129.06 205 129.07 128.99 129.01 129.05

In addition to specifying the Intraday interval, the interface also provides a number of other properties, including the ability to select specific fields to pull down from the service, specifying the number of data items, a date range, etc.  By default, all fields will be returned from the backend service if no fields are specified. 

Note: The fields defined are based on the type of asset.  For example,  the time-series fields offered for equities will be different than those provided for fixed income instruments.

To choose interday summaries, this can also be done by selecting the interval.

    	
            

// Retrieve Interday Summaries with 1-day interval
// You can optionally supply a Field list to filter the response

response = historical_pricing.summaries.Definition(

    universe = "VOD.L",

    interval = historical_pricing.Intervals.DAILY,          # Supported intervals: DAILY, WEEKLY, MONTHLY, QUARTERLY, YEARLY.

    count = 10,

    fields = ["BID", "ASK", "OPEN_PRC", "HIGH_1", "LOW_1", "TRDPRC_1", "NUM_MOVES", "TRNOVR_UNS"]

).get_data()

# Extract in DataFrame format

response.data.df

When the above cell is executed, the output should look something like this:

  BID ASK OPEN_PRC HIGH_1 LOW_1 TRDPRC_1 NUM_MOVES TRNOVR_UNS
2021-05-28 128.3 128.32 129.34 129.78 127.8 128.5817 13553 11349667837.8438
2021-06-01 128.26 128.28 128.1 129.0 128.08 128.5197 12512 11143268243.21096
2021-06-02 127.72 127.74 128.3 128.5 127.34 127.72 14560 7016824685.11
2021-06-03 127.58 127.6 127.86 128.4 126.52 127.7 12033 8864127481.639999
2021-06-04 127.94 127.98 127.28 128.36 127.18 127.94 8614 4338906940.27
2021-06-07 129.14 129.16 128.44 130.0 128.16 129.14 9006 5387285439.8194
2021-06-08 128.56 128.58 129.12 130.08 128.14 129.09335 12613 7218512711.80521
2021-06-09 128.22 128.24 128.36 128.72 127.44 128.24 9354 5140731853.58015
2021-06-10 129.76 129.8 128.7 130.1 128.22 129.8 11314 9498990403.05283
2021-06-11 129.84 129.88 129.74 130.5 128.12 129.89 9761 6875091772.74794

Time Series Events (Quotes and Trades)

The Historical Pricing Events interface provides the ability to retrieve trades, quotes, or corrections for a specified instrument.  By choosing a specific event type, the backend will select the most recent events or select events based on a specified time range.

    	
            

// Retrieve tick pricing events.  Default: 20 rows of data. 
// You can optionally specify Fields as per the summaries call

response = historical_pricing.events.Definition("VOD.L").get_data()

# Extract in DataFrame format

response.data.df

Running the the above cell will generate:

EVENT_TYPE RTL SEQNUM TRDXID_1 TRDPRC_1 TRDVOL_1 VWAP BID BIDSIZE ASK ... TRNOVR_UNS NETCHNG_1 MMT_CLASS TR_TRD_FLG ACVOL_UNS OPEN_PRC HIGH_1 LOW_1 MID_PRICE QUALIFIERS
2021-06-21 15:21:32.209 quote 3696 5314167 <NA> <NA> <NA> <NA> 129.44 8675 129.48 ... <NA> None <NA> <NA> <NA> <NA> <NA> <NA> 129.46 [ASK_TONE]
2021-06-21 15:21:32.209 quote 3728 5314169 <NA> <NA> <NA> <NA> 129.44 15499 129.48 ... <NA> None <NA> <NA> <NA> <NA> <NA> <NA> 129.46 [BID_TONE]
2021-06-21 15:21:32.209 quote 3712 5314168 <NA> <NA> <NA> <NA> 129.44 14484 129.48 ... <NA> None <NA> <NA> <NA> <NA> <NA> <NA> 129.46 [BID_TONE]
2021-06-21 15:21:32.210 quote 3776 5314172 <NA> <NA> <NA> <NA> 129.44 15499 129.5 ... <NA> None <NA> <NA> <NA> <NA> <NA> <NA> 129.47 [ASK_TONE]
2021-06-21 15:21:32.210 quote 3792 5314173 <NA> <NA> <NA> <NA> 129.44 16998 129.5 ... <NA> None <NA> <NA> <NA> <NA> <NA> <NA> 129.47 [BID_TONE]
2021-06-21 15:21:32.210 quote 3808 5314174 <NA> <NA> <NA> <NA> 129.44 16998 129.5 ... <NA> None <NA> <NA> <NA> <NA> <NA> <NA> 129.47 [ASK_TONE]
2021-06-21 15:21:32.211 quote 3824 5314175 <NA> <NA> <NA> <NA> 129.46 351 129.5 ... <NA> None <NA> <NA> <NA> <NA> <NA> <NA> 129.48 [BID_TONE]

<Output Truncated>

 

In all code segments defined, the number of rows returned from the server is dependent on a number of criteria.  By specifying a count within the definition, the value represents the maximum number of data items returned. If the count is smaller than the total amount of data of the time range specified, some data (the oldest) will not be delivered. To retrieve all available data within the time range specified, this parameter should not be specified. The returned data could be less than the number requested if there are not enough data within the time range specified. If not specified, the count will default to 20 unless both the start and end parameters are also specified. The maximum returned data is 10,000. The minimum value for count is 1.

Data structure returned

Whether accessing summaries or events, the structure and format of the data returned are the same.  All request-reply responses will carry standard response details such as the success of the response, HTTP status details, which include reasons why the request may fail, and a data section containing details specific to the service.  The structure and format of the data returned from the Historical Pricing services contain a table representing the time series data.   

The following code segment determines if the request was successful, using a simple boolean property available within the response.  Upon success, we begin to extract and display details populated within the data.  Upon failure, the details of why the underlying HTTP request failed are displayed.

    	
            

# JSON format (display only 200 characters of headers + data to minimise output)

if (response.is_success):

    print(json.dumps(response.data.raw['universe'], indent=2),

          'Headers:',

          json.dumps(response.data.raw['headers'], indent=2)[0:200],

          'Data:',

          json.dumps(response.data.raw['data'], indent=2)[0:200])

else:

    print(response.http_status)

The output from the above code snippet (assuming the call was successful) :

{
"ric": "VOD.L"
} Headers: [
{
"name": "DATE_TIME",
"type": "string"
},
{
"name": "EVENT_TYPE",
"type": "string"
},
{
"name": "RTL",
"type": "number",
"decimalChar": "."
},
{
"name" Data: [
[
"trade",
4046,
"382893",
"SINT",
129.48,
9,
128.73737,
129.46,
3000,
129.48,
368,
"\u21e7",
null,
null,
null,
"594295566880137328"

Handling invalid requests

When using the get_data() method, in case of a server error, an exception could be raised.
For example, requesting an invalid RIC:

    	
            

try:

    response = historical_pricing.events.Definition("BADRIC").get_data()

    print(response.data.df)

except rd.errors.RDError as e:

    print("Error code :", e.code)

    print("Error message:", e.message)

Would output something like:

Error code : TS.Intraday.UserRequestError.90001
Error message: The universe is not found.

 

The above code snippets are just a few sample queries - the Historical Pricing interfaces defined within the LSEG Data Library for Python include other useful features based on the corresponding endpoint features. Refer to the TUT_2.1.01-HistoricalPricing notebook for additional examples.  In addition, we encourage the use of auto-complete within your Jupyter Notebook or Python editor to discover other useful capabilities.