kensho-kfinance 2.7.0__py3-none-any.whl → 2.9.0__py3-none-any.whl

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 (58) hide show
  1. {kensho_kfinance-2.7.0.dist-info → kensho_kfinance-2.9.0.dist-info}/METADATA +2 -2
  2. kensho_kfinance-2.9.0.dist-info/RECORD +70 -0
  3. kfinance/CHANGELOG.md +6 -0
  4. kfinance/decimal_with_unit.py +78 -0
  5. kfinance/fetch.py +15 -16
  6. kfinance/kfinance.py +108 -122
  7. kfinance/meta_classes.py +28 -27
  8. kfinance/models/business_relationship_models.py +26 -0
  9. kfinance/models/capitalization_models.py +90 -0
  10. kfinance/models/competitor_models.py +13 -0
  11. kfinance/models/currency_models.py +345 -0
  12. kfinance/models/date_and_period_models.py +48 -0
  13. kfinance/models/id_models.py +7 -0
  14. kfinance/models/industry_models.py +12 -0
  15. kfinance/{constants.py → models/line_item_models.py} +1 -165
  16. kfinance/models/permission_models.py +15 -0
  17. kfinance/models/price_models.py +70 -0
  18. kfinance/models/segment_models.py +8 -0
  19. kfinance/models/statement_models.py +9 -0
  20. kfinance/tests/test_batch_requests.py +61 -31
  21. kfinance/tests/test_client.py +1 -1
  22. kfinance/tests/test_decimal_with_unit.py +60 -0
  23. kfinance/tests/test_example_notebook.py +1 -0
  24. kfinance/tests/test_fetch.py +23 -12
  25. kfinance/tests/test_models/__init__.py +0 -0
  26. kfinance/tests/test_models/test_capitalization_models.py +83 -0
  27. kfinance/tests/test_models/test_price_models.py +58 -0
  28. kfinance/tests/test_objects.py +107 -57
  29. kfinance/tests/test_tools.py +35 -11
  30. kfinance/tool_calling/get_advisors_for_company_in_transaction_from_identifier.py +10 -7
  31. kfinance/tool_calling/get_business_relationship_from_identifier.py +2 -1
  32. kfinance/tool_calling/get_capitalization_from_identifier.py +4 -5
  33. kfinance/tool_calling/get_competitors_from_identifier.py +2 -1
  34. kfinance/tool_calling/get_cusip_from_ticker.py +1 -1
  35. kfinance/tool_calling/get_earnings.py +1 -1
  36. kfinance/tool_calling/get_financial_line_item_from_identifier.py +3 -1
  37. kfinance/tool_calling/get_financial_statement_from_identifier.py +3 -1
  38. kfinance/tool_calling/get_history_metadata_from_identifier.py +2 -1
  39. kfinance/tool_calling/get_info_from_identifier.py +1 -1
  40. kfinance/tool_calling/get_isin_from_ticker.py +1 -1
  41. kfinance/tool_calling/get_latest.py +2 -1
  42. kfinance/tool_calling/get_latest_earnings.py +1 -1
  43. kfinance/tool_calling/get_merger_info_from_transaction_id.py +6 -5
  44. kfinance/tool_calling/get_mergers_from_identifier.py +4 -1
  45. kfinance/tool_calling/get_n_quarters_ago.py +2 -1
  46. kfinance/tool_calling/get_next_earnings.py +1 -1
  47. kfinance/tool_calling/get_prices_from_identifier.py +4 -3
  48. kfinance/tool_calling/get_segments_from_identifier.py +3 -1
  49. kfinance/tool_calling/get_transcript.py +1 -1
  50. kfinance/tool_calling/resolve_identifier.py +1 -1
  51. kfinance/tool_calling/shared_models.py +1 -1
  52. kfinance/version.py +2 -2
  53. kensho_kfinance-2.7.0.dist-info/RECORD +0 -54
  54. {kensho_kfinance-2.7.0.dist-info → kensho_kfinance-2.9.0.dist-info}/WHEEL +0 -0
  55. {kensho_kfinance-2.7.0.dist-info → kensho_kfinance-2.9.0.dist-info}/licenses/AUTHORS.md +0 -0
  56. {kensho_kfinance-2.7.0.dist-info → kensho_kfinance-2.9.0.dist-info}/licenses/LICENSE +0 -0
  57. {kensho_kfinance-2.7.0.dist-info → kensho_kfinance-2.9.0.dist-info}/top_level.txt +0 -0
  58. /kfinance/{tests/scratch.py → models/__init__.py} +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kensho-kfinance
3
- Version: 2.7.0
3
+ Version: 2.9.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
@@ -14,7 +14,7 @@ License-File: LICENSE
14
14
  License-File: AUTHORS.md
15
15
  Requires-Dist: cachetools<6,>=5.5
16
16
  Requires-Dist: click<=9,>=8.2.1
17
- Requires-Dist: fastmcp<3,>=2
17
+ Requires-Dist: fastmcp<2.10,>=2.9
18
18
  Requires-Dist: langchain-core>=0.3.15
19
19
  Requires-Dist: langchain-google-genai<3,>=2.1.5
20
20
  Requires-Dist: numpy>=1.22.4
