hyean 0.4.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.
- hyean-0.4.0/PKG-INFO +78 -0
- hyean-0.4.0/README.md +46 -0
- hyean-0.4.0/hyean.egg-info/PKG-INFO +78 -0
- hyean-0.4.0/hyean.egg-info/SOURCES.txt +38 -0
- hyean-0.4.0/hyean.egg-info/dependency_links.txt +1 -0
- hyean-0.4.0/hyean.egg-info/requires.txt +15 -0
- hyean-0.4.0/hyean.egg-info/top_level.txt +1 -0
- hyean-0.4.0/pyproject.toml +53 -0
- hyean-0.4.0/sdk/__init__.py +115 -0
- hyean-0.4.0/sdk/audit.py +17 -0
- hyean-0.4.0/sdk/benchmark.py +32 -0
- hyean-0.4.0/sdk/cache.py +89 -0
- hyean-0.4.0/sdk/client.py +97 -0
- hyean-0.4.0/sdk/companies.py +130 -0
- hyean-0.4.0/sdk/config.py +77 -0
- hyean-0.4.0/sdk/context.py +68 -0
- hyean-0.4.0/sdk/coverage.py +23 -0
- hyean-0.4.0/sdk/deep.py +23 -0
- hyean-0.4.0/sdk/discover.py +23 -0
- hyean-0.4.0/sdk/enhanced.py +148 -0
- hyean-0.4.0/sdk/events.py +115 -0
- hyean-0.4.0/sdk/exceptions.py +25 -0
- hyean-0.4.0/sdk/filings.py +51 -0
- hyean-0.4.0/sdk/financials.py +175 -0
- hyean-0.4.0/sdk/grades.py +18 -0
- hyean-0.4.0/sdk/groups.py +66 -0
- hyean-0.4.0/sdk/hub.py +221 -0
- hyean-0.4.0/sdk/index.py +53 -0
- hyean-0.4.0/sdk/macro.py +62 -0
- hyean-0.4.0/sdk/meta.py +31 -0
- hyean-0.4.0/sdk/names.py +373 -0
- hyean-0.4.0/sdk/prices.py +48 -0
- hyean-0.4.0/sdk/profile.py +77 -0
- hyean-0.4.0/sdk/segments.py +50 -0
- hyean-0.4.0/sdk/source.py +48 -0
- hyean-0.4.0/sdk/utils.py +167 -0
- hyean-0.4.0/sdk/valuation.py +18 -0
- hyean-0.4.0/setup.cfg +4 -0
- hyean-0.4.0/tests/test_reference.py +48 -0
- hyean-0.4.0/tests/test_smoke.py +92 -0
hyean-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hyean
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Korean financial data SDK — DART 5소스 교차검증, LLM-ready
|
|
5
|
+
Author-email: Hyean <support@hyean.io>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://hyean.io
|
|
8
|
+
Project-URL: Documentation, https://hyean.io/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/twiw49/hyean
|
|
10
|
+
Keywords: korea,finance,dart,financial-data,xbrl,valuation,llm
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
Requires-Dist: pandas>=2.0
|
|
21
|
+
Requires-Dist: requests>=2.28
|
|
22
|
+
Provides-Extra: parquet
|
|
23
|
+
Requires-Dist: pyarrow>=12.0; extra == "parquet"
|
|
24
|
+
Provides-Extra: server
|
|
25
|
+
Requires-Dist: fastapi>=0.115.0; extra == "server"
|
|
26
|
+
Requires-Dist: uvicorn[standard]>=0.30.0; extra == "server"
|
|
27
|
+
Requires-Dist: pydantic>=2.7.0; extra == "server"
|
|
28
|
+
Requires-Dist: pydantic-settings>=2.3.0; extra == "server"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest; extra == "dev"
|
|
31
|
+
Requires-Dist: httpx; extra == "dev"
|
|
32
|
+
|
|
33
|
+
# hyean — Korean financial data SDK
|
|
34
|
+
|
|
35
|
+
DART 원문 기반 **5소스 교차검증** 한국 상장기업 재무 데이터. 모든 수치에 confidence 등급과 원문 출처(report_url + anchor)가 따라옵니다.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install git+https://github.com/twiw49/hyean-sdk.git # 또는: pip install hyean
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import hyean as hy
|
|
43
|
+
|
|
44
|
+
hy.set_api_key("hyn_live_xxxx") # 또는 export HYEAN_API_KEY=...
|
|
45
|
+
# base_url 기본값 = https://api.hyean.io (생략 가능)
|
|
46
|
+
|
|
47
|
+
# 재무제표 → pandas DataFrame (식별자: 종목코드 / corp_code / 기업명)
|
|
48
|
+
bs = hy.load_balance("삼성전자")
|
|
49
|
+
is_ = hy.load_income("005930", min_confidence="high") # 품질 필터
|
|
50
|
+
cf = hy.load_cashflow("00126380")
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### dart-fss와 다른 점 — point-in-time(정정 소급반영)
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
# 특정 시점 기준으로 본 재무 — 이후 정정공시를 반영/미반영해 백테스트 무결성 확보
|
|
57
|
+
bs_then = hy.load_balance("005930", as_of="2023-03-31")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`as_of`는 survivorship bias와 미반영 정정으로 백테스트가 틀어지는 문제를 막습니다 — 무료 오픈소스가 싸게 제공하지 못하는 지점입니다.
|
|
61
|
+
|
|
62
|
+
### 원문 추적
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
bs = hy.load_balance("005930")
|
|
66
|
+
url = hy.source_url(bs, "BS_AST_TOT", "2024") # 이 숫자의 DART 원문 위치
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### CompanyHub — 한 기업, 여러 관점
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
hub = hy.CompanyHub("005930")
|
|
73
|
+
hub.balance, hub.income, hub.cashflow, hub.audit, hub.profile, hub.risk
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
API 키 발급: https://hyean.io · 문서: https://api.hyean.io/docs · 가격: https://hyean.io/pricing
|
hyean-0.4.0/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# hyean — Korean financial data SDK
|
|
2
|
+
|
|
3
|
+
DART 원문 기반 **5소스 교차검증** 한국 상장기업 재무 데이터. 모든 수치에 confidence 등급과 원문 출처(report_url + anchor)가 따라옵니다.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install git+https://github.com/twiw49/hyean-sdk.git # 또는: pip install hyean
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
import hyean as hy
|
|
11
|
+
|
|
12
|
+
hy.set_api_key("hyn_live_xxxx") # 또는 export HYEAN_API_KEY=...
|
|
13
|
+
# base_url 기본값 = https://api.hyean.io (생략 가능)
|
|
14
|
+
|
|
15
|
+
# 재무제표 → pandas DataFrame (식별자: 종목코드 / corp_code / 기업명)
|
|
16
|
+
bs = hy.load_balance("삼성전자")
|
|
17
|
+
is_ = hy.load_income("005930", min_confidence="high") # 품질 필터
|
|
18
|
+
cf = hy.load_cashflow("00126380")
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### dart-fss와 다른 점 — point-in-time(정정 소급반영)
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
# 특정 시점 기준으로 본 재무 — 이후 정정공시를 반영/미반영해 백테스트 무결성 확보
|
|
25
|
+
bs_then = hy.load_balance("005930", as_of="2023-03-31")
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`as_of`는 survivorship bias와 미반영 정정으로 백테스트가 틀어지는 문제를 막습니다 — 무료 오픈소스가 싸게 제공하지 못하는 지점입니다.
|
|
29
|
+
|
|
30
|
+
### 원문 추적
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
bs = hy.load_balance("005930")
|
|
34
|
+
url = hy.source_url(bs, "BS_AST_TOT", "2024") # 이 숫자의 DART 원문 위치
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### CompanyHub — 한 기업, 여러 관점
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
hub = hy.CompanyHub("005930")
|
|
41
|
+
hub.balance, hub.income, hub.cashflow, hub.audit, hub.profile, hub.risk
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
API 키 발급: https://hyean.io · 문서: https://api.hyean.io/docs · 가격: https://hyean.io/pricing
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hyean
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Korean financial data SDK — DART 5소스 교차검증, LLM-ready
|
|
5
|
+
Author-email: Hyean <support@hyean.io>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://hyean.io
|
|
8
|
+
Project-URL: Documentation, https://hyean.io/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/twiw49/hyean
|
|
10
|
+
Keywords: korea,finance,dart,financial-data,xbrl,valuation,llm
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
Requires-Dist: pandas>=2.0
|
|
21
|
+
Requires-Dist: requests>=2.28
|
|
22
|
+
Provides-Extra: parquet
|
|
23
|
+
Requires-Dist: pyarrow>=12.0; extra == "parquet"
|
|
24
|
+
Provides-Extra: server
|
|
25
|
+
Requires-Dist: fastapi>=0.115.0; extra == "server"
|
|
26
|
+
Requires-Dist: uvicorn[standard]>=0.30.0; extra == "server"
|
|
27
|
+
Requires-Dist: pydantic>=2.7.0; extra == "server"
|
|
28
|
+
Requires-Dist: pydantic-settings>=2.3.0; extra == "server"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest; extra == "dev"
|
|
31
|
+
Requires-Dist: httpx; extra == "dev"
|
|
32
|
+
|
|
33
|
+
# hyean — Korean financial data SDK
|
|
34
|
+
|
|
35
|
+
DART 원문 기반 **5소스 교차검증** 한국 상장기업 재무 데이터. 모든 수치에 confidence 등급과 원문 출처(report_url + anchor)가 따라옵니다.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install git+https://github.com/twiw49/hyean-sdk.git # 또는: pip install hyean
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import hyean as hy
|
|
43
|
+
|
|
44
|
+
hy.set_api_key("hyn_live_xxxx") # 또는 export HYEAN_API_KEY=...
|
|
45
|
+
# base_url 기본값 = https://api.hyean.io (생략 가능)
|
|
46
|
+
|
|
47
|
+
# 재무제표 → pandas DataFrame (식별자: 종목코드 / corp_code / 기업명)
|
|
48
|
+
bs = hy.load_balance("삼성전자")
|
|
49
|
+
is_ = hy.load_income("005930", min_confidence="high") # 품질 필터
|
|
50
|
+
cf = hy.load_cashflow("00126380")
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### dart-fss와 다른 점 — point-in-time(정정 소급반영)
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
# 특정 시점 기준으로 본 재무 — 이후 정정공시를 반영/미반영해 백테스트 무결성 확보
|
|
57
|
+
bs_then = hy.load_balance("005930", as_of="2023-03-31")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`as_of`는 survivorship bias와 미반영 정정으로 백테스트가 틀어지는 문제를 막습니다 — 무료 오픈소스가 싸게 제공하지 못하는 지점입니다.
|
|
61
|
+
|
|
62
|
+
### 원문 추적
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
bs = hy.load_balance("005930")
|
|
66
|
+
url = hy.source_url(bs, "BS_AST_TOT", "2024") # 이 숫자의 DART 원문 위치
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### CompanyHub — 한 기업, 여러 관점
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
hub = hy.CompanyHub("005930")
|
|
73
|
+
hub.balance, hub.income, hub.cashflow, hub.audit, hub.profile, hub.risk
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
API 키 발급: https://hyean.io · 문서: https://api.hyean.io/docs · 가격: https://hyean.io/pricing
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
hyean.egg-info/PKG-INFO
|
|
4
|
+
hyean.egg-info/SOURCES.txt
|
|
5
|
+
hyean.egg-info/dependency_links.txt
|
|
6
|
+
hyean.egg-info/requires.txt
|
|
7
|
+
hyean.egg-info/top_level.txt
|
|
8
|
+
sdk/__init__.py
|
|
9
|
+
sdk/audit.py
|
|
10
|
+
sdk/benchmark.py
|
|
11
|
+
sdk/cache.py
|
|
12
|
+
sdk/client.py
|
|
13
|
+
sdk/companies.py
|
|
14
|
+
sdk/config.py
|
|
15
|
+
sdk/context.py
|
|
16
|
+
sdk/coverage.py
|
|
17
|
+
sdk/deep.py
|
|
18
|
+
sdk/discover.py
|
|
19
|
+
sdk/enhanced.py
|
|
20
|
+
sdk/events.py
|
|
21
|
+
sdk/exceptions.py
|
|
22
|
+
sdk/filings.py
|
|
23
|
+
sdk/financials.py
|
|
24
|
+
sdk/grades.py
|
|
25
|
+
sdk/groups.py
|
|
26
|
+
sdk/hub.py
|
|
27
|
+
sdk/index.py
|
|
28
|
+
sdk/macro.py
|
|
29
|
+
sdk/meta.py
|
|
30
|
+
sdk/names.py
|
|
31
|
+
sdk/prices.py
|
|
32
|
+
sdk/profile.py
|
|
33
|
+
sdk/segments.py
|
|
34
|
+
sdk/source.py
|
|
35
|
+
sdk/utils.py
|
|
36
|
+
sdk/valuation.py
|
|
37
|
+
tests/test_reference.py
|
|
38
|
+
tests/test_smoke.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hyean
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hyean"
|
|
7
|
+
version = "0.4.0"
|
|
8
|
+
description = "Korean financial data SDK — DART 5소스 교차검증, LLM-ready"
|
|
9
|
+
license = {text = "MIT"}
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [{ name = "Hyean", email = "support@hyean.io" }]
|
|
13
|
+
keywords = ["korea", "finance", "dart", "financial-data", "xbrl", "valuation", "llm"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Topic :: Office/Business :: Financial :: Investment",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"pandas>=2.0",
|
|
25
|
+
"requests>=2.28",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://hyean.io"
|
|
30
|
+
Documentation = "https://hyean.io/docs"
|
|
31
|
+
Repository = "https://github.com/twiw49/hyean"
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
parquet = ["pyarrow>=12.0"]
|
|
35
|
+
server = [
|
|
36
|
+
"fastapi>=0.115.0",
|
|
37
|
+
"uvicorn[standard]>=0.30.0",
|
|
38
|
+
"pydantic>=2.7.0",
|
|
39
|
+
"pydantic-settings>=2.3.0",
|
|
40
|
+
]
|
|
41
|
+
dev = ["pytest", "httpx"]
|
|
42
|
+
|
|
43
|
+
# pip install hyean → sdk/ 만 설치됨
|
|
44
|
+
# pip install hyean[server] → 서버 의존성 포함
|
|
45
|
+
[tool.setuptools]
|
|
46
|
+
packages = ["hyean"]
|
|
47
|
+
|
|
48
|
+
[tool.setuptools.package-dir]
|
|
49
|
+
hyean = "sdk"
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
testpaths = ["tests"]
|
|
53
|
+
# 스모크 테스트는 DB가 떠 있어야 의미 있음 (데이터 의존 테스트는 db_up fixture로 자동 skip)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Hyean — Korean financial data SDK
|
|
3
|
+
===================================
|
|
4
|
+
DART 원문 기반, 5소스 교차검증 한국 상장기업 재무 데이터.
|
|
5
|
+
|
|
6
|
+
Quick start:
|
|
7
|
+
import hyean as hy
|
|
8
|
+
|
|
9
|
+
hy.set_api_key("hyn_live_xxxx")
|
|
10
|
+
hy.set_base_url("https://api.hyean.io/v1")
|
|
11
|
+
|
|
12
|
+
# 스마트 식별자 — corp_code, stock_code, 기업명 모두 가능
|
|
13
|
+
bs = hy.load_balance("005930")
|
|
14
|
+
bs = hy.load_balance("삼성전자")
|
|
15
|
+
bs = hy.load_balance("00126380")
|
|
16
|
+
|
|
17
|
+
# 복수 기업
|
|
18
|
+
bs = hy.load_balance(["005930", "000660"])
|
|
19
|
+
|
|
20
|
+
# 품질 필터
|
|
21
|
+
bs = hy.load_balance("005930", min_confidence="high")
|
|
22
|
+
|
|
23
|
+
# 원문 추적
|
|
24
|
+
url = hy.source_url(bs, "BS_AST_TOT", "2024")
|
|
25
|
+
|
|
26
|
+
# CompanyHub
|
|
27
|
+
hub = hy.CompanyHub("005930")
|
|
28
|
+
hub.balance, hub.income, hub.audit
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
__version__ = "0.4.0"
|
|
32
|
+
|
|
33
|
+
# ── Config ──
|
|
34
|
+
from .config import (
|
|
35
|
+
set_api_key, get_api_key, load_api_key,
|
|
36
|
+
set_base_url, get_base_url,
|
|
37
|
+
set_data_dir, get_data_dir,
|
|
38
|
+
set_cache, get_cache_format, get_refresh_days,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# ── Companies ──
|
|
42
|
+
from .companies import load_companies, search_companies, company_detail, load_company, resolve
|
|
43
|
+
|
|
44
|
+
# ── Discover (AI 카탈로그) ──
|
|
45
|
+
from .discover import discover
|
|
46
|
+
|
|
47
|
+
# ── Financials (core) ──
|
|
48
|
+
from .financials import (
|
|
49
|
+
load_financials,
|
|
50
|
+
load_balance, load_income, load_cashflow,
|
|
51
|
+
load_derived,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# ── Events & Anomalies ──
|
|
55
|
+
from .events import load_events, search_events, load_anomalies
|
|
56
|
+
|
|
57
|
+
# ── Groups / Rank / Grades ──
|
|
58
|
+
from .groups import load_groups, load_rank
|
|
59
|
+
from .grades import load_grades
|
|
60
|
+
|
|
61
|
+
# ── Profile / Risk / Quality / Notes / Insight ──
|
|
62
|
+
from .profile import (
|
|
63
|
+
load_profile, load_risk, load_quality,
|
|
64
|
+
load_notes, load_note_elements, load_insight_context,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# ── Segments ──
|
|
68
|
+
from .segments import load_segments, load_segment_axes
|
|
69
|
+
|
|
70
|
+
# ── Insight S1 context ──
|
|
71
|
+
from .context import (
|
|
72
|
+
load_context_categories, load_context, load_context_available, search_context,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# ── Audit / Coverage / Benchmark / Deep ──
|
|
76
|
+
from .audit import load_audit
|
|
77
|
+
from .coverage import load_coverage
|
|
78
|
+
from .benchmark import load_benchmark
|
|
79
|
+
from .deep import load_deep
|
|
80
|
+
|
|
81
|
+
# ── Valuation ──
|
|
82
|
+
from .valuation import load_valuation
|
|
83
|
+
|
|
84
|
+
# ── Filings ──
|
|
85
|
+
from .filings import load_filings, load_filing
|
|
86
|
+
|
|
87
|
+
# ── Prices ──
|
|
88
|
+
from .prices import load_prices
|
|
89
|
+
|
|
90
|
+
# ── Enhanced (AI Agent 최적화) ──
|
|
91
|
+
from .enhanced import (
|
|
92
|
+
load_summary, load_price, load_price_stats,
|
|
93
|
+
load_quarterly, load_peers, load_prices_bulk, screening,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# ── Macro (ECOS) ──
|
|
97
|
+
from .macro import load_macro, load_macro_rates, load_macro_indicators, load_macro_context
|
|
98
|
+
|
|
99
|
+
# ── KRX Index ──
|
|
100
|
+
from .index import load_index_list, load_index_timeseries, load_index_constituents
|
|
101
|
+
|
|
102
|
+
# ── Source provenance ──
|
|
103
|
+
from .source import load_source_detail, load_source_items
|
|
104
|
+
|
|
105
|
+
# ── Meta ──
|
|
106
|
+
from .meta import load_items, load_stats
|
|
107
|
+
|
|
108
|
+
# ── Utils ──
|
|
109
|
+
from .utils import pivot_financials, source_url, source_detail
|
|
110
|
+
|
|
111
|
+
# ── Hub ──
|
|
112
|
+
from .hub import CompanyHub
|
|
113
|
+
|
|
114
|
+
# ── Exceptions ──
|
|
115
|
+
from .exceptions import HyeanError, APIError, NotFoundError, ConfigError
|
hyean-0.4.0/sdk/audit.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Audit opinions, going concern, KAM"""
|
|
2
|
+
from .client import get_client
|
|
3
|
+
from .companies import resolve
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def load_audit(code: str | None = None, *, corp_code: str | None = None, stock_code: str | None = None) -> dict:
|
|
7
|
+
"""
|
|
8
|
+
Load audit opinions, going concern warnings, and KAM.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
code: Smart identifier (corp_code/stock_code/name)
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
Dict with keys: corp_code, total, has_going_concern, reports[]
|
|
15
|
+
"""
|
|
16
|
+
cc = resolve(code or corp_code or stock_code)
|
|
17
|
+
return get_client().get(f"/api/companies/{cc}/audit")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Sector benchmark comparison"""
|
|
2
|
+
from .client import get_client
|
|
3
|
+
from .companies import resolve
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def load_benchmark(
|
|
7
|
+
code: str | None = None,
|
|
8
|
+
*,
|
|
9
|
+
corp_code: str | None = None,
|
|
10
|
+
stock_code: str | None = None,
|
|
11
|
+
consol: int = 1,
|
|
12
|
+
group_by: str | None = None,
|
|
13
|
+
group_code: str | None = None,
|
|
14
|
+
) -> dict:
|
|
15
|
+
"""
|
|
16
|
+
Compare company metrics against group benchmarks.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
code: Smart identifier (corp_code/stock_code/name)
|
|
20
|
+
group_by: Comparison dimension (industry/krx_index/market/size/ecos_sector)
|
|
21
|
+
group_code: Specific group within dimension (auto-resolved if omitted)
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Dict with keys: corp_name, sector_code, items[]
|
|
25
|
+
"""
|
|
26
|
+
cc = resolve(code or corp_code or stock_code)
|
|
27
|
+
params: dict = {"consol": consol}
|
|
28
|
+
if group_by:
|
|
29
|
+
params["group_by"] = group_by
|
|
30
|
+
if group_code:
|
|
31
|
+
params["group_code"] = group_code
|
|
32
|
+
return get_client().get(f"/api/companies/{cc}/benchmark", params)
|
hyean-0.4.0/sdk/cache.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Caching decorator for Hyean SDK
|
|
3
|
+
=================================
|
|
4
|
+
Caches DataFrame results to local disk.
|
|
5
|
+
"""
|
|
6
|
+
import time
|
|
7
|
+
import hashlib
|
|
8
|
+
import functools
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import pandas as pd
|
|
12
|
+
|
|
13
|
+
from .config import get_data_dir, get_cache_format, get_refresh_days
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _cache_path(name: str, fmt: str) -> Path | None:
|
|
17
|
+
data_dir = get_data_dir()
|
|
18
|
+
if data_dir is None:
|
|
19
|
+
return None
|
|
20
|
+
ext = {"pickle": ".pkl", "parquet": ".parquet"}.get(fmt, ".pkl")
|
|
21
|
+
return data_dir / "cache" / f"{name}{ext}"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _file_age_days(path: Path) -> float:
|
|
25
|
+
if not path.exists():
|
|
26
|
+
return float("inf")
|
|
27
|
+
return (time.time() - path.stat().st_mtime) / 86400
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _save_df(df: pd.DataFrame, path: Path, fmt: str):
|
|
31
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
32
|
+
if fmt == "parquet":
|
|
33
|
+
df.to_parquet(path)
|
|
34
|
+
else:
|
|
35
|
+
df.to_pickle(path)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _load_df(path: Path, fmt: str) -> pd.DataFrame:
|
|
39
|
+
if fmt == "parquet":
|
|
40
|
+
return pd.read_parquet(path)
|
|
41
|
+
else:
|
|
42
|
+
return pd.read_pickle(path)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def cache(name_template: str, refresh_days: int | None = None):
|
|
46
|
+
"""
|
|
47
|
+
Decorator that caches DataFrame results to disk.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
name_template: Cache file name template with {param} placeholders.
|
|
51
|
+
e.g. "balance_{corp_code}_{consol}"
|
|
52
|
+
refresh_days: Override global refresh_days setting.
|
|
53
|
+
|
|
54
|
+
Usage:
|
|
55
|
+
@cache("balance_{corp_code}_{consol}")
|
|
56
|
+
def load_balance(corp_code, consol=1):
|
|
57
|
+
...
|
|
58
|
+
"""
|
|
59
|
+
def decorator(func):
|
|
60
|
+
@functools.wraps(func)
|
|
61
|
+
def wrapper(*args, **kwargs):
|
|
62
|
+
# Build cache key from function args
|
|
63
|
+
import inspect
|
|
64
|
+
sig = inspect.signature(func)
|
|
65
|
+
bound = sig.bind(*args, **kwargs)
|
|
66
|
+
bound.apply_defaults()
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
cache_name = name_template.format(**bound.arguments)
|
|
70
|
+
except (KeyError, IndexError):
|
|
71
|
+
# Can't build cache name, skip caching
|
|
72
|
+
return func(*args, **kwargs)
|
|
73
|
+
|
|
74
|
+
fmt = get_cache_format()
|
|
75
|
+
path = _cache_path(cache_name, fmt)
|
|
76
|
+
|
|
77
|
+
if path is not None:
|
|
78
|
+
max_age = refresh_days if refresh_days is not None else get_refresh_days()
|
|
79
|
+
if _file_age_days(path) < max_age:
|
|
80
|
+
return _load_df(path, fmt)
|
|
81
|
+
|
|
82
|
+
result = func(*args, **kwargs)
|
|
83
|
+
|
|
84
|
+
if path is not None and isinstance(result, pd.DataFrame) and not result.empty:
|
|
85
|
+
_save_df(result, path, fmt)
|
|
86
|
+
|
|
87
|
+
return result
|
|
88
|
+
return wrapper
|
|
89
|
+
return decorator
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HTTP client for Hyean API
|
|
3
|
+
==========================
|
|
4
|
+
Handles requests, retries, error mapping.
|
|
5
|
+
"""
|
|
6
|
+
import requests
|
|
7
|
+
from urllib.parse import urljoin
|
|
8
|
+
|
|
9
|
+
from .config import get_base_url, get_api_key
|
|
10
|
+
from .exceptions import APIError, NotFoundError, HyeanError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class HyeanClient:
|
|
14
|
+
"""HTTP client with retry and error handling"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, base_url: str | None = None, api_key: str | None = None):
|
|
17
|
+
self._base_url = base_url
|
|
18
|
+
self._api_key = api_key
|
|
19
|
+
self._session = requests.Session()
|
|
20
|
+
self._session.headers["User-Agent"] = "hyean-sdk/0.4.0"
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def base_url(self) -> str:
|
|
24
|
+
return self._base_url or get_base_url()
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def api_key(self) -> str | None:
|
|
28
|
+
return self._api_key or get_api_key()
|
|
29
|
+
|
|
30
|
+
def get(self, path: str, params: dict | None = None) -> dict:
|
|
31
|
+
"""GET request, returns parsed JSON"""
|
|
32
|
+
url = urljoin(self.base_url + "/", path.lstrip("/"))
|
|
33
|
+
headers = {}
|
|
34
|
+
if self.api_key:
|
|
35
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
resp = self._session.get(url, params=params, headers=headers, timeout=30)
|
|
39
|
+
except requests.ConnectionError:
|
|
40
|
+
raise HyeanError(f"서버 연결 실패: {self.base_url}")
|
|
41
|
+
except requests.Timeout:
|
|
42
|
+
raise HyeanError("요청 타임아웃 (30초)")
|
|
43
|
+
|
|
44
|
+
if resp.status_code == 404:
|
|
45
|
+
raise NotFoundError(resp.text)
|
|
46
|
+
if resp.status_code >= 400:
|
|
47
|
+
detail = ""
|
|
48
|
+
try:
|
|
49
|
+
detail = resp.json().get("detail", resp.text)
|
|
50
|
+
except Exception:
|
|
51
|
+
detail = resp.text
|
|
52
|
+
raise APIError(resp.status_code, detail)
|
|
53
|
+
|
|
54
|
+
return resp.json()
|
|
55
|
+
|
|
56
|
+
def post(self, path: str, json_body: dict | None = None) -> dict:
|
|
57
|
+
"""POST request, returns parsed JSON"""
|
|
58
|
+
url = urljoin(self.base_url + "/", path.lstrip("/"))
|
|
59
|
+
headers = {"Content-Type": "application/json"}
|
|
60
|
+
if self.api_key:
|
|
61
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
resp = self._session.post(url, json=json_body, headers=headers, timeout=60)
|
|
65
|
+
except requests.ConnectionError:
|
|
66
|
+
raise HyeanError(f"서버 연결 실패: {self.base_url}")
|
|
67
|
+
except requests.Timeout:
|
|
68
|
+
raise HyeanError("요청 타임아웃 (60초)")
|
|
69
|
+
|
|
70
|
+
if resp.status_code == 404:
|
|
71
|
+
raise NotFoundError(resp.text)
|
|
72
|
+
if resp.status_code >= 400:
|
|
73
|
+
detail = ""
|
|
74
|
+
try:
|
|
75
|
+
detail = resp.json().get("detail", resp.text)
|
|
76
|
+
except Exception:
|
|
77
|
+
detail = resp.text
|
|
78
|
+
raise APIError(resp.status_code, detail)
|
|
79
|
+
|
|
80
|
+
return resp.json()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Module-level singleton
|
|
84
|
+
_client: HyeanClient | None = None
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_client() -> HyeanClient:
|
|
88
|
+
global _client
|
|
89
|
+
if _client is None:
|
|
90
|
+
_client = HyeanClient()
|
|
91
|
+
return _client
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def reset_client():
|
|
95
|
+
"""Reset client (e.g. after changing base_url)"""
|
|
96
|
+
global _client
|
|
97
|
+
_client = None
|