interest-rate-decisions 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ node_modules/
2
+ dist/
3
+ .astro/
4
+ .env
5
+ .env.*
6
+ *.log
7
+ .DS_Store
8
+ dist-*/
9
+ !.env.example
10
+
11
+ __pycache__/
12
+ *.pyc
13
+ integrations/pypi/dist/
14
+ network/**/node_modules/
15
+ network/**/dist/
16
+ *.ex5
17
+ *.ex4
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 InterestRateDecision.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.5
2
+ Name: interest-rate-decisions
3
+ Version: 1.0.0
4
+ Summary: Central bank interest rates and decisions (Fed, ECB, BoE, BoJ, BoC, RBA, RBNZ, SNB, Norges Bank, Riksbank): today's rates, the next meetings and every decision since 2008.
5
+ Project-URL: Homepage, https://interestratedecision.com/central-bank-data/
6
+ Project-URL: Source, https://github.com/Interest-Rate-Decision/interest-rate-decisions/tree/main/python
7
+ Author: InterestRateDecision.com
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: central bank,ecb,economic calendar,fed,fomc,forex,interest rates,monetary policy
11
+ Classifier: Intended Audience :: Financial and Insurance Industry
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Office/Business :: Financial
15
+ Classifier: Topic :: Office/Business :: Financial :: Investment
16
+ Requires-Python: >=3.9
17
+ Provides-Extra: pandas
18
+ Requires-Dist: pandas; extra == 'pandas'
19
+ Description-Content-Type: text/markdown
20
+
21
+ # interest-rate-decisions
22
+
23
+ Central bank interest rates and decisions, from [InterestRateDecision.com](https://interestratedecision.com/): today's policy rates, the next meetings and every decision since 2008, for the Fed, ECB, Bank of England, Bank of Japan, Bank of Canada, RBA, RBNZ, SNB, Norges Bank and the Riksbank.
24
+
25
+ Standard library only. pandas is optional.
26
+
27
+ ```sh
28
+ pip install interest-rate-decisions
29
+ interest-rate-decisions # the next decisions and every rate
30
+ interest-rate-decisions fed # one bank
31
+ ```
32
+
33
+ ```python
34
+ import interest_rate_decisions as ird
35
+
36
+ ird.get_rate("fed") # {'bank': 'fed', 'rate': 4.0, 'rangeLow': 3.75, 'nextDecision': ...}
37
+ ird.get_next() # the next decision of any bank
38
+ ird.get_upcoming("ecb") # the ECB's meetings to come
39
+ ird.get_decisions("boe") # every Bank of England decision since 2008
40
+
41
+ df = ird.decisions_frame("fed") # pip install "interest-rate-decisions[pandas]"
42
+ df.rate.plot(drawstyle="steps-post")
43
+ ```
44
+
45
+ Banks: `fed`, `ecb`, `boe`, `boj`, `boc`, `rba`, `rbnz`, `snb`, `norges`, `riksbank`. Rates are per cent; the Fed's `rate` is the top of its target range. Times are UTC. The ECB's `rate` is None before March 2015, where the source gives only its refinancing rate's change.
46
+
47
+ The data updates within minutes of each decision. For the odds of the next move, charts and what each decision did to the currency, see [interestratedecision.com](https://interestratedecision.com/).
48
+
49
+ ## Data terms
50
+
51
+ The code is MIT. The data is free to use in anything, including commercial work, **with a visible link to [InterestRateDecision.com](https://interestratedecision.com/)** ([terms](https://interestratedecision.com/central-bank-data/#licence)).
@@ -0,0 +1,31 @@
1
+ # interest-rate-decisions
2
+
3
+ Central bank interest rates and decisions, from [InterestRateDecision.com](https://interestratedecision.com/): today's policy rates, the next meetings and every decision since 2008, for the Fed, ECB, Bank of England, Bank of Japan, Bank of Canada, RBA, RBNZ, SNB, Norges Bank and the Riksbank.
4
+
5
+ Standard library only. pandas is optional.
6
+
7
+ ```sh
8
+ pip install interest-rate-decisions
9
+ interest-rate-decisions # the next decisions and every rate
10
+ interest-rate-decisions fed # one bank
11
+ ```
12
+
13
+ ```python
14
+ import interest_rate_decisions as ird
15
+
16
+ ird.get_rate("fed") # {'bank': 'fed', 'rate': 4.0, 'rangeLow': 3.75, 'nextDecision': ...}
17
+ ird.get_next() # the next decision of any bank
18
+ ird.get_upcoming("ecb") # the ECB's meetings to come
19
+ ird.get_decisions("boe") # every Bank of England decision since 2008
20
+
21
+ df = ird.decisions_frame("fed") # pip install "interest-rate-decisions[pandas]"
22
+ df.rate.plot(drawstyle="steps-post")
23
+ ```
24
+
25
+ Banks: `fed`, `ecb`, `boe`, `boj`, `boc`, `rba`, `rbnz`, `snb`, `norges`, `riksbank`. Rates are per cent; the Fed's `rate` is the top of its target range. Times are UTC. The ECB's `rate` is None before March 2015, where the source gives only its refinancing rate's change.
26
+
27
+ The data updates within minutes of each decision. For the odds of the next move, charts and what each decision did to the currency, see [interestratedecision.com](https://interestratedecision.com/).
28
+
29
+ ## Data terms
30
+
31
+ The code is MIT. The data is free to use in anything, including commercial work, **with a visible link to [InterestRateDecision.com](https://interestratedecision.com/)** ([terms](https://interestratedecision.com/central-bank-data/#licence)).
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "interest-rate-decisions"
7
+ version = "1.0.0"
8
+ description = "Central bank interest rates and decisions (Fed, ECB, BoE, BoJ, BoC, RBA, RBNZ, SNB, Norges Bank, Riksbank): today's rates, the next meetings and every decision since 2008."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "InterestRateDecision.com" }]
14
+ keywords = ["interest rates", "central bank", "fed", "fomc", "ecb", "forex", "monetary policy", "economic calendar"]
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "Topic :: Office/Business :: Financial",
18
+ "Topic :: Office/Business :: Financial :: Investment",
19
+ "Intended Audience :: Financial and Insurance Industry",
20
+ "Intended Audience :: Science/Research",
21
+ ]
22
+ dependencies = []
23
+
24
+ [project.optional-dependencies]
25
+ pandas = ["pandas"]
26
+
27
+ [project.scripts]
28
+ interest-rate-decisions = "interest_rate_decisions.__main__:main"
29
+
30
+ [project.urls]
31
+ Homepage = "https://interestratedecision.com/central-bank-data/"
32
+ Source = "https://github.com/Interest-Rate-Decision/interest-rate-decisions/tree/main/python"
@@ -0,0 +1,94 @@
1
+ """Central bank interest rates and decisions from InterestRateDecision.com.
2
+
3
+ Today's policy rates, the next meetings and every decision since 2008 for the
4
+ Fed, ECB, Bank of England, Bank of Japan, Bank of Canada, RBA, RBNZ, SNB,
5
+ Norges Bank and the Riksbank. Standard library only; pandas is optional.
6
+
7
+ Data terms: free to reuse with a visible link to https://interestratedecision.com
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import csv
13
+ import io
14
+ import json
15
+ import time
16
+ import urllib.request
17
+ from datetime import datetime, timezone
18
+ from typing import Any, Callable, Optional
19
+
20
+ __version__ = "1.0.0"
21
+ __all__ = ["BASE", "BANKS", "get_rates", "get_rate", "get_upcoming", "get_next", "get_decisions", "parse_decisions", "decisions_frame"]
22
+
23
+ BASE = "https://interestratedecision.com"
24
+ BANKS = ("fed", "ecb", "boe", "boj", "boc", "rba", "rbnz", "snb", "norges", "riksbank")
25
+
26
+ Fetch = Callable[[str], str]
27
+
28
+
29
+ def _fetch(url: str) -> str:
30
+ req = urllib.request.Request(url, headers={"User-Agent": f"interest-rate-decisions-python/{__version__}"})
31
+ with urllib.request.urlopen(req, timeout=20) as res:
32
+ return res.read().decode("utf-8")
33
+
34
+
35
+ def _get(path: str, fetch: Optional[Fetch] = None, base: str = BASE) -> str:
36
+ return (fetch or _fetch)(f"{base}{path}")
37
+
38
+
39
+ def _ts(iso: str) -> float:
40
+ return datetime.fromisoformat(iso.replace("Z", "+00:00")).timestamp()
41
+
42
+
43
+ def get_rates(fetch: Optional[Fetch] = None) -> list[dict[str, Any]]:
44
+ """Every bank's rate today (per cent; the Fed's is the top of its range, ``rangeLow`` the bottom), its last change and next decision."""
45
+ return json.loads(_get("/data/rates.json", fetch))["rates"]
46
+
47
+
48
+ def get_rate(bank: str, fetch: Optional[Fetch] = None) -> dict[str, Any]:
49
+ """One bank's rate today."""
50
+ for r in get_rates(fetch):
51
+ if r["bank"] == bank:
52
+ return r
53
+ raise ValueError(f'unknown bank "{bank}" (one of {", ".join(BANKS)})')
54
+
55
+
56
+ def get_upcoming(bank: Optional[str] = None, fetch: Optional[Fetch] = None) -> list[dict[str, Any]]:
57
+ """The decisions to come, soonest first; times (``t``) are ISO UTC."""
58
+ ds = json.loads(_get("/data/next.json", fetch))["decisions"]
59
+ ds = [d for d in ds if bank is None or d["bank"] == bank]
60
+ return sorted(ds, key=lambda d: _ts(d["t"]))
61
+
62
+
63
+ def get_next(bank: Optional[str] = None, fetch: Optional[Fetch] = None) -> Optional[dict[str, Any]]:
64
+ """The next decision, of one bank or of any; None when none is listed."""
65
+ now = time.time()
66
+ return next((d for d in get_upcoming(bank, fetch) if _ts(d["t"]) > now - 3600), None)
67
+
68
+
69
+ def parse_decisions(text: str) -> list[dict[str, Any]]:
70
+ """Rows of the decisions CSV, with ``rate`` and ``change_bp`` as numbers (None where blank)."""
71
+ out = []
72
+ for row in csv.DictReader(io.StringIO(text)):
73
+ out.append({
74
+ "bank": row["bank"],
75
+ "bank_name": row["bank_name"],
76
+ "time_utc": datetime.fromisoformat(row["time_utc"].replace("Z", "+00:00")).astimezone(timezone.utc),
77
+ "date": row["date"],
78
+ "rate": float(row["rate"]) if row["rate"] != "" else None,
79
+ "change_bp": int(row["change_bp"]) if row["change_bp"] != "" else None,
80
+ })
81
+ return out
82
+
83
+
84
+ def get_decisions(bank: Optional[str] = None, fetch: Optional[Fetch] = None) -> list[dict[str, Any]]:
85
+ """Every decision since 2008, oldest first. The ECB's ``rate`` is None before March 2015."""
86
+ rows = parse_decisions(_get("/data/decisions.csv", fetch))
87
+ return [r for r in rows if bank is None or r["bank"] == bank]
88
+
89
+
90
+ def decisions_frame(bank: Optional[str] = None, fetch: Optional[Fetch] = None):
91
+ """The decisions as a pandas DataFrame indexed by time (needs pandas)."""
92
+ import pandas as pd # optional
93
+
94
+ return pd.DataFrame(get_decisions(bank, fetch)).set_index("time_utc")
@@ -0,0 +1,39 @@
1
+ """python -m interest_rate_decisions [bank] [--json]: the next decisions and every rate."""
2
+
3
+ import json
4
+ import sys
5
+ import time
6
+ from datetime import datetime
7
+
8
+ from . import BANKS, get_rates, get_upcoming, _ts
9
+
10
+
11
+ def _until(t: str) -> str:
12
+ s = _ts(t) - time.time()
13
+ if s <= 0:
14
+ return "now"
15
+ d, h, m = int(s // 86400), int(s % 86400 // 3600), int(s % 3600 // 60)
16
+ return f"{d}d {h}h" if d else f"{h}h {m}m" if h else f"{m}m"
17
+
18
+
19
+ def main() -> None:
20
+ args = sys.argv[1:]
21
+ bank = next((a for a in args if a in BANKS), None)
22
+ rates = [r for r in get_rates() if bank is None or r["bank"] == bank]
23
+ upcoming = [d for d in get_upcoming(bank) if _ts(d["t"]) > time.time() - 3600]
24
+ if "--json" in args:
25
+ print(json.dumps({"rates": rates, "next": upcoming[:10]}, indent=2))
26
+ return
27
+ print("\nNext central bank decisions (your time)")
28
+ for d in upcoming[: 4 if bank else 6]:
29
+ local = datetime.fromtimestamp(_ts(d["t"])).strftime("%a %d %b, %H:%M")
30
+ print(f" {d['short']:<12} {local:<20}{' est.' if d['tentative'] else ' '} in {_until(d['t'])}")
31
+ print("\nPolicy rates")
32
+ for r in rates:
33
+ v = f"{r['rangeLow']:.2f}-{r['rate']:.2f}%" if r.get("rangeLow") is not None else f"{r['rate']:.2f}%"
34
+ print(f" {r['bank']:<12} {v:<13} {r['name']}")
35
+ print(f"\nOdds, history and what each decision did to the currency: https://interestratedecision.com{'/' + bank + '/' if bank else ''}\n")
36
+
37
+
38
+ if __name__ == "__main__":
39
+ main()
@@ -0,0 +1,35 @@
1
+ import json
2
+ import unittest
3
+
4
+ import interest_rate_decisions as ird
5
+
6
+ FILES = {
7
+ "/data/rates.json": json.dumps({"rates": [{"bank": "fed", "name": "Federal Reserve", "rate": 4, "rangeLow": 3.75}]}),
8
+ "/data/next.json": json.dumps({"decisions": [{"bank": "ecb", "t": "2999-02-01T12:00:00Z"}, {"bank": "fed", "t": "2999-01-01T19:00:00Z"}, {"bank": "boe", "t": "2000-01-01T12:00:00Z"}]}),
9
+ "/data/decisions.csv": "bank,bank_name,time_utc,date,rate,change_bp\necb,European Central Bank,2008-01-10T12:45:00.000Z,2008-01-10,,\nfed,Federal Reserve,2008-01-22T13:20:00.000Z,2008-01-22,3.5,-75\n",
10
+ }
11
+
12
+
13
+ def fetch(url: str) -> str:
14
+ return FILES[url.replace(ird.BASE, "")]
15
+
16
+
17
+ class Client(unittest.TestCase):
18
+ def test_rate(self):
19
+ self.assertEqual(ird.get_rate("fed", fetch)["rangeLow"], 3.75)
20
+ with self.assertRaises(ValueError):
21
+ ird.get_rate("xyz", fetch)
22
+
23
+ def test_next(self):
24
+ self.assertEqual(ird.get_next(fetch=fetch)["bank"], "fed")
25
+ self.assertIsNone(ird.get_next("boe", fetch))
26
+
27
+ def test_decisions(self):
28
+ rows = ird.get_decisions(fetch=fetch)
29
+ self.assertIsNone(rows[0]["rate"])
30
+ self.assertEqual(rows[1]["change_bp"], -75)
31
+ self.assertEqual(rows[1]["time_utc"].year, 2008)
32
+
33
+
34
+ if __name__ == "__main__":
35
+ unittest.main()