Historical BOK (BOK_BASE_RATE) Rates

Historical BOK (BOK_BASE_RATE) Rates

You need reliable, machine-readable history for the Bank of Korea’s policy rate to backtest strategies, reprice loans, or drive dashboards. By the end of this article, you’ll query, analyze, and export historical BOK_BASE_RATE data from the Interest Rates API, build OHLC series for charting, and handle date/frequency edge cases correctly in your applications.

Understand BOK_BASE_RATE and how it’s expressed

BOK_BASE_RATE is the Bank of Korea Base Rate symbol in the Interest Rates API. It belongs to the central_bank category and is denominated in KRW. The series is monthly in nature, but the API can represent it on a daily grid for convenience (see the frequency note in examples below). Values are quoted as percentages (for example, a JSON value of 3 means 3% annualized).

Illustration: Historical BOK (BOK_BASE_RATE) Rates

Effective date handling matters: for monthly symbols, a specific decision date (or the last day with data in a given month) determines the rate for that month. When you request a point-in-time value using a date that falls on a weekend or holiday, the API uses the last day with data within that month. When using the time series endpoint, you may see a daily frequency representation in the response to simplify charting, with the same monthly rate repeated across business days until updated by the next decision.

For discovery, documentation, and more endpoints, visit Try Interest Rates API, Explore Interest Rates API features, and Get started with Interest Rates API. When you’re ready to build, you can also Register for an API key and consult the MCP reference.

Start from the latest BOK_BASE_RATE

Before requesting long histories, confirm the current rate and its effective date. The Interest Rates API returns both the value and a per-symbol dates map indicating the effective date used for each symbol.

Official cURL example

curl -s "https://interestratesapi.com/api/v1/latest?api_key=YOUR_API_KEY&symbols=BOK_BASE_RATE"

Official JSON example

{
    "success": true,
    "date": "2026-09-30",
    "base": "KRW",
    "rates": {
        "BOK_BASE_RATE": 3
    },
    "dates": {
        "BOK_BASE_RATE": "2026-09-30"
    },
    "currencies": {
        "BOK_BASE_RATE": "KRW"
    },
    "base_filter_note": null
}

How to read this:

  • rates.BOK_BASE_RATE is 3, which represents 3% annualized.
  • dates.BOK_BASE_RATE is "2026-09-30", the date of the value used for this symbol.
  • currencies.BOK_BASE_RATE is "KRW", the base currency of the rate.

Cache the latest response for short intervals (for example, several minutes to an hour) depending on your refresh needs. Central bank policy rates generally change infrequently relative to intraday markets; reducing duplicate traffic helps avoid 429 throttling and keeps your dashboards responsive.

Multi‑year history via /timeseries

For backtesting and analytics, the /timeseries endpoint is your primary tool. Specify a start and end date and the BOK_BASE_RATE symbol.

cURL

Python (requests)

import requests

url = "https://interestratesapi.com/api/v1/timeseries"
params = dict(
start="2025-10-18",
end="2026-10-18",
symbols="BOK_BASE_RATE",
api_key="YOUR_API_KEY",
)
resp = requests.get(url, params=params, timeout=30)
resp.raise_for_status()
data = resp.json()
# data["rates"]["BOK_BASE_RATE"] is a date-keyed dict
# data["frequencies"]["BOK_BASE_RATE"] may show 'daily' if values are carried per business day
# data["currencies"]["BOK_BASE_RATE"] is 'KRW'

JavaScript (fetch)

const response = await fetch(
"https://interestratesapi.com/api/v1/timeseries?start=2025-10-18&end=2026-10-18&symbols=BOK_BASE_RATE&api_key=YOUR_API_KEY"
);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
// data.rates.BOK_BASE_RATE is an object of date -> value (percent) pairs

PHP

<?php
$base = "https://interestratesapi.com/api/v1/timeseries";
$query = http_build_query([
"start" => "2025-10-18",
"end" => "2026-10-18",
"symbols" => "BOK_BASE_RATE",
"api_key" => "YOUR_API_KEY"
]);
$resp = file_get_contents("$base?$query");
if ($resp === false) {
throw new Exception("Request failed");
}
$data = json_decode($resp, true);
// $data["rates"]["BOK_BASE_RATE"] is your date-indexed series
?>

Timeseries JSON example