@@ -0,0 +1,70 @@
1
+ kensho_kfinance-2.9.0.dist-info/licenses/AUTHORS.md,sha256=0h9ClbI0pu1oKj1M28ROUsaxrbZg-6ukQGl6X4y9noI,68
2
+ kensho_kfinance-2.9.0.dist-info/licenses/LICENSE,sha256=bsY4blvSgq6o0FMQ3RXa2NCgco--nHCCchLXzxr6kms,83
3
+ kfinance/CHANGELOG.md,sha256=vwLoxhyrR2AGSJbkfkvWYjjZQ6UBrfjOPSZq4eM9nok,2280
4
+ kfinance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ kfinance/batch_request_handling.py,sha256=G9rhpgQaCdb5C1dsfuJip8383iszibcOJ5k8gxld-tQ,5001
6
+ kfinance/decimal_with_unit.py,sha256=U1eJSJ-4zPHkdtHcrfaW9CmmaLPE13MiWJy6odRyeXo,2904
7
+ kfinance/fetch.py,sha256=MSdDddZ_1YdmzCuXqCXwY_vfFLdbdQeCJ6YRQrwCUCI,28157
8
+ kfinance/kfinance.py,sha256=ob5jNO5-aTSfBwknsSVCMLQJD5mWZkPTAZlvsBJ_Z2Y,72584
9
+ kfinance/mcp.py,sha256=MbktclVfBOEwfe-eR7kPaTXopMJmn_8RMlf4Jx5CXKU,3689
10
+ kfinance/meta_classes.py,sha256=0wI70PXfQzNbRUW2nYVfxJjqCqqI5EukUIKjaMcrzVA,21804
11
+ kfinance/prompt.py,sha256=PtVB8c_FcSlVdyGgByAnIFGzuUuBaEjciCqnBJl1hSQ,25133
12
+ kfinance/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ kfinance/pydantic_models.py,sha256=avpbPqwrAyLqsCbrmFpK_B8_fj1nPlBHrnPxRcBaSkE,774
14
+ kfinance/server_thread.py,sha256=jUnt1YGoYDkqqz1MbCwd44zJs1T_Z2BCgvj75bdtLgA,2574
15
+ kfinance/version.py,sha256=pqhLPO2SP7VnEU-lJpoO0qS9x0Kgz8BD6Rgr6J_aK-o,511
16
+ kfinance/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ kfinance/models/business_relationship_models.py,sha256=XlkYI_XUegORH4U4oLXjdFIX9Pr9FvQUnFAc67D2M4s,770
18
+ kfinance/models/capitalization_models.py,sha256=jB0MIZ94UOPfVckuS2asED9ARjisrStC_O4KgfHmoJw,3193
19
+ kfinance/models/competitor_models.py,sha256=0yDu49Pe28ErpCMLX-BBeUnjjxqerb49ToVKSTOivNk,565
20
+ kfinance/models/currency_models.py,sha256=JfDZf-nATCyjThBw-Ky2BNvM-n2oHepBLIHMCIyCRUE,19201
21
+ kfinance/models/date_and_period_models.py,sha256=B508v1SLy_mbSSuSbPz41xeFNRAeBFv41gJSlaXyHnU,1062
22
+ kfinance/models/id_models.py,sha256=xhFKmDddBfqkQZsbOP8za8VnxIFHiwvGThKjeGKC2Hg,138
23
+ kfinance/models/industry_models.py,sha256=ydB_cTIsNsfCUeaO7K2qqLUuHdG6WfUCoAzBigKVV8M,243
24
+ kfinance/models/line_item_models.py,sha256=JIdoSYxoJDQVkmqUK6_ABpb6lULXRvrCDJGiKL6kRhE,45399
25
+ kfinance/models/permission_models.py,sha256=z6MKY7Zf7StPKwsucsoVqltUesicU6MC6rxRGmlRwZI,557
26
+ kfinance/models/price_models.py,sha256=saiJk1ZIs02cHtY54-5YvS7NgH3EABR2RGT6wpzRauY,2149
27
+ kfinance/models/segment_models.py,sha256=GSJhK1HmbMmwRDFmrDTZzx8aYrAaHN13IJ0J9GTBn9Y,145
28
+ kfinance/models/statement_models.py,sha256=RmclTeyahCODUP0-KgZZZequFgQ2pUQ8cdfHI96c9vA,207
29
+ kfinance/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ kfinance/tests/conftest.py,sha256=dhL_RSc-af3j-2_UrAGRE9mxgcbjuIRtj08DTx79pQc,1123
31
+ kfinance/tests/test_batch_requests.py,sha256=JjP5OOKyxzYqmVmTR2hzM4Q6wyYDCEDHINH4vNFd6ag,11597
32
+ kfinance/tests/test_client.py,sha256=YZT-AXpFsVHpdoZj01d2TkmUkNP-8f3cIOgeXtP_05U,3870
33
+ kfinance/tests/test_decimal_with_unit.py,sha256=98zZmSLojWq3FS0e5AuNxv9eluqGVEoqM3r_agkmt_Y,2188
34
+ kfinance/tests/test_example_notebook.py,sha256=VFS2W_T0yEtd74YiRxj3KA7eEL_fJuCpWwUAkiFqzkc,6501
35
+ kfinance/tests/test_fetch.py,sha256=s8fSkXDtNjDcK_jWQYUO1stx9ElX1I54qG_48WxfBAc,18558
36
+ kfinance/tests/test_group_objects.py,sha256=SoMEZmkG4RYdgWOAwxLHHtzIQho92KM01YbQXPUg578,1689
37
+ kfinance/tests/test_objects.py,sha256=cpTE22omZATe-2j9jnuchgEiZtNM-wler95ainYoh_o,42471
38
+ kfinance/tests/test_tools.py,sha256=jLrugYTSdK6Cw4SmJxsxdYdJ1S3X7wDcBC7kQAWe75A,31024
39
+ kfinance/tests/test_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
+ kfinance/tests/test_models/test_capitalization_models.py,sha256=E-5eZX0ufdFsmcWATt5agyH4Ks-q8TNO-W6cnYIMOcE,3116
41
+ kfinance/tests/test_models/test_price_models.py,sha256=DHBMAFJ8axat1s_C0tElqcCjw6YhmzF9WWKpKmySwv0,2378
42
+ kfinance/tool_calling/README.md,sha256=omJq7Us6r4U45QB7hRpLjRJ5BMalCkZkh4uXBjTbJXc,2022
43
+ kfinance/tool_calling/__init__.py,sha256=UmtbtG6PvQHB1fInEL-K5q0kPHL__zTY9wzaPRSp1wg,2174
44
+ kfinance/tool_calling/get_advisors_for_company_in_transaction_from_identifier.py,sha256=IYpImoYfeq7Ep_IrUZgsSHC0oLSmI1mwuTR_1ftTPMY,1789
45
+ kfinance/tool_calling/get_business_relationship_from_identifier.py,sha256=oPlVpDy4AY8nQFZnHRp9DhpL8SecIlyEY6aiklHtVDg,1551
46
+ kfinance/tool_calling/get_capitalization_from_identifier.py,sha256=qciQI9gSJh4gGatnjOkid-GJSlzXkvt7-2VcK2yBfrg,1558
47
+ kfinance/tool_calling/get_competitors_from_identifier.py,sha256=J9TVWNU_6d6ltJLIJTdCtkhbc0MqoCbqdWUxrwBkOUs,1156
48
+ kfinance/tool_calling/get_cusip_from_ticker.py,sha256=ebzFmjZFkcuydntQXmuxfh8mhPiXmmzUTb2ncHy00ao,667
49
+ kfinance/tool_calling/get_earnings.py,sha256=d7UvVsSAcrVlveWyUpua35vdloA_QgJnQ4Nmg7wT7m0,1245
50
+ kfinance/tool_calling/get_financial_line_item_from_identifier.py,sha256=hsKmObT2TJ4HMusVtQXU6FMDmyY7bKg2V-x-IXuU71c,2270
51
+ kfinance/tool_calling/get_financial_statement_from_identifier.py,sha256=ba8Z378YrQ_J0-A6KVLOtxe-hYMP68780g0xXZfAyT8,2023
52
+ kfinance/tool_calling/get_history_metadata_from_identifier.py,sha256=hPC-RwwcnJ9kkhxTUJLE-xvCqfIq5kJcKM4deiL8zlI,789
53
+ kfinance/tool_calling/get_info_from_identifier.py,sha256=2-NmGvFpYXASGV_lJaYhhdXMxQpyvi30bXY9mGWwbBw,787
54
+ kfinance/tool_calling/get_isin_from_ticker.py,sha256=tp79lowBUdkv7fm-8QX4vJqeDZiq5M_jkkp8XKC1KY4,661
55
+ kfinance/tool_calling/get_latest.py,sha256=m6nBA8Bo51Q85kGbGnP59IUz4-lm_CRo1kSuNM26iXg,857
56
+ kfinance/tool_calling/get_latest_earnings.py,sha256=R98ImaONP3AjVshygkRLwcAHKscvVRkVoPw117O9nuw,1197
57
+ kfinance/tool_calling/get_merger_info_from_transaction_id.py,sha256=gB6VUmCAKS0OBclpcdp2gQq7cdxKbWTXt5Z8aMH_-ys,3243
58
+ kfinance/tool_calling/get_mergers_from_identifier.py,sha256=tgpcLQM1CPvyk4_xyUhcZh01kAzwdkQCV6gq-bEsFhA,1935
59
+ kfinance/tool_calling/get_n_quarters_ago.py,sha256=VYUBbQIowHXmNuln1oKoDKeWDbnXLg4p6X0d1HoY_NY,784
60
+ kfinance/tool_calling/get_next_earnings.py,sha256=vL3sCoocPhHDRawVRu9IyQPLXVAgODrZgKSqkP3Scs8,1177
61
+ kfinance/tool_calling/get_prices_from_identifier.py,sha256=uXD9fiLFI0vUM_YY8DI_9ifC0oeeC3KCyaTQQ0IjuSA,1966
62
+ kfinance/tool_calling/get_segments_from_identifier.py,sha256=1Ux9ZWEU3xmOSuAPGedo2r8wdRa_glv8roghp08MJ-c,1980
63
+ kfinance/tool_calling/get_transcript.py,sha256=urZgpQXigmahy-vj6OjkGI9O6HJcPIpd-5CRU7NI3YQ,782
64
+ kfinance/tool_calling/prompts.py,sha256=Yw1DJIMh90cjL-8q6_RMRiSjCtFDXvJAy7QiV5_uAU8,911
65
+ kfinance/tool_calling/resolve_identifier.py,sha256=Rkhwi6m3hffE19qaxRkrsu6slRKyiAXjfLr8L41N2zc,647
66
+ kfinance/tool_calling/shared_models.py,sha256=Sx_zlwk5YLu533406Pmh499NH5oTBWrZf8Ua8zoUSRk,3746
67
+ kensho_kfinance-2.9.0.dist-info/METADATA,sha256=NhJXLeMBY0A1QP2PaA2BWB7-m-cUxY1wqp7TlDRqPAY,6202
68
+ kensho_kfinance-2.9.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
69
+ kensho_kfinance-2.9.0.dist-info/top_level.txt,sha256=kT_kNwVhfQoOAecY8W7uYah5xaHMoHoAdBIvXh6DaKM,9
70
+ kensho_kfinance-2.9.0.dist-info/RECORD,,
kfinance/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## v2.9.0
4
+ - Limit FastMCP version
5
+
6
+ ## v2.8.0
7
+ - Add currency to get_capitalization and get_prices tools.
8
+
3
9
  ## v2.7.0
