19. Corporate Actions

View dividends, bonus shares and rights issues for today or a date range, filtered by symbol and language

Objective

View corporate action events (dividends, bonus shares, rights issues...) for today or for a past date range, filtered by symbol and language. Matches Sample 19 in the tutorials repo (SDK v3.3.2). The sample is read-only: it places no orders and needs no OTP.

Flow

Auth (token cache) → Market Data API (Corporate Actions) → List of CorporateAction
  1. Call get_corporate_actions() for today's events
  2. Call get_corporate_actions_historical(from_date, to_date) for events in a date range (at most 5 days per call)
  3. Filter by symbol (symbol="SSI") and language (language="en")
  4. A range that is too wide is blocked by the SDK with a ValidationError before any server call; split the range into chunks of at most 5 days and call each chunk

Samples in the repo

LanguageFile
Pythonpython/sample_19_corporate_actions.py, python/sample_19_corporate_actions_async.py
Node.jsnode/sample_19_corporate_actions.js
.NETdotnet/Sample19CorporateActions.cs
Gogo/sample_19_corporate_actions.go

This page uses Python for illustration. Repo: ssi-fastconnect-v3-tutorials.

Prerequisites

  • Credentials in config.json, see Tutorial 1. The repo samples load the config through config.py (from config import config), so no credentials appear in the code.
  • A token with the scope data:corporateActions:get.
  • auth_helper.py (token cache, Tutorial 1). This sample only calls Market Data, so no OTP is needed.

Sample Code — Sync

The code below is taken verbatim from the repo sample (the Vietnamese comments and output text are kept as in the repo).

python/sample_19_corporate_actions.py
"""
Sample 19 — Sự kiện doanh nghiệp (Corporate actions)
=====================================================
Xem cổ tức, cổ phiếu thưởng, quyền mua... của các mã. Chỉ ĐỌC dữ liệu, không đặt lệnh.

Luồng:
  1. get_corporate_actions(): sự kiện của HÔM NAY
  2. get_corporate_actions_historical(from, to): sự kiện trong một khoảng ngày ở quá khứ
     (server cho tối đa 5 ngày mỗi lần gọi)
  3. Lọc theo mã (symbol) và ngôn ngữ ("vn" / "en")
  4. Khoảng ngày quá rộng bị SDK chặn tại client (ValidationError), không gọi server

Lưu ý:
  - SDK tự lấy hết các trang (pageSize 100), bạn không cần tự phân trang.
  - Mọi trường là chuỗi đúng như server gửi. Ngày có dạng YYYY/MM/DD, ratio KHÔNG được parse
    vì ý nghĩa phụ thuộc loại sự kiện. Trường server để trống (sự kiện mới công bố chưa có
    ngày GDKHQ/tỷ lệ) là "".
  - Ngày truyền vào phải đúng dạng YYYY/MM/DD (không dùng dấu '-').
  - "Hôm nay" lấy theo ngày của máy bạn.
"""

from datetime import datetime, timedelta

from ssi_sdk import Auth, Data, ValidationError
from auth_helper import ensure_auth
from config import config

DATE_FMT = "%Y/%m/%d"


def show(actions, limit=10):
    for a in actions[:limit]:
        print(
            f"  {a.symbol:<8} | {a.exchange:<6} | GDKHQ: {a.exright_date or '-':<10} "
            f"| Chốt: {a.record_date or '-':<10} | Phát hành: {a.issue_date or '-':<10} "
            f"| Tỷ lệ: {a.ratio or '-':<8} | {a.event_title}"
        )
    if len(actions) > limit:
        print(f"  ... còn {len(actions) - limit} sự kiện")


with Auth(config) as auth:
    ensure_auth(auth)

    with Data(auth) as data:
        # --- Bước 1: Sự kiện của hôm nay ---
        print("--- Sự kiện doanh nghiệp hôm nay ---")
        today_actions = data.market_data.get_corporate_actions()
        print(f"Tổng số sự kiện: {len(today_actions)}")
        show(today_actions)

        # --- Bước 2: Sự kiện trong 5 ngày gần nhất (tối đa 5 ngày cho mỗi lần gọi) ---
        today = datetime.now()
        from_date = (today - timedelta(days=4)).strftime(DATE_FMT)
        to_date = today.strftime(DATE_FMT)
        print(f"\n--- Sự kiện từ {from_date} đến {to_date} ---")
        range_actions = data.market_data.get_corporate_actions_historical(from_date, to_date)
        print(f"Tổng số sự kiện: {len(range_actions)}")
        show(range_actions)

        # --- Bước 3: Lọc theo mã, trả tiêu đề bằng tiếng Anh ---
        print("\n--- Sự kiện của mã SSI (tiếng Anh) ---")
        ssi_actions = data.market_data.get_corporate_actions_historical(
            from_date, to_date, symbol="SSI", language="en"
        )
        print(f"Tổng số sự kiện: {len(ssi_actions)}")
        show(ssi_actions)

        # --- Bước 4: Khoảng ngày quá rộng bị chặn tại SDK ---
        print("\n--- Khoảng 30 ngày (vượt giới hạn 5 ngày) ---")
        too_wide_from = (today - timedelta(days=30)).strftime(DATE_FMT)
        try:
            data.market_data.get_corporate_actions_historical(too_wide_from, to_date)
        except ValidationError as e:
            print(f"  SDK từ chối trước khi gọi server: {e}")
            print("  -> chia khoảng ngày thành các đoạn <= 5 ngày rồi gọi từng đoạn.")

        # --- Response Summary ---
        print("\n[Response] today_count|range_count|ssi_range_count")
        print(f"{len(today_actions)}|{len(range_actions)}|{len(ssi_actions)}")

