A developer's Guide

Exploring the 
LSEG Workspace 
Corporate Actions Content Set

Ujjawal Khandelwal
Developer Advocate Developer Advocate

Libraries Used: lseg.data
Level: Intermediate

Introduction

Corporate actions are among the most common sources of data discontinuity in financial time series. A stock split, a dividend, or a merger can introduce breaks in price history that - if left unaddressed - propagate errors through every downstream calculation: returns, volatility, signals, and portfolio valuations.

This guide covers the full lifecycle of working with corporate actions using the LSEG Data Library for Python: from understanding what corporate actions are, to fetching events, applying adjustments, and safeguarding your pipelines against identifier changes.

Prerequisites:

  • Python 3.8+
  • LSEG Workspace (desktop) or valid Platform credentials
  • lseg-data library installed

01 - What Are Corporate Actions?

A corporate action is any event initiated by a company that materially changes its shareholders' position, its outstanding securities, or its capital structure. 'Material' here means measurable: share count, price per share, capital structure, or the investor's relationship with the company.

Why developers need to care:

Corporate actions break raw price series. Consider a stock trading at $800 on Tuesday that opens at $200 on Wednesday. In unadjusted data, this appears as a 75% decline. In reality, it was a 4-for-1 stock split - total market capitalisation unchanged, share count quadrupled, price quartered.

The challenge: unadjusted price data does not raise errors or warnings. It returns numbers that are systematically incorrect for any calculation that spans across a corporate action date. Most financial data bugs - incorrect returns, inflated volatility, false signals - trace back to corporate actions not being accounted for.

Corporate actions are classified as either mandatory (automatic, no shareholder action required) or voluntary (requires shareholder election to participate).

02 - Types of Corporate Actions

2.1 Mandatory Corporate Actions
These events affect all shareholders automatically - no action or election is required. The common ones are:

Type Description  Price Impact
Cash Dividend Company distributes earnings to shareholders on a per-share basis. Eligibility determined by the record date. Price typically drops by the dividend amount on ex-date
Stock Split A stock split is a corporate event which increases the number of a company’s shares, while simultaneously reducing its per share price, such that the market capitalization of the company remains the same before and after the event. Stock splits are quoted in terms of shares received to shares held. E.g., 4-for-1: each share becomes four, price quartered. Direct price reduction by split ratio
Reverse Stock Split Existing shares are consolidated to form new shares with a higher nominal value (where applicable). This is the opposite of a stock split and is also referred to as a “Reverse Stock Split”. In a reverse split, the shares of a company are decreased while its per-share-price is increased by the adjustment factor. Also, like a stock split, the overall market capitalization of the company remains unchanged by the event. Reverse Stock splits are quoted in terms of shares received to shares held.  Direct price increase by consolidation ratio
Bonus Issue Additional shares issued to existing shareholders at no cost, funded by capitalising retained earnings. Similar market effect to a split, but different accounting treatment. Price adjusts proportionally
Spin-Off pin-off represents a form of divestiture usually resulting in an independent company or in an existing company. The spunoff company takes assets, intellectual property, technology, and/or existing products from the parent organization and forms its own private or publicly listed company. Shares of the new organization are distributed to the equity shareholders of the parent organization, at a ratio established by the parent. The new company formed by this divestiture is called the “spun-off” entity. Spin-offs is also referred to as “demergers”.  Parent price adjusts; new entity begins trading
Merger & Acquisition Two companies combine. Shareholders of the acquired entity receive cash, shares of the acquirer, or both. The acquired ticker may cease to exist. Acquired ticker delisted; data continuity challenge

 

2.2 Voluntary Corporate Actions
These require shareholders to actively choose whether to participate. Non-participation is the default outcome. The common ones are:

Type Description Shareholder Options
Rights Issue A short-term privilege granted to common shareholders to purchase additional common shares, usually at a discount, from the company itself, at a stated price and within a specified time. Rights issues are either renounceable or non-renounceable. If the issue is renounceable, the shareholders can trade on their rights on the stock exchange and these rights are forfeited if the shareholder does not exercise. Rights are traded for a short period of time. Subscribe, sell the rights (if renounceable), or let them lapse
Tender Offer A buyer proposes to purchase shares at a premium over market price. Tender (sell) shares at the offered price, or reject and continue holding
Buyback (Share Repurchase) Offer to existing shareholders by the issuing company to repurchase equity or other securities convertible into equity. The objective of the offer is to reduce the number of outstanding equities.  These repurchased shares could either be retired by the company or retained as treasury stock, to be reissued at a later date. The share buyback can be either mandatory or voluntary.  Participate in the buyback, or hold and ignore the offer