4
10
  - Expose a new list of LLM tools `grounding_tools` that return a list of all endpoint urls called
5
11
 
@@ -0,0 +1,78 @@
1
+ from copy import deepcopy
2
+ from decimal import Decimal
3
+ from typing import Any
4
+
5
+ from pydantic import BaseModel, Field, model_validator
6
+ from typing_extensions import Self
7
+
8
+ from kfinance.models.currency_models import ISO_CODE_TO_CURRENCY
9
+
10
+
11
+ class DecimalWithUnit(BaseModel):
12
+ """DecimalWithUnit (DWU) represents a decimal with a corresponding unit like $100 or 20 shares.
13
+
14
+ In addition to a value and unit, each DWU has a `conventional_decimals` attribute,
15
+ which indicates the number of decimals that should be represented.
16
+ For example, for USD, conventional_decimals is 2, which will display as "1.00".
17
+ For shares, conventional_decimals is 0, which will display as "1"
18
+
19
+ Usually, rather than initializing a DWU directly, you'll likely want to use an
20
+ existing subclass like `Money` or `Shares` or create a new one.
21
+ """
22
+
23
+ value: Decimal
24
+ unit: str
25
+ # exclude conventional_decimals from serialization
26
+ conventional_decimals: int = Field(exclude=True)
27
+
28
+ @model_validator(mode="after")
29
+ def quantize_value(self) -> Self:
30
+ """Quantize the value at the end of the deserialization.
31
+
32
+ The value gets adjusted so that it always has the expected number of decimals defined in
33
+ conventional_decimals.
34
+ For USD with conventional_decimals=2, it will show values like "1.00"
35
+ For Shares with conventional_decimals=0, it will show values like "1"
36
+ """
37
+ exponent = Decimal("10") ** Decimal(-self.conventional_decimals)
38
+ self.value = self.value.quantize(exp=exponent)
39
+ return self
40
+
41
+
42
+ class Money(DecimalWithUnit):
43
+ @model_validator(mode="before")
44
+ @classmethod
45
+ def inject_conventional_decimals_into_data(cls, data: Any) -> Any:
46
+ """Inject conventional_decimals into data dict.
47
+
48
+ Each currency has an associated conventional_decimals defined in the
49
+ CURRENCIES list. This validator fetches that number and injects it into the
50
+ data dict.
51
+ """
52
+
53
+ if isinstance(data, dict) and "conventional_decimals" not in data:
54
+ data = deepcopy(data)
55
+ currency = ISO_CODE_TO_CURRENCY[data["unit"]]
56
+ data["conventional_decimals"] = currency.conventional_decimals
57
+
58
+ return data
59
+
60
+
61
+ class Shares(DecimalWithUnit):
62
+ unit: str = "Shares"
63
+ conventional_decimals: int = Field(exclude=True, default=0)
64
+
65
+ @model_validator(mode="before")
66
+ @classmethod
67
+ def convert_numbers_to_dicts(cls, data: Any) -> Any:
68
+ """Convert numbers into dicts.
69
+
70
+ The shares class can be built from a single number because unit and
71
+ conventional_decimals are always the same. However, the parser expects a
72
+ dict instead of a number, so we have to convert any number ("10") into a
73
+ dict {"value": "10"}.
74
+ """
75
+
76
+ if isinstance(data, (str, int, float, Decimal)):
77
+ data = {"value": data}
78
+ return data
kfinance/fetch.py CHANGED
@@ -10,23 +10,22 @@ import jwt
10
10
  from pydantic import ValidationError
