Skip to content

About

An R interface to LSEG Workspace, Refinitiv Eikon, and Refinitiv DataStream

Topics

Resources

Stars

12 stars

Watchers

3 watching

Forks

Repository files navigation

Codecov test coverage R-CMD-check Installation Test

Overview

RefinitivR is an R interface to LSEG Workspace (formerly Refinitiv Eikon) and Refinitiv DataStream.

Just load and go — the package auto-detects your running terminal (LSEG Workspace on port 9000 or Eikon Desktop on port 9060) and connects on the first API call. No API key, no setup code, no connection objects to manage. Repeated requests can be served from an opt-in session-scoped cache with configurable TTLs.

  • Snapshot & historical data — rd_GetData(), rd_GetHistory(), rd_GetHistoricalPricing()
  • Real-time streaming — WebSocket-based live market data with callbacks (rd_get_streaming_data())
  • ESG, estimates & ownership — rd_GetESG(), rd_GetEstimates(), rd_GetOwnership()
  • Symbology & search — rd_ConvertSymbol(), RDPsearch(), RDPget_search_metadata()
  • News — rd_get_news_headlines(), rd_get_news_story(), rd_get_top_news()
  • Custom instruments — create, update, delete basket and formula instruments (rd_ManageCustomInstruments())
  • DataStream — via DatastreamDSWS2R (DataStreamConnect())
  • Robust under the hood — three-layer retry with exponential backoff, connection-reset recovery, automatic chunking, HTTP 429/503 handling, and progress reporting for large requests

Note (v0.2.0+): Python/reticulate support has been removed. All data retrieval now uses the JSON API exclusively. See the Changelog (NEWS.md) for details.

This package is in no way affiliated with Thomson Reuters, Refinitiv, Eikon, Datastream, or LSEG. A subscription to LSEG Workspace / Eikon and/or Datastream is required. Use at your own risk!

Installation

install.packages("pak")
pak::pak("GreenGrassBlueOcean/RefinitivR")
library(Refinitiv)

Quick Start

With LSEG Workspace (or Eikon Desktop) running, no explicit connection step is needed:

library(Refinitiv)

# Get snapshot data
rd_GetData(rics = "AAPL.O", fields = "TR.CompanyName")

# Get historical data
rd_GetHistory(universe = c("AAPL.O", "MSFT.O"))

Real-Time Streaming

stream <- rd_get_streaming_data(
  universe = "EUR=",
  fields = c("BID", "ASK", "OPEN_PRC")
)

stream$on_update(function(stream, instrument, fields) {
  cat(sprintf("%s: BID=%s, ASK=%s\n", instrument, fields$BID, fields$ASK))
})

stream$open()
Sys.sleep(10)
print(stream$get_latest_data())
stream$close()

Table of Contents

  1. Connecting to LSEG Workspace
  2. Real-Time Streaming
  3. Working with Refinitiv Data (RD)
  4. Legacy Eikon Functions
  5. Custom Instruments
  6. DataStream
  7. Caching
  8. Progress Reporting
  9. Building Custom Visualizations

Connecting to LSEG Workspace

No explicit connection step is needed. All API functions default to rd_connection(), which auto-detects the running terminal (LSEG Workspace on port 9000 or Refinitiv Eikon on port 9060) and caches a connection on first use.

Make sure LSEG Workspace (or Eikon Desktop) is running and online before calling any API function. After a terminal restart, call rd_connection(reset = TRUE) to force a fresh connection.

For headless, CI, or remote-terminal setups, you can pre-configure connection settings in .Renviron (read at package load, skipping terminal auto-detection):

REFINITIV_PORT=9000
REFINITIV_BASE_URL=http://localhost
REFINITIV_APP_KEY=DEFAULT_WORKSPACE_APP_KEY

Real-Time Streaming

The package includes a real-time streaming API for live market data using WebSocket connections.

Prerequisites