03 - Key Dates

Every corporate action revolves around a set of critical dates that determine eligibility, price adjustment timing, and settlement. These apply across global markets.

Date Purpose
Declaration (Announcement) Date The company officially announces the corporate action, disclosing type, ratio, record date, payment date, and other terms.
Ex-Date The stock begins trading without the entitlement. Buyers on or after this date do not receive the benefit. Price typically adjusts on this date. Usually falls 1-2 business days before the record date (varies by market).
Record Date Shareholders registered on the company's books at the end of this day are eligible. Shares must be settled (not just traded) to qualify.
Payment (Effective) Date The benefit is delivered - cash, shares, rights, or other instruments.

 

Timeline example (Cash Dividend):

Declaration ──── Ex-Date ──── Record Date ──── Payment Date

   Apr 18                     May 30                  May 30                        Jun 30

 

Note: The relationship between ex-date and record date varies by market. In most markets, ex-date precedes record date by the settlement cycle (T+1 or T+2).

04 - Price Adjustments

The effect of Corporate Action event creates gap in current market price and historical market prices of the share and it misleads investors choice of buying/selling if not filled the gap. Adjustment factor is calculated and applied to fill the gap appropriately. Historical prices must be adjusted backwards.

How it works:

A stock trading at 800 undergoes a 4-for-1 split. Post-split price: 200. To create a continuous, comparable series, all historical prices before the split are divided by the split ratio (4). The 800 becomes 200 in the adjusted series.

Adjustment Factor:

LSEG provides an Adjustment Factor - a multiplier that can be applied backward through price history. This allows you to:

  • Convert unadjusted prices to adjusted prices: Adjusted Price = Unadjusted Price × Adjustment Factor
  • Maintain correct return calculations across event dates
  • Preserve data integrity in automated pipelines

The adjustment factors should be applied on Price Only or Pricing data (Price and Volume) & Per Share data (Dividends, Earnings, Shares). Adjustment type is also provided which indicate the factors should be adjusted on components for each event type. The adjustment types are

  • Capital Change (CCH) - This adjustment type indicates the adjustment factor should be applied on Pricing data (Price and Volume) & Per Share data (Dividends, Earnings, Shares). This event type is predominantly used where the shares outstanding value changes due to corporate action event. For example- Stock splits, consolidations, Rights issue (same stock), Priority Issue (same stock), Bonus Issue (Same stock) and Stock Dividend (Same stock)
  • Reuters Pricing Only (RPO) - This adjustment type indicates the adjustment factor should be applied on Pricing only. This type is predominantly used where there would not be change in the existing number of outstanding shares due to corporate action event. For example, Demergers, Rights issue (different stock), Priority Issue (different stock), Bonus Issue (different stock) and Stock Dividend (different stock), capital returns and so on.

Note: Refer section 11 for practical demo. 

Default behaviour: LSEG delivers adjusted prices by default. You do not need to do anything extra to get a clean, split-adjusted series. To retrieve raw unadjusted prices, you must explicitly pass Adjusted=0 as a field-level parameter. 

Both views have valid use cases:

Adjusted (default): Continuous series for return calculations, backtesting, technical analysis

Unadjusted (Adjusted=0): Actual traded prices, identifying corporate action dates visually, regulatory reporting

05 - Environment Setup

    	
            

# Install the LSEG Data Library (run once)

# pip install lseg-data

 

import lseg.data as ld

import pandas as pd

import matplotlib.pyplot as plt

from IPython.display import display
 

# Visual defaults

plt.rcParams['figure.figsize'] = (13, 6)

plt.rcParams['axes.grid'] = True

plt.rcParams['grid.alpha'] = 0.3

    	
            

# I am using the desktop session (requires LSEG Workspace running locally)

ld.open_session()