11
11
  import requests
12
12
 
13
- from .constants import (
14
- BusinessRelationshipType,
15
- CompetitorSource,
16
- IdentificationTriple,
17
- IndustryClassification,
18
- Periodicity,
19
- PeriodType,
20
- Permission,
21
- SegmentType,
22
- )
23
- from .pydantic_models import RelationshipResponse, RelationshipResponseNoName
13
+ from kfinance.models.business_relationship_models import BusinessRelationshipType
14
+ from kfinance.models.capitalization_models import Capitalizations
15
+ from kfinance.models.competitor_models import CompetitorSource
16
+ from kfinance.models.date_and_period_models import Periodicity, PeriodType
17
+ from kfinance.models.id_models import IdentificationTriple
18
+ from kfinance.models.industry_models import IndustryClassification
19
+ from kfinance.models.permission_models import Permission
20
+ from kfinance.models.price_models import PriceHistory
21
+ from kfinance.models.segment_models import SegmentType
22
+ from kfinance.pydantic_models import RelationshipResponse, RelationshipResponseNoName
24
23
 
25
24
 
26
25
  # version.py gets autogenerated by setuptools-scm and is not available
27
26
  # during local development.
28
27
  try:
29
- from .version import __version__ as kfinance_version
28
+ from kfinance.version import __version__ as kfinance_version
30
29
  except ImportError:
31
30
  kfinance_version = "dev"
32
31
 