# Required packages (installed automatically)
install.packages(c("websocket", "later", "shiny", "data.table"))

Quick Example

library(Refinitiv)

stream <- rd_get_streaming_data(
  universe = "EUR=",
  fields = c("BID", "ASK")
)

stream$on_update(function(stream, instrument, fields) {
  cat(sprintf("[%s] BID: %s | ASK: %s\n", 
              instrument, fields$BID, fields$ASK))
})

stream$open()
Sys.sleep(10)
stream$close()

Multiple Instruments

stream <- rd_get_streaming_data(
  universe = c("EUR=", "GBP=", "JPY="),
  fields = c("BID", "ASK", "OPEN_PRC", "DSPLY_NAME")
)

Event Callbacks

# Refresh callback - called when initial data is received
stream$on_refresh(function(stream, instrument, fields) {
  cat(sprintf("Initial data for %s received\n", instrument))
})

# Update callback - called on every price update
stream$on_update(function(stream, instrument, fields) {
  # Process update
})

# Error callback - called on errors
stream$on_error(function(stream, error_message) {
  warning("Stream error: ", error_message)
})

Accessing Data

# Latest snapshot (all instruments)
latest <- stream$get_latest_data()

# Latest for specific instrument
eur_data <- stream$get_latest_data("EUR=")

# Full history (data.table)
history <- stream$get_data_history()

# Summary statistics
summary <- stream$get_summary()
summary_eur <- stream$get_summary(instrument = "EUR=")

Built-in Live Plotting

app <- stream$plot_live(field = "BID", instrument = "EUR=")
shiny::runApp(app)

Advanced Usage

# Enable debug logging
options(refinitiv_streaming_debug = TRUE)

# Create stream with custom manager
def <- rd_streaming_pricing$Definition$new(
  universe = "EUR=",
  fields = c("BID", "ASK")
)
stream <- def$get_stream()
stream$open()

Examples

Run the included examples:

# Quick example (~10 seconds)
source(system.file("examples", "streaming_quick_example.R", package = "Refinitiv"))

# Complete example (~30 seconds, all features)
source(system.file("examples", "streaming_complete_example.R", package = "Refinitiv"))

# Debug example (~15 seconds, with logging)
source(system.file("examples", "streaming_test_debug.R", package = "Refinitiv"))

Working with Refinitiv Data (RD)

Searching & Symbol Conversion

# Basic search
results <- RDPsearch(query = "AAPL.O")

# Advanced search with filters
Presidents <- RDPsearch(
  view = "People", 
  query = 'president',
  filter = "startswith(LastName,'H')",
  select = 'DocumentTitle',
  order_by = 'DocumentTitle asc',
  top = 20
)

# Robust multi-tiered symbol conversion (ISIN/CUSIP/SEDOL/RIC, bare tickers, delisted RICs)
rd_ConvertSymbol(
  symbols = c("US0378331005", "US5949181045"),
  from_symbol_type = "ISIN",
  to_symbol_type = "RIC"
)

Get History

# Simple timeseries
timeseries <- rd_GetHistory(universe = c("AAPL.O", "NVDA.O"))

# With fields and parameters
data <- rd_GetHistory(
  universe = c("GOOG.O", "AAPL.O"),
  fields = c("TR.Revenue", "TR.GrossProfit"),
  parameters = list("SDate" = "0CY", "Curn" = "CAD")
)

Get Data

ex1 <- rd_GetData(
  rics = c("MMM", "III.L"),
  fields = c(
    "TR.PE(Sdate=0D)/*P/E (LTM) - Diluted Excl*/", 
    "TR.CompanyName"
  )
)

Historical Pricing

# Daily data
daily <- rd_GetHistoricalPricing(
  universe = "VOD.L", 
  interval = "P1D",
  count = 20L
)

# Intraday (1-minute)
intraday <- rd_GetHistoricalPricing(
  universe = c("VOD.L", "AAPL.O"),
  interval = "PT1M", 
  count = 500L,
  sessions = c("pre", "normal", "post")
)