Sample Code — Async

Async uses the same flow; steps 1-3 are independent, so they run in parallel with asyncio.gather.

python/sample_19_corporate_actions_async.py
"""
Sample 19 (Async) — Sự kiện doanh nghiệp (Corporate actions)
=============================================================
Xem cổ tức, cổ phiếu thưởng, quyền mua... của các mã. Chỉ ĐỌC dữ liệu, không đặt lệnh.

Luồng:
  1. get_corporate_actions(): sự kiện của HÔM NAY
  2. get_corporate_actions_historical(from, to): sự kiện trong một khoảng ngày ở quá khứ
     (server cho tối đa 5 ngày mỗi lần gọi)
  3. Lọc theo mã (symbol) và ngôn ngữ ("vn" / "en")
  4. Khoảng ngày quá rộng bị SDK chặn tại client (ValidationError), không gọi server

Bước 1-3 độc lập nên chạy song song bằng asyncio.gather.

Lưu ý: SDK tự lấy hết các trang. Mọi trường là chuỗi đúng như server gửi (ngày YYYY/MM/DD,
ratio không được parse, trường để trống là ""). Ngày truyền vào phải đúng dạng YYYY/MM/DD.
"""

import asyncio
from datetime import datetime, timedelta

from ssi_sdk import AsyncAuth, AsyncData, ValidationError
from auth_helper import ensure_auth_async
from config import config

DATE_FMT = "%Y/%m/%d"


def show(actions, limit=10):
    for a in actions[:limit]:
        print(
            f"  {a.symbol:<8} | {a.exchange:<6} | GDKHQ: {a.exright_date or '-':<10} "
            f"| Chốt: {a.record_date or '-':<10} | Phát hành: {a.issue_date or '-':<10} "
            f"| Tỷ lệ: {a.ratio or '-':<8} | {a.event_title}"
        )
    if len(actions) > limit:
        print(f"  ... còn {len(actions) - limit} sự kiện")


async def main():
    async with AsyncAuth(config) as auth:
        await ensure_auth_async(auth)

        async with AsyncData(auth) as data:
            today = datetime.now()
            from_date = (today - timedelta(days=4)).strftime(DATE_FMT)
            to_date = today.strftime(DATE_FMT)

            # --- Bước 1-3: Gọi song song ---
            today_actions, range_actions, ssi_actions = await asyncio.gather(
                data.market_data.get_corporate_actions(),
                data.market_data.get_corporate_actions_historical(from_date, to_date),
                data.market_data.get_corporate_actions_historical(
                    from_date, to_date, symbol="SSI", language="en"
                ),
            )

            print("--- Sự kiện doanh nghiệp hôm nay ---")
            print(f"Tổng số sự kiện: {len(today_actions)}")
            show(today_actions)

            print(f"\n--- Sự kiện từ {from_date} đến {to_date} ---")
            print(f"Tổng số sự kiện: {len(range_actions)}")
            show(range_actions)

            print("\n--- Sự kiện của mã SSI (tiếng Anh) ---")
            print(f"Tổng số sự kiện: {len(ssi_actions)}")
            show(ssi_actions)

            # --- Bước 4: Khoảng ngày quá rộng bị chặn tại SDK ---
            print("\n--- Khoảng 30 ngày (vượt giới hạn 5 ngày) ---")
            too_wide_from = (today - timedelta(days=30)).strftime(DATE_FMT)
            try:
                await data.market_data.get_corporate_actions_historical(too_wide_from, to_date)
            except ValidationError as e:
                print(f"  SDK từ chối trước khi gọi server: {e}")
                print("  -> chia khoảng ngày thành các đoạn <= 5 ngày rồi gọi từng đoạn.")

            # --- Response Summary ---
            print("\n[Response] today_count|range_count|ssi_range_count")
            print(f"{len(today_actions)}|{len(range_actions)}|{len(ssi_actions)}")


asyncio.run(main())

CorporateAction fields

FieldMeaning
symbolTicker symbol
event_titleEvent name
exright_dateEx-rights date
record_dateRecord date
issue_dateIssue / execution date
exchangeExchange, e.g. HOSE
ratioEvent ratio, as a string

Notes

  • At most 5 days per call: to_date must not be more than 5 days after from_date. To cover a longer period, split it into chunks of at most 5 days and call each chunk.
  • Every field is a string: the SDK keeps the values exactly as the server sends them. Dates look like YYYY/MM/DD; ratio is not parsed because its meaning depends on the event type.
  • A field can be an empty string "": a newly announced event may not have an ex-rights date or ratio yet (exright_date, ratio). The sample prints a.ratio or '-'. Do not assume every field has a value.
  • Checked before the server is called: the SDK validates the date format (YYYY/MM/DD, no -), from_date not after to_date, the 5-day maximum span, symbol and language. Any failure raises ValidationError and no request is sent.
  • language: "vn" (default) or "en"; it sets the language of event_title.
  • Symbol filter: symbol is one symbol (letters and digits only, up to 20 characters). Leave it out to get all symbols.
  • "Today" is your machine's date: get_corporate_actions() takes the current date from the machine running the code.
  • The SDK fetches every page for you: no manual paging.
  • Verification status: per the SDK 3.3.2 changelog, these two methods were written from the API documentation and unit-tested, but not yet run against the live server. If results differ from the API documentation, report it to SSI.
  • Endpoint, parameters and scope: data-corporateActions. Handling ValidationError, rate limits and server errors: Error Handling & Rate Limits.

On this page