@@ -300,7 +299,7 @@ class KFinanceApiClient:
300
299
  start_date: Optional[str] = None,
301
300
  end_date: Optional[str] = None,
302
301
  periodicity: Optional[Periodicity] = None,
303
- ) -> dict:
302
+ ) -> PriceHistory:
304
303
  """Get the pricing history."""
305
304
  url = (
306
305
  f"{self.url_base}pricing/{trading_item_id}/"
@@ -309,7 +308,7 @@ class KFinanceApiClient:
309
308
  f"{periodicity if periodicity else 'none'}/"
310
309
  f"{'adjusted' if is_adjusted else 'unadjusted'}"
311
310
  )
312
- return self.fetch(url)
311
+ return PriceHistory.model_validate(self.fetch(url))
313
312
 
314
313
  def fetch_history_metadata(self, trading_item_id: int) -> dict[str, str]:
315
314
  """Get the pricing history metadata."""
@@ -321,14 +320,14 @@ class KFinanceApiClient:
321
320
  company_id: int,
322
321
  start_date: Optional[str] = None,
323
322
  end_date: Optional[str] = None,
324
- ) -> dict:
323
+ ) -> Capitalizations:
325
324
  """Get the market cap, TEV, and shares outstanding for a company."""
326
325
  url = (
327
326
  f"{self.url_base}market_cap/{company_id}/"
328
327
  f"{start_date if start_date is not None else 'none'}/"
329
328
  f"{end_date if end_date is not None else 'none'}"
330
329
  )
331
- return self.fetch(url)
330
+ return Capitalizations.model_validate(self.fetch(url))
332
331
 