ESG, Consensus Estimates & Ownership

# ESG scores and measures
esg <- rd_GetESG(universe = c("AAPL.O", "MSFT.O"), view = "scores-full")

# I/B/E/S consensus estimates
estimates <- rd_GetEstimates(
  universe = "AAPL.O",
  view = "view-summary/annual",
  package = "standard"
)

# Institutional & insider ownership (with automatic pagination)
ownership <- rd_GetOwnership(
  universe = "AAPL.O",
  view = "consolidated/investors",
  limit = 50
)

News

# Headlines, full stories, and top news
headlines <- rd_get_news_headlines(query = "MSFT.O", limit = 5)
story <- rd_get_news_story(story_id = headlines$storyId[1])
top_news <- rd_get_top_news()

Working with the Legacy Eikon Functions

The legacy Eikon* functions now also default to rd_connection(), so no explicit connection is needed:

News

headlines <- EikonGetNewsHeadlines(query = "R:MSFT.O", count = 2)
stories <- EikonGetNewsStory(story_id = headlines$storyId)

Timeseries

Timeseries <- EikonGetTimeseries(
  rics = c("MMM", "III.L"),
  start_date = "2020-01-01T01:00:00",
  end_date = paste0(Sys.Date(), "T01:00:00")
)

Data Requests

Data <- EikonGetData(
  rics = c("MMM", "III.L"),
  Eikonformulas = c("TR.PE(Sdate=0D)/*P/E (LTM) - Diluted Excl*/", 
                     "TR.CompanyName")
)

Custom Instruments

Setup

# Get UUID from LSEG Workspace / Eikon: Help > About > User Details
RD <- RDConnect(UUID = "ABCDE-123456")

Create Simple Instrument

rd_ManageCustomInstruments(
  operation = "CREATE", 
  symbol = "testAAPLandAMZN",
  formula = "AAPL.O + AMZN.O"
)

rd_ManageCustomInstruments(operation = "GET", symbol = "testAAPLandAMZN")
rd_ManageCustomInstruments(
  operation = "UPDATE", 
  symbol = "testAAPLandAMZN",
  formula = "AAPL.O + 2 * AMZN.O"
)
rd_ManageCustomInstruments(operation = "DELETE", symbol = "testAAPLandAMZN")

Basket Instruments

basket <- CustomInstrumentBasketBuilder(
  RICs = c("AAPL.O", "AMZN.O"), 
  Weights = c(0.5, 0.5)
)

rd_ManageCustomInstruments(
  operation = "CREATE", 
  symbol = "InterestingBasket",
  basket = basket, 
  currency = "USD"
)

holidays <- CustomInstrumentHolidayBuilder(
  dates = c("2023-12-01", "2023-12-31"),
  reasons = c("Special Bank Holiday 1", "Special Bank Holiday 2")
)

rd_ManageCustomInstruments(
  operation = "UPDATE", 
  symbol = "InterestingBasket",
  holidays = holidays
)

Utilities

AllActiveCustomInstruments <- rd_SearchCustomInstruments()
RealInstrumentName <- CorrectCustomInstrument("InterestingBasket")

DataStream

DatastreamUserName <- "Your datastream username"
DatastreamPassword <- "Your datastream password"
DataStream <- DataStreamConnect(DatastreamUserName, DatastreamPassword)

DSResult <- DataStream$snapshotRequest(
  instrument = c("ABF", "RIO", "WPP"),
  datatype = "P",
  requestDate = "0D"
)

For further details, see DatastreamDSWS2R.


Caching

All data retrieval functions support opt-in session-scoped caching to avoid redundant API calls:

# Enable caching globally (uses per-function default TTLs, typically 300 s)
options(refinitiv_cache = TRUE)

# Or enable per call
rd_GetData(rics = "AAPL.O", fields = "TR.CompanyName", cache = TRUE)