Tip: To identify the correct field names for any LSEG content set, use the Data Item Browser (DIB) available in Workspace. Filter by Corporate Action under content classification to browse all available fields, their descriptions, and supported parameters.

06 - Fetching Capital Change Events

Capital change events are corporate actions that directly affect shares - quantity, face value, or price. These include stock splits, bonus issues, and reverse splits.

The field TR.CACorpActEventType returns capital change events specifically. Below, we retrieve the complete split history for Apple (AAPL.O).

    	
            

share_splits = ld.get_data(

    universe=['AAPL.O'],

    fields=[

        'TR.CACorpActEventType',    # Type of capital change event

        'TR.CACorpActDesc',         # Description of the event

        'TR.CATermsOldShares',      # Old shares in ratio (e.g., 1 in a 4-for-1)

        'TR.CATermsNewShares',      # New shares in ratio (e.g., 4 in a 4-for-1)

        'TR.CAAnnouncementDate',

        'TR.CAExDate',

        'TR.CARecordDate',

        'TR.CAEffectiveDate',

        'TR.CAIsRescinded'          # Whether the action was subsequently revoked

    ],

    parameters={

        'SDate': '1950-01-01',

        'EDate': '2026-05-31',

        'CAEventType': 'SSP;SIS'    # SSP = Share Split, SIS = Scrip/Bonus Issue

    }

)

display(share_splits)

The CAEventType parameter accepts semicolon-separated codes to filter by event type. 

The full list of valid codes is available in the Data Item Browser (DIB) in the parameters section for the CAEventType field. Always verify codes against DIB, as they may vary by coverage.

You can pass multiple codes (e.g., 'SSP;SIS') or omit the parameter to retrieve all capital change events.

07 Adjusted vs. Unadjusted Prices

LSEG delivers adjusted prices by default - corporate actions are already accounted for. To retrieve raw (unadjusted) prices, pass Adjusted=0 as a field-level parameter. Below, we fetch both views for Apple to see the difference.

    	
            

# Fetch unadjusted close prices

price_unadj = ld.get_history(

    universe=['AAPL.O'],

    fields=['TR.CLOSEPRICE(Adjusted=0)'],  # 0 = unadjusted

    interval='1D',

    start='2000-01-01',

    end='2026-05-31'

)

 

# Fetch adjusted close prices

price_adj = ld.get_history(

    universe=['AAPL.O'],

    fields=['TR.CLOSEPRICE(Adjusted=1)'],  # 1 = adjusted

    interval='1D',

    start='2000-01-01',

    end='2026-05-31'

)

    	
            

fig, axes = plt.subplots(2, 1, figsize=(14, 10), sharex=True)

 

# Unadjusted

axes[0].plot(price_unadj.index, price_unadj['Close Price'], color='#d9534f', linewidth=0.8)

axes[0].set_title('AAPL — Unadjusted Close Price', fontsize=13, fontweight='bold')

axes[0].set_ylabel('Price (USD)')

axes[0].annotate('Visible price drops at\ncorporate action dates',

                 xy=(0.65, 0.75), xycoords='axes fraction',

                 fontsize=10, color='#d9534f', style='italic')

 

# Adjusted

axes[1].plot(price_adj.index, price_adj['Close Price'], color='#1a7f37', linewidth=0.8)

axes[1].set_title('AAPL — Adjusted Close Price', fontsize=13, fontweight='bold')

axes[1].set_ylabel('Price (USD)')

axes[1].set_xlabel('Date')

axes[1].annotate('Continuous series — corporate actions\nadjusted backward through history',

                 xy=(0.02, 0.80), xycoords='axes fraction',

                 fontsize=10, color='#1a7f37', style='italic')

 

plt.tight_layout()

plt.show()

Observations:

  • The unadjusted chart shows sudden price drops at each split date. These are not crashes - they are the raw traded prices before and after each corporate action. This view is useful for identifying when events occurred and analysing post-event price recovery.
  • The adjusted chart rewrites history so that the entire series is comparable on a single scale. This is the correct input for return calculations, moving averages, and backtesting.

Important: TR. Fields vs. Real-Time Pricing Fields

There are two different adjustment mechanisms depending on the type of field you use. This is a common source of confusion.