333
332
  def fetch_segments(
334
333
  self,
kfinance/kfinance.py CHANGED
@@ -15,33 +15,28 @@ import webbrowser
15
15
  import google.ai.generativelanguage_v1beta.types as gapic
16
16
  from langchain_core.utils.function_calling import convert_to_openai_tool
17
17
  from langchain_google_genai._function_utils import convert_to_genai_function_declarations
18
- import numpy as np
19
18
  import pandas as pd
20
19
  from PIL.Image import Image, open as image_open
21
20
 
22
- from .batch_request_handling import add_methods_of_singular_class_to_iterable_class
23
- from .constants import (
24
- HistoryMetadata,
25
- IdentificationTriple,
26
- IndustryClassification,
27
- LatestPeriods,
28
- Periodicity,
29
- YearAndQuarter,
30
- )
31
- from .fetch import (
21
+ from kfinance.batch_request_handling import add_methods_of_singular_class_to_iterable_class
22
+ from kfinance.fetch import (
32
23
  DEFAULT_API_HOST,
33
24
  DEFAULT_API_VERSION,
34
25
  DEFAULT_OKTA_AUTH_SERVER,
35
26
  DEFAULT_OKTA_HOST,
36
27
  KFinanceApiClient,
37
28
  )
38
- from .meta_classes import (
29
+ from kfinance.meta_classes import (
39
30
  CompanyFunctionsMetaClass,
40
31
  DelegatedCompanyFunctionsMetaClass,
41
32
  )
42
- from .prompt import PROMPT
43
- from .pydantic_models import TranscriptComponent
44
- from .server_thread import ServerThread
33
+ from kfinance.models.date_and_period_models import LatestPeriods, Periodicity, YearAndQuarter
34
+ from kfinance.models.id_models import IdentificationTriple
35
+ from kfinance.models.industry_models import IndustryClassification
36
+ from kfinance.models.price_models import HistoryMetadata, PriceHistory
37
+ from kfinance.prompt import PROMPT
38
+ from kfinance.pydantic_models import TranscriptComponent
39
+ from kfinance.server_thread import ServerThread
45
40
 
46
41
 
47
42
  if TYPE_CHECKING:
@@ -140,36 +135,29 @@ class TradingItem:
140
135
  adjusted: bool = True,
141
136
  start_date: Optional[str] = None,
142
137
  end_date: Optional[str] = None,
143
- ) -> pd.DataFrame:
138
+ ) -> PriceHistory:
144
139
  """Retrieves the historical price data for a given asset over a specified date range.
145
140
 
146
141
  :param periodicity: Determines the frequency of the historical data returned. Defaults to Periodicity.day.
147
142
  :param Optional[bool] adjusted: Whether to retrieve adjusted prices that account for corporate actions such as dividends and splits, it defaults True
148
143
  :param Optional[str] start_date: The start date for historical price retrieval in format "YYYY-MM-DD", default to None
149
144
  :param Optional[str] end_date: The end date for historical price retrieval in format "YYYY-MM-DD", default to None
150
- :return: A pd.DataFrame containing historical price data with columns corresponding to the specified periodicity, with Date as the index, and columns "open", "high", "low", "close", "volume" in type decimal. The Date index is a string that depends on the periodicity. If Periodicity.day, the Date index is the day in format "YYYY-MM-DD", eg "2024-05-13" If Periodicity.week, the Date index is the week number of the year in format "YYYY Week ##", eg "2024 Week 2" If Periodicity.month, the Date index is the month name of the year in format "<Month> YYYY", eg "January 2024". If Periodicity.year, the Date index is the year in format "YYYY", eg "2024".
151
- :rtype: pd.DataFrame
145
+ :return: A PriceHistory containing historical price data including "open", "high", "low", "close", "volume" in type Money. The date value is a string that depends on the periodicity. If Periodicity.day, the Date index is the day in format "YYYY-MM-DD", eg "2024-05-13" If Periodicity.week, the Date index is the week number of the year in format "YYYY Week ##", eg "2024 Week 2" If Periodicity.month, the Date index is the month name of the year in format "<Month> YYYY", eg "January 2024". If Periodicity.year, the Date index is the year in format "YYYY", eg "2024".
146
+ :rtype: PriceHistory
152
147
  """
153
148
  if start_date and end_date:
154
149
  if (
155
150
  datetime.strptime(start_date, "%Y-%m-%d").date()
156
151
  > datetime.strptime(end_date, "%Y-%m-%d").date()
157
152
  ):
158
- return pd.DataFrame()
153
+ return PriceHistory(prices=[])
159
154
 
160
- return (
161
- pd.DataFrame(
162
- self.kfinance_api_client.fetch_history(
163
- trading_item_id=self.trading_item_id,
164
- is_adjusted=adjusted,
165
- start_date=start_date,
166
- end_date=end_date,
167
- periodicity=periodicity,
168
- )["prices"]
169
- )
170
- .set_index("date")
171
- .apply(pd.to_numeric)
172
- .replace(np.nan, None)
155
+ return self.kfinance_api_client.fetch_history(
156
+ trading_item_id=self.trading_item_id,
157
+ is_adjusted=adjusted,
158
+ start_date=start_date,
159
+ end_date=end_date,
160
+ periodicity=periodicity,
173
161
  )
174
162
 
175
163
  def price_chart(
@@ -653,83 +641,77 @@ class Company(CompanyFunctionsMetaClass):
653
641
  return self._mergers_for_company
654
642
 
655
643
 
656
- class AdvisedCompany(Company):
644
+ class ParticipantInMerger:
657
645
  """A Company that has been involved in a transaction is a company that may have been advised."""
658
646
 
659
647
  def __init__(
660
- self,
661
- kfinance_api_client: KFinanceApiClient,
662
- company_id: int,
663
- transaction_id: int,
664
- company_name: str | None = None,
648
+ self, kfinance_api_client: KFinanceApiClient, transaction_id: int, company: Company
665
649
  ):
666
650
  """Initialize the AdvisedCompany object
667
651
 
668
652
  :param kfinance_api_client: The KFinanceApiClient used to fetch data
669
653
  :type kfinance_api_client: KFinanceApiClient
670
- :param company_id: The S&P Global CIQ Company Id
671
- :type company_id: int
672
654
  :param transaction_id: The S&P Global CIP Transaction Id
673
655
  :type transaction_id: int
656
+ :param company: The company object
657
+ :type company: Company
674
658
  """
675
-
676
- super().__init__(
677
- kfinance_api_client=kfinance_api_client,
678
- company_id=company_id,
679
- company_name=company_name,
680
- )
659
+ self.kfinance_api_client = kfinance_api_client
681
660
  self.transaction_id = transaction_id
661
+ self._company = company
662
+
663
+ @property
664
+ def company(self) -> Company:
665
+ """Get the specific Company object."""
666
+ return self._company
682
667
 
683
668
  @property
684
- def advisors(self) -> Companies | None:
669
+ def advisors(self) -> list[Advisor] | None:
685
670
  """Get the companies that advised this company during the current transaction."""
686
671
  advisors = self.kfinance_api_client.fetch_advisors_for_company_in_merger(
687
- transaction_id=self.transaction_id, advised_company_id=self.company_id
672
+ transaction_id=self.transaction_id, advised_company_id=self._company.company_id
688
673
  )["advisors"]
689
- companies = [
690
- AdvisorCompany(
691
- kfinance_api_client=self.kfinance_api_client,
692
- company_id=int(advisor["advisor_company_id"]),
693
- company_name=str(advisor["advisor_company_name"]),
674
+ return [
675
+ Advisor(
694
676
  advisor_type_name=str(advisor["advisor_type_name"]),
677
+ company=Company(
678
+ kfinance_api_client=self.kfinance_api_client,
679
+ company_id=int(advisor["advisor_company_id"]),
680
+ company_name=str(advisor["advisor_company_name"]),
681
+ ),
695
682
  )
696
683
  for advisor in advisors
697
684
  ]
698
- return Companies(kfinance_api_client=self.kfinance_api_client, companies=companies)
699
685
 
700
686
 
701
- class AdvisorCompany(Company):
687
+ class Advisor:
702
688
  """A company that advised another company during a transaction."""
703
689
 
704
690
  def __init__(
705
691
  self,
706
- kfinance_api_client: KFinanceApiClient,
707
- company_id: int,
708
- advisor_type_name: str,
709
- company_name: str | None = None,
692
+ advisor_type_name: str | None,
693
+ company: Company,
710
694
  ):
711
695
  """Initialize the AdvisorCompany object
712
696
 
713
- :param kfinance_api_client: The KFinanceApiClient used to fetch data
714
- :type kfinance_api_client: KFinanceApiClient
715
- :param company_id: The S&P Global CIQ Company Id
716
- :type company_id: int
697
+ :param company: The company that advised
698
+ :type company: Company
717
699
  :param advisor_type_name: The type of the advisor company
718
700
  :type advisor_type_name: str
719
701
  """
720
-
721
- super().__init__(
722
- kfinance_api_client=kfinance_api_client,
723
- company_id=company_id,
724
- company_name=company_name,
725
- )
726
702
  self._advisor_type_name = advisor_type_name
703
+ self._company = company
727
704
 
728
705
  @property
729
706
  def advisor_type_name(self) -> str | None:
730
707
  """When this company advised another during a transaction, get the advisor type name."""
731
708
  return self._advisor_type_name
732
709
 
710
+ @property
711
+ def company(self) -> Company:
712
+ """Get the Company object."""
713
+ return self._company
714
+
733
715
 
734
716
  class Security:
735
717
  """Security class
@@ -815,7 +797,11 @@ class Security:
815
797
  "trading_items"
816
798
  ]
817
799
  self._trading_items = TradingItems(
818
- kfinance_api_client=self.kfinance_api_client, trading_item_ids=trading_item_ids
800
+ kfinance_api_client=self.kfinance_api_client,
801
+ trading_items=[
802
+ TradingItem(kfinance_api_client=self.kfinance_api_client, trading_item_id=tii)
803
+ for tii in trading_item_ids
804
+ ],
819
805
  )
820
806
  return self._trading_items
821
807
 
@@ -1194,7 +1180,7 @@ class Ticker(DelegatedCompanyFunctionsMetaClass):
1194
1180
  adjusted: bool = True,
1195
1181
  start_date: Optional[str] = None,
1196
1182
  end_date: Optional[str] = None,
1197
- ) -> pd.DataFrame:
1183
+ ) -> PriceHistory:
1198
1184
  """Retrieves the historical price data for a given asset over a specified date range.
1199
1185
 
1200
1186
  :param periodicity: Determines the frequency of the historical data returned. Defaults to Periodicity.day.
@@ -1205,8 +1191,8 @@ class Ticker(DelegatedCompanyFunctionsMetaClass):
1205
1191
  :type start_date: str, optional
1206
1192
  :param end_date: The end date for historical price retrieval in format "YYYY-MM-DD", default to None
1207
1193
  :type end_date: str, optional
1208
- :return: A pd.DataFrame containing historical price data with columns corresponding to the specified periodicity, with Date as the index, and columns "open", "high", "low", "close", "volume" in type decimal. The Date index is a string that depends on the periodicity. If Periodicity.day, the Date index is the day in format "YYYY-MM-DD", eg "2024-05-13" If Periodicity.week, the Date index is the week number of the year in format "YYYY Week ##", eg "2024 Week 2" If Periodicity.month, the Date index is the month name of the year in format "<Month> YYYY", eg "January 2024". If Periodicity.year, the Date index is the year in format "YYYY", eg "2024".
1209
- :rtype: pd.DataFrame
1194
+ :return: A PriceHistory containing historical price data including "open", "high", "low", "close", "volume" in type Money. The date value is a string that depends on the periodicity. If Periodicity.day, the Date index is the day in format "YYYY-MM-DD", eg "2024-05-13" If Periodicity.week, the Date index is the week number of the year in format "YYYY Week ##", eg "2024 Week 2" If Periodicity.month, the Date index is the month name of the year in format "<Month> YYYY", eg "January 2024". If Periodicity.year, the Date index is the year in format "YYYY", eg "2024".
1195
+ :rtype: PriceHistory
1210
1196
  """
1211
1197
  return self.primary_trading_item.history(
1212
1198
  periodicity,
@@ -1261,7 +1247,11 @@ class MergerOrAcquisition:
1261
1247
  """An object that represents a merger or an acquisition of a company."""
1262
1248
 
1263
1249
  def __init__(
1264
- self, kfinance_api_client: KFinanceApiClient, transaction_id: int, merger_title: str | None
1250
+ self,
1251
+ kfinance_api_client: KFinanceApiClient,
1252
+ transaction_id: int,
1253
+ merger_title: str | None,
1254
+ closed_date: date | None,
1265
1255
  ) -> None:
1266
1256
  """MergerOrAcqusition initializer.
1267
1257
 
@@ -1272,6 +1262,7 @@ class MergerOrAcquisition:
1272
1262
  self.kfinance_api_client = kfinance_api_client
1273
1263
  self.transaction_id = transaction_id
1274
1264
  self.merger_title = merger_title
1265
+ self.closed_date = closed_date
1275
1266
  self._merger_info: dict | None = None
1276
1267
 
1277
1268
  @property
@@ -1309,36 +1300,39 @@ class MergerOrAcquisition:
1309
1300
  Each category is a single Company or a list of Companies.
1310
1301
  """
1311
1302
  return {
1312
- "target": AdvisedCompany(
1303
+ "target": ParticipantInMerger(
1313
1304
  kfinance_api_client=self.kfinance_api_client,
1314
- company_id=self.merger_info["participants"]["target"]["company_id"],
1315
- company_name=self.merger_info["participants"]["target"]["company_name"],
1316
1305
  transaction_id=self.transaction_id,
1306
+ company=Company(
1307
+ kfinance_api_client=self.kfinance_api_client,
1308
+ company_id=self.merger_info["participants"]["target"]["company_id"],
1309
+ company_name=self.merger_info["participants"]["target"]["company_name"],
1310
+ ),
1317
1311
  ),
1318
- "buyers": Companies(
1319
- kfinance_api_client=self.kfinance_api_client,
1320
- companies=[
1321
- AdvisedCompany(
1312
+ "buyers": [
1313
+ ParticipantInMerger(
1314
+ kfinance_api_client=self.kfinance_api_client,
1315
+ transaction_id=self.transaction_id,
1316
+ company=Company(
1322
1317
  kfinance_api_client=self.kfinance_api_client,
1323
1318
  company_id=company["company_id"],
1324
1319
  company_name=company["company_name"],
1325
- transaction_id=self.transaction_id,
1326
- )
1327
- for company in self.merger_info["participants"]["buyers"]
1328
- ],
1329
- ),
1330
- "sellers": Companies(
1331
- kfinance_api_client=self.kfinance_api_client,
1332
- companies=[
1333
- AdvisedCompany(
1320
+ ),
1321
+ )
1322
+ for company in self.merger_info["participants"]["buyers"]
1323
+ ],
1324
+ "sellers": [
1325
+ ParticipantInMerger(
1326
+ kfinance_api_client=self.kfinance_api_client,
1327
+ transaction_id=self.transaction_id,
1328
+ company=Company(
1334
1329
  kfinance_api_client=self.kfinance_api_client,
1335
1330
  company_id=company["company_id"],
1336
1331
  company_name=company["company_name"],
1337
- transaction_id=self.transaction_id,
1338
- )
1339
- for company in self.merger_info["participants"]["sellers"]
1340
- ],
1341
- ),
1332
+ ),
1333
+ )
1334
+ for company in self.merger_info["participants"]["sellers"]
1335
+ ],
1342
1336
  }
1343
1337
 
1344
1338
  @property
@@ -1368,7 +1362,6 @@ class Companies(set):
1368
1362
  self,
1369
1363
  kfinance_api_client: KFinanceApiClient,
1370
1364
  company_ids: Optional[Iterable[int]] = None,
1371
- transaction_id: Optional[int] = None,
1372
1365
  companies: Optional[Iterable[Company]] = None,
1373
1366
  ) -> None:
1374
1367
  """Initialize the Companies object
@@ -1377,8 +1370,6 @@ class Companies(set):
1377
1370
  :type kfinance_api_client: KFinanceApiClient
1378
1371
  :param company_ids: An iterable of S&P CIQ Company ids
1379
1372
  :type company_ids: Iterable[int]
1380
- :param transaction_id: If the companies were party to a transaction, the S&P CIQ Transaction Id
1381
- :type transaction_id: Optional[int]
1382
1373
  :param companies: If there's already an iterable of Company objects
1383
1374
  :type companies: Iterable[Company]
1384
1375
  """
@@ -1386,23 +1377,13 @@ class Companies(set):
1386
1377
  if companies is not None:
1387
1378
  super().__init__(company for company in companies)
1388
1379
  elif company_ids is not None:
1389
- if transaction_id is not None:
1390
- super().__init__(
1391
- AdvisedCompany(
1392
- kfinance_api_client=kfinance_api_client,
1393
- company_id=company_id,
1394
- transaction_id=transaction_id,
1395
- )
1396
- for company_id in company_ids
1397
- )
1398
- else:
1399
- super().__init__(
1400
- Company(
1401
- kfinance_api_client=kfinance_api_client,
1402
- company_id=company_id,
1403
- )
1404
- for company_id in company_ids
1380
+ super().__init__(
1381
+ Company(
1382
+ kfinance_api_client=kfinance_api_client,
1383
+ company_id=company_id,
1405
1384
  )
1385
+ for company_id in company_ids
1386
+ )
1406
1387
 
1407
1388
 
1408
1389
  @add_methods_of_singular_class_to_iterable_class(Security)
@@ -1425,20 +1406,17 @@ class TradingItems(set):
1425
1406
  """Base class for representing a set of Trading Items"""
1426
1407
 
1427
1408
  def __init__(
1428
- self, kfinance_api_client: KFinanceApiClient, trading_item_ids: Iterable[int]
1409
+ self, kfinance_api_client: KFinanceApiClient, trading_items: Iterable[TradingItem]
1429
1410
  ) -> None:
1430
1411
  """Initialize the Trading Items
1431
1412
 
1432
1413
  :param kfinance_api_client: The KFinanceApiClient used to fetch data
1433
1414
  :type kfinance_api_client: KFinanceApiClient
1434
- :param company_ids: An iterable of S&P CIQ Company ids
1435
- :type company_ids: Iterable[int]
1415
+ :param trading_items: An iterable of TradingItem
1416
+ :type trading_items: Iterable[TradingItem]
1436
1417
  """
1437
1418
  self.kfinance_api_client = kfinance_api_client
1438
- super().__init__(
1439
- TradingItem(kfinance_api_client, trading_item_id)
1440
- for trading_item_id in trading_item_ids
1441
- )
1419
+ super().__init__(trading_items)
1442
1420
 
1443
1421
 
1444
1422
  @add_methods_of_singular_class_to_iterable_class(Ticker)
@@ -1515,7 +1493,14 @@ class Tickers(set):
1515
1493
  :rtype: TradingItems
1516
1494
  """
1517
1495
  return TradingItems(
1518
- self.kfinance_api_client, (ticker.trading_item_id for ticker in self.__iter__())
1496
+ self.kfinance_api_client,
1497
+ [
1498
+ TradingItem(
1499
+ kfinance_api_client=self.kfinance_api_client,
1500
+ trading_item_id=ticker.trading_item_id,
1501
+ )
1502
+ for ticker in self.__iter__()
1503
+ ],
1519
1504
  )
1520
1505
 
1521
1506
 
@@ -1537,6 +1522,7 @@ class MergersAndAcquisitions(set):
1537
1522
  kfinance_api_client=kfinance_api_client,
1538
1523
  transaction_id=id_and_title["transaction_id"],
1539
1524
  merger_title=id_and_title["merger_title"],
1525
+ closed_date=id_and_title["closed_date"],
1540
1526
  )
1541
1527
  for id_and_title in ids_and_titles
1542
1528
  )