{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Example usage of `sgfixedincome_pkg` (MAS API Client)\n", "\n", "This Jupyter Notebook vignette shows how to use `sgfixedincome_pkg`'s API client and related functions for working with the Monetary Authority of Singapore's (MAS) 'bonds and bills' endpoints. The functions and methods shown here are primarily found in `mas_api_client.py` and `consolidate.py`.\n", "\n", "## Disclaimer\n", "\n", "The API we query is not found in the official [MAS API catalogue](https://eservices.mas.gov.sg/apimg-portal/api-catalog), and there is thus no documentation for it. Instead, I found this API and its endpoints by using Google DevTools to see where the MAS [T-bill webpage](https://www.mas.gov.sg/bonds-and-bills/treasury-bills-statistics) and [SSB webpage](https://www.mas.gov.sg/bonds-and-bills/auctions-and-issuance-calendar/issuance-singapore-savings-bond?issue_code=GX24120F&issue_date=2024-12-02) pulls their data from (picture below). \n", "\n", "Whilst no API key or token is required to pull data from this API, do use it responsibly (avoid flooding the API with requests).\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup\n", "Let's first import the package and initialize the API client:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import sgfixedincome_pkg as sfi\n", "client = sfi.MAS_bondsandbills_APIClient()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## General fetch data method\n", "\n", "The `fetch_data()` method provides the most flexibility in fetching data from MAS bonds and bills API endpoints. Simply input the endpoint name and optionally include query parameters. \n", "\n", "In the example below, we query the `listbondsandbills` endpoint which provides information on MAS bonds and bills. Using input parameters, we retrieve details of the most recently auctioned MAS bill that had a cutoff yield of at least 4.1%. This bill turns out to be the 'MD24112N' bill issued on '2024-04-01' with a cutoff yield of 4.12%:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'success': True,\n", " 'result': {'total': 156,\n", " 'records': [{'issue_code': 'MD24112N',\n", " 'isin_code': 'SGXZ44349256',\n", " 'issue_no': '1',\n", " 'reopened_issue': 'N',\n", " 'raw_tenor': 25.0,\n", " 'auction_tenor': 4.0,\n", " 'auction_date': '2024-03-26',\n", " 'issue_date': '2024-04-01',\n", " 'first_issue_date': '2024-04-01',\n", " 'bill_bond_ind': 'bill',\n", " 'maturity_date': '2024-04-26',\n", " 'ann_date': '2024-03-25',\n", " 'rate': 0.0,\n", " 'coupon_date_1': None,\n", " 'coupon_date_2': None,\n", " 'product_type': 'M',\n", " 'sgs_type': 'U',\n", " 'total_amt_allot': '14100.00000000',\n", " 'amt_allot_non_cmpt_appls': '0.00000000',\n", " 'amt_allot_mas': '0.00000000',\n", " 'pct_cmpt_appls_cutoff': 98.05,\n", " 'pct_non_cmpt_appls_cutoff': 100.0,\n", " 'total_bids': 26201.713,\n", " 'bid_to_cover': 1.86,\n", " 'cutoff_yield': 4.12,\n", " 'cutoff_price': 99.718,\n", " 'median_yield': 3.87,\n", " 'median_price': 99.735,\n", " 'avg_yield': 3.61,\n", " 'avg_price': 99.753,\n", " 'auction_amt': 14100.0,\n", " 'intended_tender_amt': 0.0,\n", " 'accrued_int': 0.0,\n", " 'total_amount': 14100.0}]}}" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "response = client.fetch_data(\n", " endpoint=\"listbondsandbills\", \n", " params={\n", " \"rows\": 1, # Get the first row only\n", " \"filters\":\"bill_bond_ind:bill AND cutoff_yield:[4.1 TO *]\", \n", " \"sort\": \"auction_date desc\"\n", " }\n", ")\n", "response" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Built-in SSB methods and functions\n", "\n", "Using `fetch_data()` requires knowledge of the available endpoints and output structure (to know what parameters we could possibly input). However, since MAS does not provide documentation for its 'bondsandbills' endpoints, it may be time-consuming to figure that out.\n", "\n", "As such, this package has built in a number of methods that fetch data from the API which you may find useful. Let's first cover methods related to Singapore Savings Bonds (SSBs):" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'issue_code': 'GX25010E',\n", " 'isin_code': 'SGXZ30907869',\n", " 'auction_tenor': 10.0,\n", " 'issue_size': 600.0,\n", " 'amt_applied': 0.0,\n", " 'total_applied_within_limits': 0.0,\n", " 'amt_alloted': 0.0,\n", " 'rndm_alloted_amt': 0.0,\n", " 'rndm_alloted_rate': 0.0,\n", " 'cutoff_amt': 0.0,\n", " 'first_int_date': '2025-07-01',\n", " 'sb_int_1': '2024-01-01',\n", " 'sb_int_2': '2024-07-01',\n", " 'payment_month': 'Jan,Jul',\n", " 'issue_date': '2025-01-02',\n", " 'maturity_date': '2035-01-01',\n", " 'ann_date': '2024-12-02',\n", " 'last_day_to_apply': '2024-12-26',\n", " 'tender_date': '2024-12-27',\n", " 'start_of_redemption': '2024-12-02',\n", " 'end_of_redemption': '2024-12-26'}" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Get dictionary with details on the latest SSB\n", "client.get_latest_ssb_details()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instead of all the details of the latest SSB, we may only be interested in the issue code:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'GX25010E'" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Get the latest SSB's issue code as string\n", "client.get_latest_ssb_issue_code()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can get details on the interest rate of any given Singapore Savings Bond (SSB) issue by passing the issue code into `get_ssb_interest()`. Note that `yearX_return` values are simple averages of the coupon rates up to that year.\n" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'issue_code': 'GX25010E',\n", " 'year1_coupon': 2.73,\n", " 'year1_return': 2.73,\n", " 'year2_coupon': 2.82,\n", " 'year2_return': 2.77,\n", " 'year3_coupon': 2.82,\n", " 'year3_return': 2.79,\n", " 'year4_coupon': 2.82,\n", " 'year4_return': 2.8,\n", " 'year5_coupon': 2.82,\n", " 'year5_return': 2.8,\n", " 'year6_coupon': 2.85,\n", " 'year6_return': 2.81,\n", " 'year7_coupon': 2.9,\n", " 'year7_return': 2.82,\n", " 'year8_coupon': 2.95,\n", " 'year8_return': 2.84,\n", " 'year9_coupon': 2.99,\n", " 'year9_return': 2.85,\n", " 'year10_coupon': 3.01,\n", " 'year10_return': 2.86}" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Get interest rate details of SSB with issue code GX25010E\n", "client.get_ssb_interest(\"GX25010E\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instead of getting this long dictionary, we may simply be interested in the coupon rates for the SSBs. This can be extracted with `get_ssb_coupons()`:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2.73, 2.82, 2.82, 2.82, 2.82, 2.85, 2.9, 2.95, 2.99, 3.01]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Get coupon rate details of SSB with issue code GX25010E\n", "client.get_ssb_coupons(\"GX25010E\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Based on a list of SSB coupon rates, we may want to calculate the SSB monthly tenure rates in percentage per annum, assuming compounding. This can be done with `calculate_ssb_tenure_rates()`:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | Tenure | \n", "Rate | \n", "
|---|---|---|
| 0 | \n", "1 | \n", "2.76 | \n", "
| 1 | \n", "2 | \n", "2.76 | \n", "
| 2 | \n", "3 | \n", "2.76 | \n", "
| 3 | \n", "4 | \n", "2.75 | \n", "
| 4 | \n", "5 | \n", "2.75 | \n", "
| ... | \n", "... | \n", "... | \n", "
| 115 | \n", "116 | \n", "2.56 | \n", "
| 116 | \n", "117 | \n", "2.56 | \n", "
| 117 | \n", "118 | \n", "2.56 | \n", "
| 118 | \n", "119 | \n", "2.56 | \n", "
| 119 | \n", "120 | \n", "2.56 | \n", "
120 rows × 2 columns
\n", "| \n", " | Tenure | \n", "Rate | \n", "Deposit lower bound | \n", "Deposit upper bound | \n", "Required multiples | \n", "Product provider | \n", "Product | \n", "
|---|---|---|---|---|---|---|---|
| 0 | \n", "1 | \n", "2.76 | \n", "500 | \n", "195000 | \n", "500 | \n", "MAS | \n", "SSB GX25010E | \n", "
| 1 | \n", "2 | \n", "2.76 | \n", "500 | \n", "195000 | \n", "500 | \n", "MAS | \n", "SSB GX25010E | \n", "
| 2 | \n", "3 | \n", "2.76 | \n", "500 | \n", "195000 | \n", "500 | \n", "MAS | \n", "SSB GX25010E | \n", "
| 3 | \n", "4 | \n", "2.75 | \n", "500 | \n", "195000 | \n", "500 | \n", "MAS | \n", "SSB GX25010E | \n", "
| 4 | \n", "5 | \n", "2.75 | \n", "500 | \n", "195000 | \n", "500 | \n", "MAS | \n", "SSB GX25010E | \n", "
| ... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
| 115 | \n", "116 | \n", "2.56 | \n", "500 | \n", "195000 | \n", "500 | \n", "MAS | \n", "SSB GX25010E | \n", "
| 116 | \n", "117 | \n", "2.56 | \n", "500 | \n", "195000 | \n", "500 | \n", "MAS | \n", "SSB GX25010E | \n", "
| 117 | \n", "118 | \n", "2.56 | \n", "500 | \n", "195000 | \n", "500 | \n", "MAS | \n", "SSB GX25010E | \n", "
| 118 | \n", "119 | \n", "2.56 | \n", "500 | \n", "195000 | \n", "500 | \n", "MAS | \n", "SSB GX25010E | \n", "
| 119 | \n", "120 | \n", "2.56 | \n", "500 | \n", "195000 | \n", "500 | \n", "MAS | \n", "SSB GX25010E | \n", "
120 rows × 7 columns
\n", "| \n", " | Tenure | \n", "Rate | \n", "Deposit lower bound | \n", "Deposit upper bound | \n", "Required multiples | \n", "Product provider | \n", "Product | \n", "
|---|---|---|---|---|---|---|---|
| 0 | \n", "6 | \n", "3.0 | \n", "1000 | \n", "99999999 | \n", "1000 | \n", "MAS | \n", "T-bill BS24124Z | \n", "