Field Type Example Fields Adjustment Control
TR. Fields (fundamental/reference) TR.CLOSEPRICE, TR.OPENPRICE Use inline parameter: TR.CLOSEPRICE(Adjusted=0) or (Adjusted=1)
Real-time pricing fields (non-TR.) TRDPRC_1, HIGH_1, LOW_1, OPEN_PRC Use the adjustments parameter in get_history()

 

For real-time pricing fields, the adjustments parameter accepts a list of correction types:

Value Meaning
CCH Capital Change (splits, bonus issues)
CRE Currency Redenomination
RTS LSEG TimeSeries adjustment (price + volume)
RPO LSEG Price Only adjustment (price only, not volume)
exchangeCorrection Exchange-level corrections
manualCorrection Analyst-made corrections
unadjusted No adjustments applied

 

    	
            

# Real-time pricing fields - adjustments parameter

# This applies CORAX (Corporate Actions) adjustments to non-TR fields

price_rt_adjusted = ld.get_history(

    universe=['AAPL.O'],

    fields=['TRDPRC_1', 'HIGH_1', 'LOW_1', 'OPEN_PRC', 'ACVOL_UNS'],

    adjustments=['exchangeCorrection', 'manualCorrection', 'CCH', 'CRE', 'RPO', 'RTS'],

    start='2020-08-25',

    end='2020-09-04'

)

 

print("Real-time pricing fields WITH adjustments (around 2020 split):")

display(price_rt_adjusted)

    	
            

# Same fields WITHOUT adjustments — raw traded prices

price_rt_unadjusted = ld.get_history(

    universe=['AAPL.O'],

    fields=['TRDPRC_1', 'HIGH_1', 'LOW_1', 'OPEN_PRC', 'ACVOL_UNS'],

    adjustments=['unadjusted'],

    start='2020-08-25',

    end='2020-09-04'

)

 

print("Real-time pricing fields WITHOUT adjustments (raw):")

display(price_rt_unadjusted)

08. Detecting Price Discontinuities

A practical use case:
programmatically detecting large overnight price moves in unadjusted data that likely correspond to corporate actions rather than genuine market moves.

    	
            

# Calculate daily returns on unadjusted prices

price_unadj_clean = price_unadj.dropna()  # variable from section 07

price_unadj_clean['Daily Return'] = price_unadj_clean['Close Price'].pct_change()

 

# Flag days with >30% absolute move (likely corporate actions, not market events)

threshold = 0.30

discontinuities = price_unadj_clean[

    price_unadj_clean['Daily Return'].abs() > threshold

].copy()

 

print(f"Detected {len(discontinuities)} price discontinuities exceeding {threshold:.0%} in unadjusted data:\n")

display(discontinuities[['Close Price', 'Daily Return']])

These detected dates should align with the split events retrieved in Section 6. This technique is useful for data quality checks - if discontinuities appear that do not correspond to known corporate actions, they may indicate data errors.

09 - Dividends

Dividend data includes announcement dates, ex-dates, payment dates, amounts, types (interim, final, special), and payment forms (cash, stock). Below, we retrieve the full dividend history for Infosys (INFY.NS).

    	
            

dividends = ld.get_data(

    universe=['INFY.NS'],

    fields=[

        'TR.DivAnnouncementDate',   # When the dividend was announced

        'TR.DivType',               # Interim, Final, Special

        'TR.DivPaymentType',        # Cash, Stock, etc.

        'TR.DividendFrequency',     # Annual, Semi-annual, Quarterly

        'TR.DivExDate',

        'TR.DivRecordDate',

        'TR.DivPayDate',

        'TR.DivAdjustedGross',      # Gross dividend amount (adjusted for splits)

        'TR.DivAdjustedNet',        # Net dividend amount (after withholding)

        'TR.DivOriginalCurr'        # Currency of dividend

    ],

    parameters={

        'SDate': '1950-01-01',

        'EDate': '2026-05-31',

        'CAEventType': 'SDI'        # SDI = Standard Dividend

    },

    header_type=ld.HeaderType.NAME   # Column headers match field names

)

 

print(f"Total dividend events: {len(dividends)}")

display(dividends.head(10))

display(dividends.tail(5))

9.1 - Dividend Pattern Visualization