# Custom TTL (seconds)
rd_GetHistory(universe = "AAPL.O", cache = 600)

# Inspect and clear
rd_CacheInfo()
rd_ClearCache()

Caching is purely in-memory and scoped to the current R session — restarting R or calling rd_ClearCache() wipes all cached results.


Progress Reporting

Multi-chunk requests (large instrument universes, multi-query news, etc.) automatically show compact progress messages:

[RefinitivR] 500 instruments, 500 data points, 3 chunks
[RefinitivR] EikonGetData: Chunk 1/3 done (167 items, 0.3s)
[RefinitivR] EikonGetData: Chunk 2/3 done (167 items, 0.3s)
[RefinitivR] EikonGetData: Chunk 3/3 done (166 items, 0.3s)
[RefinitivR] EikonGetData: Download complete: 3/3 chunks succeeded in 2.5s

Single-instrument requests stay silent (one-chunk rule). Server-side polling and retriable errors always report status regardless of mode.

Control progress output with options(refinitiv_progress = ...) or the REFINITIV_PROGRESS environment variable in .Renviron:

Value Behavior
TRUE (default) Compact progress for multi-chunk requests
FALSE Silent
"verbose" Compact progress + full debug dumps
# Disable globally
options(refinitiv_progress = FALSE)

# Or per-call
rd_GetData(rics = large_universe, fields = fields, verbose = FALSE)

# Or via .Renviron (read at package load)
# REFINITIV_PROGRESS=FALSE

All output uses message(), so suppressMessages() works as expected.


Building Custom Visualizations

The streaming API provides several ways to build custom visualizations:

Using Built-in plot_live()

stream <- rd_get_streaming_data(universe = "EUR=", fields = c("BID", "ASK"))
stream$open()

app <- stream$plot_live(field = "BID", instrument = "EUR=")
shiny::runApp(app)

Custom Shiny App

library(shiny)
library(Refinitiv)

stream <- rd_get_streaming_data(universe = "EUR=", fields = c("BID", "ASK"))
stream$open()

ui <- fluidPage(
  titlePanel("Custom Live Stream"),
  plotOutput("live_plot"),
  verbatimTextOutput("stats")
)

server <- function(input, output, session) {
  output$live_plot <- renderPlot({
    invalidateLater(1000, session)
    history <- stream$get_data_history()
    if (nrow(history) > 0) {
      plot(history$timestamp, history$BID, 
           type = "l", xlab = "Time", ylab = "BID",
           main = "EUR/USD Bid Price")
    }
  })
  
  output$stats <- renderText({
    latest <- stream$get_latest_data("EUR=")
    paste("Latest BID:", latest$BID)
  })
}

shinyApp(ui, server)

Static Plots with ggplot2

library(ggplot2)

stream <- rd_get_streaming_data(universe = "EUR=", fields = c("BID", "ASK"))
stream$open()
Sys.sleep(30)
stream$close()

history <- stream$get_data_history()

ggplot(history, aes(x = timestamp, y = BID)) +
  geom_line() +
  labs(title = "EUR/USD Bid Price Over Time",
       x = "Time", y = "BID Price") +
  theme_minimal()

Best Practices

  1. Always close streams when done to free resources
  2. Use callbacks for real-time updates instead of polling
  3. Filter history for large datasets before plotting
  4. Handle errors in callbacks to prevent crashes
  5. Use later::run_now() in long-running scripts to process events

Examples

Example scripts are included in the package:

list.files(system.file("examples", package = "Refinitiv"))
source(system.file("examples", "streaming_quick_example.R", package = "Refinitiv"))

License

See LICENSE file.


Acknowledgments

  • Uses DatastreamDSWS2R for DataStream connections
  • Built for stability and robustness with automatic retries and chunking

About

An R interface to LSEG Workspace, Refinitiv Eikon, and Refinitiv DataStream

Topics

Resources

Stars

12 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages