kensho-kfinance 1.0.3__tar.gz → 1.1.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.

Potentially problematic release.


This version of kensho-kfinance might be problematic. Click here for more details.

Files changed (42) hide show
  1. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/.gitignore +2 -0
  2. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/PKG-INFO +9 -3
  3. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/README.md +6 -1
  4. kensho_kfinance-1.1.0/justfile +31 -0
  5. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kensho_kfinance.egg-info/PKG-INFO +9 -3
  6. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kensho_kfinance.egg-info/SOURCES.txt +1 -0
  7. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/CHANGELOG.md +3 -0
  8. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/fetch.py +22 -1
  9. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/llm_tools.py +56 -1
  10. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/meta_classes.py +74 -4
  11. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/tests/test_fetch.py +32 -2
  12. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/tests/test_objects.py +37 -0
  13. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/tool_schemas.py +14 -0
  14. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/version.py +2 -2
  15. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/scripts/lint.sh +4 -0
  16. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/.coveragerc +0 -0
  17. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/.github/workflows/ci-lint.yml +0 -0
  18. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/.github/workflows/ci-test.yml +0 -0
  19. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/.github/workflows/python-publish.yml +0 -0
  20. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/AUTHORS.md +0 -0
  21. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/CODE_OF_CONDUCT.md +0 -0
  22. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/CONTRIBUTING.md +0 -0
  23. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/LICENSE +0 -0
  24. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/docs/index.rst +0 -0
  25. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/docs/kfinance.rst +0 -0
  26. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/docs/llm_tools.rst +0 -0
  27. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kensho_kfinance.egg-info/dependency_links.txt +0 -0
  28. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kensho_kfinance.egg-info/requires.txt +0 -0
  29. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kensho_kfinance.egg-info/top_level.txt +0 -0
  30. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/__init__.py +0 -0
  31. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/constants.py +0 -0
  32. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/kfinance.py +0 -0
  33. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/prompt.py +0 -0
  34. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/py.typed +0 -0
  35. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/server_thread.py +0 -0
  36. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/kfinance/tests/__init__.py +0 -0
  37. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/pyproject.toml +0 -0
  38. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/scripts/copyright_line_check.sh +0 -0
  39. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/scripts/docs/make_rst.py +0 -0
  40. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/scripts/test.sh +0 -0
  41. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/setup.cfg +0 -0
  42. {kensho_kfinance-1.0.3 → kensho_kfinance-1.1.0}/setup.py +0 -0
@@ -98,3 +98,5 @@ dmypy.json
98
98
  .idea/*
99
99
  .vscode/
100
100
 
101
+
102
+ kfinance/version.py
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: kensho-kfinance
3
- Version: 1.0.3
3
+ Version: 1.1.0
4
4
  Summary: Python CLI for kFinance
5
5
  Author-email: Luke Brown <luke.brown@kensho.com>, Michelle Keoy <michelle.keoy@kensho.com>, Keith Page <keith.page@kensho.com>, Matthew Rosen <matthew.rosen@kensho.com>, Nick Roshdieh <nick.roshdieh@kensho.com>
6
6
  Project-URL: source, https://github.com/kensho-technologies/kfinance
@@ -28,6 +28,7 @@ Requires-Dist: mypy<2,>=1.15.0; extra == "dev"
28
28
  Requires-Dist: pytest<7,>=6.1.2; extra == "dev"
29
29
  Requires-Dist: pytest-cov<7,>=6.0.0; extra == "dev"
30
30
  Requires-Dist: ruff<1,>=0.9.4; extra == "dev"
31
+ Dynamic: license-file
31
32
 
32
33
  # kFinance
33
34
 
@@ -39,7 +40,7 @@ Any questions or suggestions can be sent to the [kFinance Maintainers](kfinance-
39
40
 
40
41
  # Setup
41
42
 
42
- You can install kFinance on [PyPI](https://pypi.org/project/kfinance/) via
43
+ You can install kFinance on [PyPI](https://pypi.org/project/kensho-kfinance/) via
43
44
 
44
45
  `pip install kensho-kfinance`
45
46
 
@@ -49,6 +50,11 @@ To receive access, please email [S&P Global Market Intelligence](market.intellig
49
50
 
50
51
  Once access is obtained, get started using the [Authentication Guide](https://docs.kensho.com/llmreadyapi/kf-authentication) and [Usage Guide](https://docs.kensho.com/llmreadyapi/usage).
51
52
 
53
+ # Versioning
54
+ The kFinance uses semantic versioning (major, minor, patch).
55
+ To bump the version, add a new entry in [CHANGELOG.md](kfinance%2FCHANGELOG.md).
56
+ This will generate a new version of the library as part of the release process.
57
+
52
58
  # License
53
59
 
54
60
  Use is solely in accordance with the signed agreement between your entity and S&P.
@@ -8,7 +8,7 @@ Any questions or suggestions can be sent to the [kFinance Maintainers](kfinance-
8
8
 
9
9
  # Setup
10
10
 
11
- You can install kFinance on [PyPI](https://pypi.org/project/kfinance/) via
11
+ You can install kFinance on [PyPI](https://pypi.org/project/kensho-kfinance/) via
12
12
 
13
13
  `pip install kensho-kfinance`
14
14
 
@@ -18,6 +18,11 @@ To receive access, please email [S&P Global Market Intelligence](market.intellig
18
18
 
19
19
  Once access is obtained, get started using the [Authentication Guide](https://docs.kensho.com/llmreadyapi/kf-authentication) and [Usage Guide](https://docs.kensho.com/llmreadyapi/usage).
20
20
 
21
+ # Versioning
22
+ The kFinance uses semantic versioning (major, minor, patch).
23
+ To bump the version, add a new entry in [CHANGELOG.md](kfinance%2FCHANGELOG.md).
24
+ This will generate a new version of the library as part of the release process.
25
+
21
26
  # License
22
27
 
23
28
  Use is solely in accordance with the signed agreement between your entity and S&P.
@@ -0,0 +1,31 @@
1
+ set dotenv-load
2
+
3
+ # Just is a command runner. It can be used to provide a shorthand to run
4
+ # complex commands, for example `just lint` for `python -m kensho_lint.lint...`
5
+
6
+ # Here are some installation instructions:
7
+ # https://github.com/casey/just?tab=readme-ov-file#installation
8
+ # Once installed, you can run any of the commands in this file by
9
+ # prepending them with `just`, for example `just lint` to run the linter.
10
+ # Run `just` shows a list of all available commands
11
+
12
+ # If there are commands that you believe can be useful to other contributors,
13
+ # feel free to add them.
14
+
15
+
16
+ default:
17
+ just --list
18
+
19
+ alias l := lint
20
+ # Lint the app directory (both lint and l work). For verbose, use `just lint --verbose`
21
+ lint *args:
22
+ python -m mypy --config-file pyproject.toml kfinance {{args}}
23
+ # The ruff linters (check) and formatters (format) are separate.
24
+ # See https://docs.astral.sh/ruff/formatter/#sorting-imports
25
+ python -m ruff --config pyproject.toml check kfinance --fix {{args}}
26
+ python -m ruff --config pyproject.toml format kfinance {{args}}
27
+
28
+ alias t := unit-test
29
+ # Run unit tests. Use args for optional settings
30
+ unit-test *args:
31
+ python -m pytest {{args}}
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: kensho-kfinance
3
- Version: 1.0.3
3
+ Version: 1.1.0
4
4
  Summary: Python CLI for kFinance
5
5
  Author-email: Luke Brown <luke.brown@kensho.com>, Michelle Keoy <michelle.keoy@kensho.com>, Keith Page <keith.page@kensho.com>, Matthew Rosen <matthew.rosen@kensho.com>, Nick Roshdieh <nick.roshdieh@kensho.com>
6
6
  Project-URL: source, https://github.com/kensho-technologies/kfinance
@@ -28,6 +28,7 @@ Requires-Dist: mypy<2,>=1.15.0; extra == "dev"
28
28
  Requires-Dist: pytest<7,>=6.1.2; extra == "dev"
29
29
  Requires-Dist: pytest-cov<7,>=6.0.0; extra == "dev"
30
30
  Requires-Dist: ruff<1,>=0.9.4; extra == "dev"
31
+ Dynamic: license-file
31
32
 
32
33
  # kFinance
33
34
 
@@ -39,7 +40,7 @@ Any questions or suggestions can be sent to the [kFinance Maintainers](kfinance-
39
40
 
40
41
  # Setup
41
42
 
42
- You can install kFinance on [PyPI](https://pypi.org/project/kfinance/) via
43
+ You can install kFinance on [PyPI](https://pypi.org/project/kensho-kfinance/) via
43
44
 
44
45
  `pip install kensho-kfinance`
45
46
 
@@ -49,6 +50,11 @@ To receive access, please email [S&P Global Market Intelligence](market.intellig
49
50
 
50
51
  Once access is obtained, get started using the [Authentication Guide](https://docs.kensho.com/llmreadyapi/kf-authentication) and [Usage Guide](https://docs.kensho.com/llmreadyapi/usage).
51
52
 
53
+ # Versioning
54
+ The kFinance uses semantic versioning (major, minor, patch).
55
+ To bump the version, add a new entry in [CHANGELOG.md](kfinance%2FCHANGELOG.md).
56
+ This will generate a new version of the library as part of the release process.
57
+
52
58
  # License
53
59
 
54
60
  Use is solely in accordance with the signed agreement between your entity and S&P.
@@ -5,6 +5,7 @@ CODE_OF_CONDUCT.md
5
5
  CONTRIBUTING.md
6
6
  LICENSE
7
7
  README.md
8
+ justfile
8
9
  pyproject.toml
9
10
  setup.py
10
11
  .github/workflows/ci-lint.yml
@@ -1,4 +1,7 @@
1
1
  # Changelog
2
+ ## v1.1.0
3
+ - Add market cap, TEV, and shares outstanding
4
+
2
5
  ## v1.0.3
3
6
  - Fix typo for get_history_metadata_from_identifier.
4
7
 
@@ -5,7 +5,14 @@ import jwt
5
5
  import requests
6
6
 
7
7
  from .constants import BusinessRelationshipType, IdentificationTriple
8
- from .version import __version__ as kfinance_version
8
+
9
+
10
+ # version.py gets autogenerated by setuptools-scm and is not available
11
+ # during local development.
12
+ try:
13
+ from .version import __version__ as kfinance_version
14
+ except ImportError:
15
+ kfinance_version = "dev"
9
16
 
10
17
 
11
18
  DEFAULT_API_HOST: str = "https://kfinance.kensho.com"
@@ -175,6 +182,20 @@ class KFinanceApiClient:
175
182
  url = f"{self.url_base}pricing/{trading_item_id}/metadata"
176
183
  return self.fetch(url)
177
184
 
185
+ def fetch_market_caps_tevs_and_shares_outstanding(
186
+ self,
187
+ company_id: int,
188
+ start_date: Optional[str] = None,
189
+ end_date: Optional[str] = None,
190
+ ) -> dict:
191
+ """Get the market cap, TEV, and shares outstanding for a company."""
192
+ url = (
193
+ f"{self.url_base}market_cap/{company_id}/"
194
+ f"{start_date if start_date is not None else 'none'}/"
195
+ f"{end_date if end_date is not None else 'none'}"
196
+ )
197
+ return self.fetch(url)
198
+
178
199
  def fetch_price_chart(
179
200
  self,
180
201
  trading_item_id: int,
@@ -4,7 +4,7 @@ import copy
4
4
  import datetime
5
5
  from enum import Enum
6
6
  from functools import partial
7
- from typing import TYPE_CHECKING, Callable
7
+ from typing import TYPE_CHECKING, Callable, Literal
8
8
 
9
9
  from langchain_core.tools import StructuredTool
10
10
 
@@ -210,6 +210,31 @@ def get_prices_from_identifier(
210
210
  )
211
211
 
212
212
 
213
+ def get_capitalization_from_identifier(
214
+ self: Client,
215
+ identifier: str,
216
+ capitalization: Literal["market_cap", "tev", "shares_outstanding"],
217
+ start_date: str | None = None,
218
+ end_date: str | None = None,
219
+ ) -> str:
220
+ """Get the historical market cap, tev (Total Enterprise Value), or shares outstanding of an identifier, where the identifier can be a ticker, ISIN or CUSIP, between inclusive start_date and inclusive end date.
221
+
222
+ Args:
223
+ identifier: A unique identifier, which can be a ticker symbol, ISIN, or CUSIP.
224
+ capitalization: The capitalization to retrieve (market_cap, tev, or shares_outstanding)
225
+ start_date: The start date for historical price retrieval in format YYYY-MM-DD
226
+ end_date: The end date for historical price retrieval in format YYYY-MM-DD
227
+ """
228
+ ticker = self.ticker(identifier)
229
+ capitalization_to_func: dict[Literal["market_cap", "tev", "shares_outstanding"], Callable] = {
230
+ "market_cap": ticker.market_cap,
231
+ "tev": ticker.tev,
232
+ "shares_outstanding": ticker.shares_outstanding,
233
+ }
234
+ func = capitalization_to_func[capitalization]
235
+ return func(start_date=start_date, end_date=end_date).to_markdown()
236
+
237
+
213
238
  def get_financial_statement_from_identifier(
214
239
  self: Client,
215
240
  identifier: str,
@@ -297,6 +322,7 @@ def _llm_tools(self: Client) -> dict[str, Callable]:
297
322
  ),
298
323
  "get_history_metadata_from_identifier": partial(get_history_metadata_from_identifier, self),
299
324
  "get_prices_from_identifier": partial(get_prices_from_identifier, self),
325
+ "get_capitalization_from_identifier": partial(get_capitalization_from_identifier, self),
300
326
  "get_financial_statement_from_identifier": partial(
301
327
  get_financial_statement_from_identifier, self
302
328
  ),
@@ -323,6 +349,7 @@ def _llm_tool_metadata() -> dict:
323
349
  "get_earnings_call_datetimes_from_identifier": tool_schemas.GetEarningsCallDatetimesFromIdentifier,
324
350
  "get_history_metadata_from_identifier": tool_schemas.GetHistoryMetadataFromIdentifier,
325
351
  "get_prices_from_identifier": tool_schemas.GetPricesFromIdentifier,
352
+ "get_capitalization_from_identifier": tool_schemas.GetCapitalizationFromIdentifier,
326
353
  "get_financial_statement_from_identifier": tool_schemas.GetFinancialStatementFromIdentifier,
327
354
  "get_financial_line_item_from_identifier": tool_schemas.GetFinancialLineItemFromIdentifier,
328
355
  "get_business_relationship_from_identifier": tool_schemas.GetBusinessRelationshipFromIdentifier,
@@ -516,6 +543,34 @@ _base_tool_descriptions = [
516
543
  "additionalProperties": False,
517
544
  },
518
545
  },
546
+ {
547
+ "name": "get_capitalization_from_identifier",
548
+ "description": "Get the historical market cap, tev (Total Enterprise Value), or shares outstanding of an identifier, where the identifier can be a ticker, ISIN or CUSIP, between inclusive start_date and inclusive end date.",
549
+ "input_schema": {
550
+ "type": "object",
551
+ "properties": {
552
+ "identifier": {
553
+ "type": "string",
554
+ "description": "A unique identifier, which can be a ticker symbol, ISIN, or CUSIP.",
555
+ },
556
+ "capitalization": {
557
+ "type": "string",
558
+ "description": "The capitalization to retrieve (market_cap, tev, or shares_outstanding).",
559
+ "enum": ["market_cap", "tev", "shares_outstanding"],
560
+ },
561
+ "start_date": {
562
+ "type": "string",
563
+ "description": "The start date for historical price retrieval in format YYYY-MM-DD",
564
+ },
565
+ "end_date": {
566
+ "type": "string",
567
+ "description": "The end date for historical price retrieval in format YYYY-MM-DD",
568
+ },
569
+ },
570
+ "required": ["identifier", "capitalization"],
571
+ "additionalProperties": False,
572
+ },
573
+ },
519
574
  {
520
575
  "name": "get_financial_statement_from_identifier",
521
576
  "description": "Get the financial statement associated with an identifier",
@@ -1,7 +1,7 @@
1
1
  from datetime import datetime
2
2
  from functools import cache, cached_property
3
3
  import logging
4
- from typing import TYPE_CHECKING, Any, Callable, Optional
4
+ from typing import TYPE_CHECKING, Any, Callable, Literal, Optional
5
5
 
6
6
  import numpy as np
7
7
  import pandas as pd
@@ -18,9 +18,7 @@ logger = logging.getLogger(__name__)
18
18
 
19
19
 
20
20
  class CompanyFunctionsMetaClass:
21
- def __init__(self) -> None:
22
- """Init company functions"""
23
- self.kfinance_api_client: KFinanceApiClient
21
+ kfinance_api_client: KFinanceApiClient
24
22
 
25
23
  @cached_property
26
24
  def company_id(self) -> Any:
@@ -239,6 +237,78 @@ class CompanyFunctionsMetaClass:
239
237
  Companies(self.kfinance_api_client, companies["previous"]),
240
238
  )
241
239
 
240
+ def market_cap(
241
+ self,
242
+ start_date: Optional[str] = None,
243
+ end_date: Optional[str] = None,
244
+ ) -> pd.DataFrame:
245
+ """Retrieves market caps for a company between start and end date.
246
+
247
+ :param start_date: The start date in format "YYYY-MM-DD", default to None
248
+ :type start_date: str, optional
249
+ :param end_date: The end date in format "YYYY-MM-DD", default to None
250
+ :type end_date: str, optional
251
+ :return: A DataFrame with a `market_cap` column. The dates are the index.
252
+ :rtype: pd.DataFrame
253
+ """
254
+
255
+ return self._fetch_market_cap_tev_or_shares_outstanding(
256
+ column_to_extract="market_cap", start_date=start_date, end_date=end_date
257
+ )
258
+
259
+ def tev(
260
+ self,
261
+ start_date: Optional[str] = None,
262
+ end_date: Optional[str] = None,
263
+ ) -> pd.DataFrame:
264
+ """Retrieves TEV (total enterprise value) for a company between start and end date.
265
+
266
+ :param start_date: The start date in format "YYYY-MM-DD", default to None
267
+ :type start_date: str, optional
268
+ :param end_date: The end date in format "YYYY-MM-DD", default to None
269
+ :type end_date: str, optional
270
+ :return: A DataFrame with a `tev` column. The dates are the index.
271
+ :rtype: pd.DataFrame
272
+ """
273
+
274
+ return self._fetch_market_cap_tev_or_shares_outstanding(
275
+ column_to_extract="tev", start_date=start_date, end_date=end_date
276
+ )
277
+
278
+ def shares_outstanding(
279
+ self,
280
+ start_date: Optional[str] = None,
281
+ end_date: Optional[str] = None,
282
+ ) -> pd.DataFrame:
283
+ """Retrieves shares outstanding for a company between start and end date.
284
+
285
+ :param start_date: The start date in format "YYYY-MM-DD", default to None
286
+ :type start_date: str, optional
287
+ :param end_date: The end date in format "YYYY-MM-DD", default to None
288
+ :type end_date: str, optional
289
+ :return: A DataFrame with a `shares_outstanding` column. The dates are the index.
290
+ :rtype: pd.DataFrame
291
+ """
292
+
293
+ return self._fetch_market_cap_tev_or_shares_outstanding(
294
+ column_to_extract="shares_outstanding", start_date=start_date, end_date=end_date
295
+ )
296
+
297
+ def _fetch_market_cap_tev_or_shares_outstanding(
298
+ self,
299
+ column_to_extract: Literal["market_cap", "tev", "shares_outstanding"],
300
+ start_date: str | None,
301
+ end_date: str | None,
302
+ ) -> pd.DataFrame:
303
+ """Helper function to fetch market cap, TEV, and shares outstanding."""
304
+
305
+ df = pd.DataFrame(
306
+ self.kfinance_api_client.fetch_market_caps_tevs_and_shares_outstanding(
307
+ company_id=self.company_id, start_date=start_date, end_date=end_date
308
+ )["market_caps"]
309
+ )
310
+ return df.set_index("date")[[column_to_extract]].apply(pd.to_numeric).replace(np.nan, None)
311
+
242
312
 
243
313
  for line_item in LINE_ITEMS:
244
314
  line_item_name = line_item["name"]
@@ -1,14 +1,22 @@
1
1
  from unittest import TestCase
2
2
  from unittest.mock import Mock
3
3
 
4
+ import pytest
5
+
4
6
  from kfinance.fetch import KFinanceApiClient
5
7
 
6
8
 
9
+ def build_mock_api_client() -> KFinanceApiClient:
10
+ """Create a KFinanceApiClient with mocked-out fetch function."""
11
+ kfinance_api_client = KFinanceApiClient(refresh_token="fake_refresh_token")
12
+ kfinance_api_client.fetch = Mock()
13
+ return kfinance_api_client
14
+
15
+
7
16
  class TestFetchItem(TestCase):
8
17
  def setUp(self):
9
18
  """Create a KFinanceApiClient with mocked-out fetch function."""
10
- self.kfinance_api_client = KFinanceApiClient(refresh_token="fake_refresh_token")
11
- self.kfinance_api_client.fetch = Mock()
19
+ self.kfinance_api_client = build_mock_api_client()
12
20
 
13
21
  def test_fetch_id_triple(self) -> None:
14
22
  identifier = "SPGI"
@@ -239,3 +247,25 @@ class TestFetchItem(TestCase):
239
247
  exchange_code=exchange_code,
240
248
  )
241
249
  self.kfinance_api_client.fetch.assert_called_once_with(expected_fetch_url)
250
+
251
+
252
+ class TestMarketCap:
253
+ @pytest.mark.parametrize(
254
+ "start_date, start_date_url", [(None, "none"), ("2025-01-01", "2025-01-01")]
255
+ )
256
+ @pytest.mark.parametrize(
257
+ "end_date, end_date_url", [(None, "none"), ("2025-01-02", "2025-01-02")]
258
+ )
259
+ def test_fetch_market_cap(
260
+ self, start_date: str | None, start_date_url: str, end_date: str | None, end_date_url: str
261
+ ) -> None:
262
+ company_id = 12345
263
+ client = build_mock_api_client()
264
+
265
+ expected_fetch_url = (
266
+ f"{client.url_base}market_cap/{company_id}/{start_date_url}/{end_date_url}"
267
+ )
268
+ client.fetch_market_caps_tevs_and_shares_outstanding(
269
+ company_id=company_id, start_date=start_date, end_date=end_date
270
+ )
271
+ client.fetch.assert_called_with(expected_fetch_url)
@@ -166,6 +166,29 @@ class MockKFinanceApiClient:
166
166
  """Get a statement"""
167
167
  return MOCK_COMPANY_DB[company_id]["line_items"][line_item]
168
168
 
169
+ def fetch_market_caps_tevs_and_shares_outstanding(
170
+ self,
171
+ company_id: int,
172
+ start_date: Optional[str] = None,
173
+ end_date: Optional[str] = None,
174
+ ) -> dict:
175
+ return {
176
+ "market_caps": [
177
+ {
178
+ "date": "2025-01-01",
179
+ "market_cap": "3133802247084.000000",
180
+ "tev": "3152211247084.000000",
181
+ "shares_outstanding": 7434880776,
182
+ },
183
+ {
184
+ "date": "2025-01-02",
185
+ "market_cap": "3112092395218.000000",
186
+ "tev": "3130501395218.000000",
187
+ "shares_outstanding": 7434880776,
188
+ },
189
+ ]
190
+ }
191
+
169
192
 
170
193
  class TestTradingItem(TestCase):
171
194
  def setUp(self):
@@ -549,3 +572,17 @@ class TestTicker(TestCase):
549
572
  self.assertEqual(expected_ticker_symbol, self.msft_ticker_from_isin.ticker)
550
573
  self.assertEqual(expected_ticker_symbol, self.msft_ticker_from_cusip.ticker)
551
574
  self.assertEqual(expected_ticker_symbol, self.msft_ticker_from_id_triple.ticker)
575
+
576
+ def test_market_cap(self):
577
+ """
578
+ GIVEN a mock client
579
+ WHEN the mock client receives a mock market cap response dict
580
+ THEN the Ticker object can correctly extract market caps from the dict.
581
+ """
582
+
583
+ expected_dataframe = pd.DataFrame(
584
+ {"market_cap": {"2025-01-01": 3133802247084.0, "2025-01-02": 3112092395218.0}}
585
+ )
586
+ expected_dataframe.index.name = "date"
587
+ market_caps = self.msft_ticker_from_ticker.market_cap()
588
+ pd.testing.assert_frame_equal(expected_dataframe, market_caps)
@@ -77,6 +77,20 @@ class GetPricesFromIdentifier(BaseModel):
77
77
  )
78
78
 
79
79
 
80
+ class GetCapitalizationFromIdentifier(BaseModel):
81
+ identifier: str = Field(
82
+ description="The identifier, which can be a ticker symbol, ISIN, or CUSIP"
83
+ )
84
+ capitalization: Literal["market_cap", "tev", "shares_outstanding"] = Field(
85
+ description="The capitalization to retrieve"
86
+ )
87
+ start_date: str | None = Field(
88
+ default=None,
89
+ description="The start date in format YYYY-MM-DD",
90
+ )
91
+ end_date: str | None = Field(default=None, description="The end date in format YYYY-MM-DD")
92
+
93
+
80
94
  class GetFinancialStatementFromIdentifier(BaseModel):
81
95
  identifier: str = Field(
82
96
  description="The identifier, which can be a ticker symbol, ISIN, or CUSIP"
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '1.0.3'
21
- __version_tuple__ = version_tuple = (1, 0, 3)
20
+ __version__ = version = '1.1.0'
21
+ __version_tuple__ = version_tuple = (1, 1, 0)
@@ -13,7 +13,11 @@ done
13
13
  python -m mypy --config-file pyproject.toml kfinance
14
14
 
15
15
  if [ "$fix" = "--fix" ]; then
16
+ # The ruff linters (check) and formatters (format) are separate.
17
+ # See https://docs.astral.sh/ruff/formatter/#sorting-imports
16
18
  python -m ruff --config pyproject.toml check kfinance --fix
19
+ python -m ruff --config pyproject.toml format kfinance
17
20
  else
18
21
  python -m ruff --config pyproject.toml check kfinance
22
+ python -m ruff --config pyproject.toml format kfinance --check
19
23
  fi
File without changes