A bubble chart showing dividend payments by month and year reveals the company's distribution pattern. Bubble size represents the dividend amount; colour indicates the dividend type.

    	
            

# Prepare data

div_viz = dividends.dropna(subset=['TR.DIVPAYDATE', 'TR.DIVADJUSTEDGROSS', 'TR.DIVTYPE']).copy()

div_viz['TR.DIVPAYDATE'] = pd.to_datetime(div_viz['TR.DIVPAYDATE'])

div_viz['YEAR'] = div_viz['TR.DIVPAYDATE'].dt.year

div_viz['MONTH_NAME'] = div_viz['TR.DIVPAYDATE'].dt.strftime('%b')

 

MONTH_ORDER = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',

               'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

MONTH_TO_X = {m: i for i, m in enumerate(MONTH_ORDER)}

div_viz['MONTH_X'] = div_viz['MONTH_NAME'].map(MONTH_TO_X)

 

# Bubble sizing

SIZE_SCALE = 30

MIN_SIZE = 30

div_viz['BUBBLE_SIZE'] = div_viz['TR.DIVADJUSTEDGROSS'] * SIZE_SCALE + MIN_SIZE

 

# Color by dividend type

div_types = div_viz['TR.DIVTYPE'].unique()

COLORS = plt.cm.Set2.colors

COLOR_MAP = {t: COLORS[i % len(COLORS)] for i, t in enumerate(div_types)}

 

# Plot

fig, ax = plt.subplots(figsize=(14, 11))

 

for dtype, group in div_viz.groupby('TR.DIVTYPE'):

    ax.scatter(

        group['MONTH_X'],

        group['YEAR'],

        s=group['BUBBLE_SIZE'],

        color=COLOR_MAP[dtype],

        alpha=0.7,

        edgecolors='black',

        linewidths=0.4,

        label=dtype

    )

 

ax.set_xticks(range(len(MONTH_ORDER)))

ax.set_xticklabels(MONTH_ORDER)

ax.set_yticks(sorted(div_viz['YEAR'].unique()))

ax.invert_yaxis()

ax.set_xlabel('Payment Month')

ax.set_ylabel('Year')

ax.set_title('INFY.NS — Dividend History (Month vs. Year)', fontsize=14, fontweight='bold')

ax.grid(axis='y', linestyle=':', linewidth=0.6, alpha=0.4)

ax.grid(axis='x', linestyle='--', linewidth=0.4, alpha=0.2)

leg = ax.legend(title='Dividend Type', bbox_to_anchor=(1.02, 1), loc='upper left')

for handle in leg.legend_handles:

    handle.set_sizes([80])

plt.tight_layout(rect=[0, 0, 0.85, 1])

plt.show()

9.2 - Annualised Dividend

To compare companies better & calculate yields, dividend periods need to be standardized. This is where annualized dividend becomes useful. LSEG provides annualized dividends, calculated using the following four methodologies:

Code Full Form Type Method
PMD Primary Market Default Auto Uses market/exchange default
IAD Indicated Annual Dividend Forward-looking Latest dividend x frequency
TTM Trailing Twelve Months Backward-looking Sum of last 12 months dividends
LFY Latest Financial Year Official Dividend from last financial year report

 

    	
            

# Fetching dividend data with different annualization methods

 

ld.get_data(

    universe=['INFY.NS','TCS.NS','WIPR.NS',],

    fields=['TR.AnnDivPrimaryAnnTaxStatus',

            'TR.AnnDivPrimaryAnnMethod',

            'TR.AnnDivDivCurr',

            'TR.ClosePrice',

            '(TR.AnnDivAdjustedGross/TR.ClosePrice)*100', # Dividend yield using default method

            'TR.AnnDivAdjustedGross', # default method

            'TR.AnnDivAdjustedGross(ANN=PMD)', # Adj Gross dividend annualized by default method

            'TR.AnnDivAdjustedGross(ANN=IAD)', # Forward looking adj annualized dividend

            'TR.AnnDivAdjustedGross(ANN=TTM)', # Trailing twelve months adj annualized dividend

            'TR.AnnDivAdjustedGross(ANN=LFY)' # Last fiscal year adj annualized dividend

    ],

    header_type = ld.HeaderType.NAME # to differentiate b/w fields with same name.

)

💡TIP: 

Instead of retrieving multiple fields and calculating metrics separately, you can embed calculations directly within your API query. This approach makes your requests more efficient and keeps your logic centralized.

10. Using Field-Level Parameters

The LSEG Data Library supports inline parameters on individual fields. This allows a single generic field to serve multiple purposes depending on the parameter passed - reducing the number of distinct field names you need to remember.

For example, TR.DivDate with the DateType parameter can return different dates:

  • DateType=PD → Payment Date
  • DateType=RD → Record Date
  • DateType=ED → Ex-Date
  • DateType=AD → Announcement Date
    	
            

# Using parameterized fields instead of separate field names

div_dates = ld.get_data(

    universe=['INFY.NS'],

    fields=[

        'TR.DivDate(DateType=AD)',   # Announcement Date

        'TR.DivDate(DateType=ED)',   # Ex-Date

        'TR.DivDate(DateType=RD)',   # Record Date

        'TR.DivDate(DateType=PD)'    # Payment Date

    ],

    parameters={

        'SDate': '2024-01-01',

        'EDate': '2026-05-31'

    },

    header_type=ld.HeaderType.NAME

)

display(div_dates)

💡TIP:

Each field listed in the Data Item Browser (DIB) shows its supported parameters. Field-level parameters (applied inline) override global parameters (applied in the parameters dict).

11. Applying Adjustment Factors Manually

Section 7 showed that LSEG delivers adjusted prices by default. Some workflows require storing unadjusted prices - for audit trails, regulatory reporting, or exchange settlement matching - and computing the adjusted series on demand.

LSEG provides two fields for adjustment factors:

Fields Returns
TR.CAAdjustmentFactor The per-event adjustment factor for each historical capital change event
TR.AdjmtFactorAdjustmentFactor (legacy field) The factor from the most recent split event only

Use TR.CAAdjustmentFactor when you need the full event history.

 

How factors work:

Each factor is event-specific and is applied backward - to prices before the corporate action date. Prices after the event are already at the post-event level and need no modification.

Different historical periods need different adjustments, depending on how many events occurred after that date:

Formula: Adjusted Price = Unadjusted Price × (product of factors for all events after that date)

Diagram:

    	
            

─── Zone 1 ───|── Split A ──|─── Zone 2 ───|── Split B ──|─── Zone 3 ───

              |  f_A = 0.5  |              |  f_B = 0.25 |

                                                         

  f_A × f_B applied         |  f_B applied               |  No adjustment

  to Zone 1 prices          |  to Zone 2 prices          |  (already current)

    	
            

# Fetch the adjustment factor for each historical capital change event

adj_factors = ld.get_data(

    universe=['AAPL.O'],

    fields=[

        'TR.CACorpActEventType',

        'TR.CAEffectiveDate',

        'TR.CAAdjustmentFactor',

        'TR.CAAdjustmentType',  # CCH or RPO (LPO is the new renamed output)

        'TR.CATermsOldShares',

        'TR.CATermsNewShares'

    ],

    parameters={

        'SDate': '1980-01-01',

        'EDate': '2026-05-31',

        'CAEventType': 'SSP;SIS'

    }

)

 

print("AAPL.O — per-event adjustment factors:")

display(adj_factors)

    	
            

# Verify: apply the 2020 4-for-1 split factor to unadjusted prices

# Ex-Date: 2020-08-31. Factor = 0.25 (from TR.CAAdjustmentFactor output above)

#

# Prices BEFORE 2020-08-31: multiply by 0.25 (one split is "ahead" of them)

# Prices ON/AFTER 2020-08-31: no adjustment needed (already at post-split level)

 

split_date = pd.Timestamp('2020-08-31')

split_factor = 0.25  # Read from adj_factors output above

 

window_unadj = ld.get_history(

    universe=['AAPL.O'],

    fields=['TR.CLOSEPRICE(Adjusted=0)'],

    interval='1D',

    start='2020-08-25',

    end='2020-09-04'

)

window_adj = ld.get_history(

    universe=['AAPL.O'],

    fields=['TR.CLOSEPRICE(Adjusted=1)'],

    interval='1D',

    start='2020-08-25',

    end='2020-09-04'

)

 

comparison = pd.DataFrame({

    'Unadjusted': window_unadj['Close Price'],

    'LSEG Adjusted': window_adj['Close Price']

})

comparison['Manual Adjusted'] = comparison.apply(

    lambda row: row['Unadjusted'] * split_factor if row.name < split_date else row['Unadjusted'],

    axis=1

)

comparison['Difference'] = (comparison['LSEG Adjusted'] - comparison['Manual Adjusted']).abs()

 

print("Verification: manually applied factor vs. LSEG adjusted series")

print("Difference should be near zero for pre-split dates, exactly zero for post-split.\n")

display(comparison.round(4))

Why 0.25 and not 1/224? The factor 1/224 accounts for all five AAPL splits combined (2×2×2×7×4). It only applies to prices from before 1987. Prices from 2020 only have one split "ahead" of them (the 4-for-1), so the correct factor is 0.25. Always use the factor that matches how many splits are after your price date.

12. Handling RIC Changes with PermIDs

Certain corporate actions - name changes, mergers, de-mergers, spin-offs - can result in RIC (Reuters Instrument Code) changes. A workflow hardcoded to a specific RIC will break when this happens.

PermIDs (Permanent Identifiers) provide a stable reference that persists across RIC changes. They are assigned to organisations, instruments, and individuals, and do not change regardless of corporate events.

Example: Meta Platforms (formerly Facebook)

When Facebook rebranded to Meta in 2021, the RIC changed from FB.OQ to META.OQ. Any pipeline referencing FB.OQ would stop receiving data.

    	
            

# Step 1: Get the Organisation PermID for the current RIC

org_permid = ld.get_data(

    universe=['META.OQ'],

    fields=['TR.OrganizationID']

)

print("Organisation PermID for META.OQ:")

display(org_permid)

    	
            

# Step 2: Use the PermID to find all historical RICs for the organisation

# Replace the PermID below with the value returned above

permid_value = '4297297477'  # Meta Platforms Inc.

 

all_rics = ld.get_history(

    universe=[permid_value],

    fields=['TR.RIC'],

    start='2000-01-01',

    end='2026-05-31'

)

print(f"All RICs associated with PermID {permid_value}:")

display(all_rics)

Best Practice:

PermID-Based Pipelines

For production workflows, store the Organisation PermID as your primary key rather than the RIC. If there are multiple venues or forms, then using RIC is ideal. 

13. Broader Corporate Events (TR.EventType)

The TR.CACorpActEventType field used above covers capital change events specifically - splits, bonus issues, and similar. But companies generate a much wider range of announcements: earnings releases, shareholder meetings, executive changes, M&A activity, and more.

For this broader scope, use the TR.EventType family of fields with the EventType parameter.

    	
            

# Fetch all corporate events for BHP over the last year

events = ld.get_data(

    universe=['BHP.AX'],

    fields=[

        'TR.EventStartDate',

        'TR.EventType',

        'TR.EventTitle',

        'TR.EventEndDate'

    ],

    parameters={

        'SDate': '-1Y',

        'EDate': '1D',

        'EventType': 'ALL'     # Returns all event types: earnings, M&A, dividends, meetings, etc.

    }

)

display(events)

The EventType parameter accepts:

  • ALL - all event types
  • Specific types like CV for company visits, or RES for earings release etc. 

This is useful when building event calendars, screening for upcoming catalysts, or monitoring corporate activity across a watchlist.

💡TIP:

When querying events for large universes (e.g., all ASX-listed companies), batch your requests into chunks to avoid timeouts:

14. Event Metadata: Status, IDs, and Forward-Looking Events

14.1 Event Status (Confirmed vs Estimated)

Corporate action dates can be confirmed (company-announced) or estimated. The field TR.EventStatus indicates this:

Value Meaning
False Date is confirmed by the company
True Date is estimated

This matters for forward-looking workflows - estimated dates shift frequently and should be treated as provisional.

 

14.2 Event ID

Each corporate action has a unique identifier (TR.EventEventID). Use it to:

- Deduplicate events when polling for updates

- Track lifecycle changes (announced → confirmed → completed → rescinded)

- Link related records across separate API calls

 

14.3 Rescinded Events