Notes for implementation:

  • Frequency: Although BOK_BASE_RATE is a monthly policy rate, the API may deliver a daily series with the latest monthly rate repeated across business days. Always check frequencies.BOK_BASE_RATE to understand how to resample data in your pipeline.
  • Missing dates: Not all calendar days appear (weekends/holidays). Use forward-fill when aggregating to month-end, or use OHLC to get open/high/low/close per period reliably.
  • Range planning: For multi-year spans, segment your requests by year or quarter if you need partial refresh caching. Store results and only refresh the most recent periods where revisions can occur.

For documentation on all query parameters, visit the Explore Interest Rates API features page, and see the MCP reference.

Point‑in‑time values with /historical

Use /historical for a specific date lookup. For monthly symbols like BOK_BASE_RATE, the API uses the last day with data in that month if you pass any date within the same month. This makes it robust to weekends and holidays.

cURL

Python (requests)

import requests

r = requests.get(
"https://interestratesapi.com/api/v1/historical",
params={"date": "2025-06-15", "symbols": "BOK_BASE_RATE", "api_key": "YOUR_API_KEY"},
timeout=30
)
r.raise_for_status()
hist = r.json()
# hist["rates"]["BOK_BASE_RATE"] is the value for June 2025 (last day with data within that month)

JavaScript (fetch)

const res = await fetch(
"https://interestratesapi.com/api/v1/historical?date=2025-06-15&symbols=BOK_BASE_RATE&api_key=YOUR_API_KEY"
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const hist = await res.json();
// hist.rates.BOK_BASE_RATE is the June 2025 value

PHP

<?php
$base = "https://interestratesapi.com/api/v1/historical";
$params = http_build_query([
"date" => "2025-06-15",
"symbols" => "BOK_BASE_RATE",
"api_key" => "YOUR_API_KEY"
]);
$json = file_get_contents("$base?$params");
$data = json_decode($json, true);
// $data["rates"]["BOK_BASE_RATE"] contains the monthly value
?>

Historical JSON example

Implementation tips:

  • Normalize monthly series to month-end to make time-based joins predictable.
  • If your pricing pipeline needs the rate “as of a specific day,” pin to /historical with that day; the service ensures the correct monthly vintage is returned.

Analyze changes with /fluctuation

To summarize rate moves between two dates, the /fluctuation endpoint returns start_value, end_value, absolute and percent change, and the observed high/low within the range.

cURL

Python (requests)

import requests

fl = requests.get(
"https://interestratesapi.com/api/v1/fluctuation",
params={"start": "2025-10-18", "end": "2026-10-18", "symbols": "BOK_BASE_RATE", "api_key": "YOUR_API_KEY"},
timeout=30
).json()

stats = fl["rates"]["BOK_BASE_RATE"]
# stats has keys: start_date, end_date, start_value, end_value, change, change_pct, high, low

JavaScript (fetch)

const flRes = await fetch(
"https://interestratesapi.com/api/v1/fluctuation?start=2025-10-18&end=2026-10-18&symbols=BOK_BASE_RATE&api_key=YOUR_API_KEY"
);
const flData = await flRes.json();
const stats = flData.rates.BOK_BASE_RATE;
// Use stats.change and stats.change_pct for summaries

PHP

<?php
$q = http_build_query([
"start" => "2025-10-18",
"end" => "2026-10-18",
"symbols" => "BOK_BASE_RATE",
"api_key" => "YOUR_API_KEY"
]);
$resp = file_get_contents("https://interestratesapi.com/api/v1/fluctuation?$q");
$data = json_decode($resp, true);
$stats = $data["rates"]["BOK_BASE_RATE"];
?>

Fluctuation JSON example

Computing spreads and payments without hard-coded numbers:

  • Spread between two rates rA and rB from /latest: spread = rA − rB. Use the “rates” object from /latest for both symbols and subtract.
  • Monthly simple-interest payment estimate for principal P, annual rate r, term T months: monthly_interest = (r / 100) * (P / 12), payment ≈ (P / T) + monthly_interest. For amortized loans use: payment = P * (i * (1 + i)^T) / ((1 + i)^T − 1) with i = (r / 100) / 12.

If you need a ready-made comparison, the /convert endpoint returns total interest for a simple loan at each symbol’s latest rate.

Loan comparison example (JSON)

Build candlesticks with /ohlc for charting

For visualization and period aggregation, /ohlc computes open, high, low, and close over weekly, monthly, or quarterly periods from the dailyized series. This is ideal for policy rate dashboards where you want monthly candles that reflect all business days in a month.

cURL

Python (requests)

import requests

ohlc = requests.get(
"https://interestratesapi.com/api/v1/ohlc",
params={"symbols": "BOK_BASE_RATE", "period": "monthly", "start": "2025-10-18", "end": "2026-10-18", "api_key": "YOUR_API_KEY"},
timeout=30
).json()
rows = ohlc["rates"]["BOK_BASE_RATE"]
# rows is a list of {"period": "YYYY-MM", "open": ..., "high": ..., "low": ..., "close": ..., "data_points": N}

JavaScript (fetch)

const ohlcRes = await fetch(
"https://interestratesapi.com/api/v1/ohlc?symbols=BOK_BASE_RATE&period=monthly&start=2025-10-18&end=2026-10-18&api_key=YOUR_API_KEY"
);
const ohlcData = await ohlcRes.json();
const candles = ohlcData.rates.BOK_BASE_RATE;

PHP

<?php
$params = http_build_query([
"symbols" => "BOK_BASE_RATE",
"period" => "monthly",
"start" => "2025-10-18",
"end" => "2026-10-18",
"api_key" => "YOUR_API_KEY"
]);
$resp = file_get_contents("https://interestratesapi.com/api/v1/ohlc?$params");
$ohlc = json_decode($resp, true);
$candles = $ohlc["rates"]["BOK_BASE_RATE"];
?>

OHLC JSON example

data_points indicates how many business-day observations underlie that candle. For a monthly policy rate, you may see repeated values and an occasional step change when a decision occurs within a period.

Plotly candlestick integration (browser)

<div id="chart"></div>
<script type="module">
import Plotly from "https://cdn.jsdelivr.net/npm/[email protected]/+esm";

async function loadCandles() {
const url = "https://interestratesapi.com/api/v1/ohlc?symbols=BOK_BASE_RATE&period=monthly&start=2024-01-01&end=2026-12-31&api_key=YOUR_API_KEY";
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
const rows = json.rates.BOK_BASE_RATE;

const x = rows.map(r => r.period + "-01"); // anchor to first of month
const open = rows.map(r => r.open);
const high = rows.map(r => r.high);
const low = rows.map(r => r.low);
const close= rows.map(r => r.close);

const trace = {
x, open, high, low, close, type: "candlestick",
increasing: { line: { color: "#2ca02c" } },
decreasing: { line: { color: "#d62728" } }
};

const layout = { title: "BOK Base Rate — Monthly OHLC", yaxis: { title: "% (annualized)" } };
Plotly.newPlot("chart", [trace], layout, {responsive: true});
}

loadCandles().catch(console.error);
</script>

Python data pipeline: fetch → DataFrame → CSV/Parquet

The following end-to-end script downloads a multi-year BOK_BASE_RATE time series, normalizes to month-end, and writes CSV and Parquet for downstream analytics.

import os
import io
import json
import requests
import pandas as pd

API_KEY = os.environ.get("INTERESTRATES_API_KEY", "YOUR_API_KEY")

def fetch_timeseries(start, end, symbol="BOK_BASE_RATE"):
url = "https://interestratesapi.com/api/v1/timeseries"
params = {"start": start, "end": end, "symbols": symbol, "api_key": API_KEY}
r = requests.get(url, params=params, timeout=60)
r.raise_for_status()
return r.json()

def to_dataframe(ts_json, symbol="BOK_BASE_RATE"):
series = ts_json["rates"][symbol] # date -> value
df = pd.DataFrame(
[(pd.to_datetime(d), v) for d, v in series.items()],
columns=["date", "rate_pct"]
).sort_values("date").set_index("date")
# The API may provide a dailyized series. For monthly analysis, take month-end:
monthly = df.resample("M").last() # last available day in month
monthly.index.name = "month_end"
return df, monthly

def main():
ts = fetch_timeseries("2015-01-01", "2026-12-31")
daily_df, monthly_df = to_dataframe(ts)

# Save full dailyized representation
daily_df.to_csv("bok_base_rate_daily.csv", float_format="%.6f")
daily_df.to_parquet("bok_base_rate_daily.parquet")

# Save month-end normalized series
monthly_df.to_csv("bok_base_rate_monthly.csv", float_format="%.6f")
monthly_df.to_parquet("bok_base_rate_monthly.parquet")

print("Rows (dailyized):", len(daily_df))
print("Rows (month-end):", len(monthly_df))

if __name__ == "__main__":
main()

Pipeline guidance:

  • Use resample("M").last() to align to month-end, matching the API’s “last day with data within that month” behavior for monthly symbols.
  • Store both dailyized and month-end files. Dailyized data helps build OHLC or event-aligned charts; month-end is ideal for economic models and rate-of-change calculations.
  • Cache the most recent 12–24 months separately to limit re-fetching immutable historical years.

Operational details: frequency, business days, caching, and errors

Publication cadence: The Bank of Korea Base Rate is a policy rate that typically changes following scheduled meetings or decisions rather than daily. In the Interest Rates API, the symbol is monthly; nevertheless, the service may return a daily grid for easier charting. Rely on the frequencies object to know what you received.

Business days: Time series may include only business days. If you require a calendar index, forward-fill from the last available observation to maintain continuity for certain models, or use OHLC to aggregate by month without manual day handling.

Caching and retries:

  • Cache latest lookups for minutes to hours since policy rates are infrequent movers.
  • Cache immutable history by year or quarter and refresh only the most recent period where revisions are possible.
  • Handle 429 (“Request quota exhausted”) using the Retry-After header and X-RateLimit-* headers to back off appropriately.

Error handling quick map:

  • 401: Missing or invalid api_key. Ensure you pass api_key as a query parameter, not a header.
  • 403: Account without active plan.
  • 404: No symbols matched or no data for the requested date/range. Some 404s include a details field with available ranges.
  • 422: Validation error (date format, invalid symbol).
  • 429: Quota exhausted; respect Retry-After.

Always use HTTPS GET with the base URL https://interestratesapi.com/api/v1/ and append api_key=YOUR_API_KEY to every request. For deeper reference, check the MCP docs.

Discoverability: check /symbols to validate BOK_BASE_RATE

To browse available central bank symbols or confirm identifiers programmatically, use /symbols. This is helpful in pipelines that need to validate configuration before fetching data.

cURL (filtering central bank KRW is not required; shown here as a pattern)

From the returned list, ensure "BOK_BASE_RATE" appears as expected. Only use the exact identifiers from the available symbols list provided by the API.

Reading effective dates correctly

Latest endpoint responses include a dates object keyed by symbol, reflecting the effective date of each rate. For historical and time series extraction, expect the last business day with data within the month to represent the monthly rate. When reconciling with your own event calendars, map decision dates to the observed step changes in the series.

Units and math recap:

  • All values are in percent per annum (KRW). Convert to decimal for calculations by dividing by 100.
  • For amortization schedules, monthly rate i = (annual_percent / 100) / 12.
  • Spreads are plain differences of two percentage values reported by /latest or a common date from /historical.

Useful cross-checks and integrations

Combine BOK_BASE_RATE with other benchmarks to contextualize funding conditions or credit pricing. You can retrieve both in one latest query using symbols=BOK_BASE_RATE,ECB_MRO, for instance, and compute spreads server- or client-side. If you need a turnkey comparison for simple loans, /convert returns total interest at each benchmark’s latest reading (see example earlier).

When integrating with web dashboards, the dailyized output from /timeseries pairs well with OHLC results for a split view: candlesticks for the broader trend, plus markers for policy decision dates sourced from the timeseries step changes. Remember to normalize to month-end for model inputs that assume economic month aggregation.

For more context and examples beyond this article, visit Try Interest Rates API and Get started with Interest Rates API.

FAQ

Q: What is the unit of BOK_BASE_RATE in the API?
A: Percent per annum. For calculations, convert to decimal by dividing by 100 (e.g., 3% → 0.03).

Q: Why does /timeseries show a daily frequency for a monthly policy rate?
A: The API may present dailyized series for consistency across endpoints and easier charting. The monthly rate is carried across business days until a policy change. Use the frequencies field to verify representation.

Q: How do weekends and holidays affect /historical for BOK_BASE_RATE?
A: For monthly symbols, the API uses the last day with data within that month, so any date inside the month maps to the correct monthly value.

Q: How should I cache responses?
A: Cache latest calls for minutes to hours, and archive older historical data by year or quarter. Refresh only the most recent periods regularly to capture updates.

Q: How do I compute a loan payment from the returned rate?
A: Use the amortized payment formula payment = P * (i * (1 + i)^T) / ((1 + i)^T − 1) with i = (annual_percent / 100) / 12. For a quick simple-interest estimate, monthly_interest = (annual_percent / 100) * (P / 12), and add to principal amortization per month.

Build and ship your BOK_BASE_RATE integration now. Review the endpoints in the MCP docs and Register for an API key to start querying.

Ready to get started?

Get your API key and start validating bank data in minutes.

Get API Key