Tutorial Source Code |
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. If accessing content from:
The majority of the examples are built to work within Jupyter Notebook. Ensure this package is installed. |
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.
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 |
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.
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"
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.