A corporate action can be announced and later cancelled. The field TR.CAIsRescinded returns True for withdrawn events. Always filter these out before applying adjustments - a rescinded split never took effect.

    	
            

# Fetch upcoming dividend events with status and event ID

upcoming_divs = ld.get_data(

    universe=['AAPL.O'],

    fields=[

        'TR.CAEventID',            # Unique event identifier

        'TR.DivExDate',

        'TR.DivPayDate',

        'TR.DivAdjustedGross',

        'TR.DivType',

        'TR.CADateStatus',         # True = estimated, False = confirmed

        'TR.CAIsRescinded'

    ],

    parameters={

        'SDate': '0D',             # From today

        'EDate': '1Y',             # Looking 1 year ahead

        'CAEventType': 'SDI'

    }

)

 

print("Upcoming dividends (with confirmation status and event ID):")

display(upcoming_divs)

    	
            

# Historical events with IDs — useful for tracking and deduplication

hist_events = ld.get_data(

    universe=['AAPL.O'],

    fields=[

        'TR.CAEventID',

        'TR.CACorpActEventType',

        'TR.CAEffectiveDate',

        'TR.CAAnnouncementDate',

        'TR.CADateStatus',

        'TR.CAIsRescinded'

    ],

    parameters={

        'SDate': '2014-01-01',

        'EDate': '2026-05-31',

        'CAEventType': 'SSP;SIS;SDI'

    }

)

 

print("Historical events with IDs and status:")

display(hist_events.head(10))

Important: Do not combine forward-looking and historical date ranges in the same request. The API behaves differently for estimated future events vs. confirmed past events. Query them separately.

14.4 Dividend Currency

For cross-border portfolios, the dividend currency matters for tax and FX conversion. The field TR.DivOriginalCurr returns the ISO currency code of the dividend payment. The difference between TR.DivAdjustedGross and TR.DivAdjustedNet represents withholding tax - relevant for international holdings.

15 - Summary & Resources

Key Takeaways

Topic Key Point
Adjusted by default LSEG delivers adjusted prices by default - use Adjusted=0 only when you need raw traded prices
Adjustment factors Per-event factors from TR.CAAdjustmentFactor; apply backward to prices before the event date
Adjustment Type The TR.CAAdjustmentType field indicates whether the adjustment type is CCH or RPO.
Zone-specific The factor for a price depends on how many splits occured after that date - not one cumulative number for all history
CAEventType Filters capital change events (splits, bonus issues, spin-offs). Verify codes in DIB
TR.EventType Covers broader corporate events: earnings, M&A, meetings, dividends, executive changes
Event Status TR.EventStatus distinguishes confirmed vs estimated dates- critical for forward-looking workflows
Event ID TR.EventEventID enables deduplication and lifecycle tracking across refreshes
Field parameters Inline parameters (e.g., DateType=PD) reduce complexity by reusing generic fields
RIC stability Use PermIDs as your primary key to survive RIC changes
Batching For large universes, split requests into chunks of ~50 RICs to avoid timeouts
Data validation Cross-check detected price discontinuities against known corporate action dates
 
Note: The article highlights some important aspects, but there are many additional details and fields that can still be explored. 
 
ISO 15022 Corporate Action Codes (SWIFT):
 
If your downstream systems require ISO 15022 messaging formats, these are available via LSEG DataScope Select (DSS) rather than the Workspace APIs used in this article. 
You can contact your LSEG Account Manager or LSEG Support for more information on DSS. 
DataScope Select provides corporate actions data in standardized ISO 15022 message formats, including MT564 (Notification) and MT568 (Narrative), which are widely used formats for distributing global corporate actions data.
 
Resources & Links
 
Resource URL
LSEG Data Library for Python LSEG Data Library for Python | Devportal
Data Item Browser (DIB) Available in LSEG Workspace - field discovery and parameter reference
Developer Community https://community.developers.lseg.com/
DataScope Select (DSS) LSEG DataScope Select - REST API | Devportal
LSEG Developer Portal https://developers.lseg.com/
 
Questions or feedback?

If you have questions, find an issue, or want to suggest improvements:

- Post on the Developer Community Q&A

- Contact your LSEG representative for access and licensing queries

  • Register or Log in to applaud this article
  • Let the author know how much this article helped you
If you require assistance, please contact us here