opendart-fss 0.1.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.
@@ -0,0 +1,51 @@
1
+ """DS004 지분공시 종합정보 API."""
2
+
3
+ from opendart_fss.api.base import BaseAPI
4
+ from opendart_fss.models.shareholder import (
5
+ ExecutiveStock,
6
+ ExecutiveStockListResponse,
7
+ MajorStock,
8
+ MajorStockListResponse,
9
+ )
10
+
11
+
12
+ class ShareholderAPI(BaseAPI):
13
+ """지분공시 종합정보 API (DS004)."""
14
+
15
+ async def get_major_stock(
16
+ self,
17
+ corp_code: str,
18
+ ) -> list[MajorStock]:
19
+ """대량보유 상황보고 조회.
20
+
21
+ Args:
22
+ corp_code: 고유번호 (8자리)
23
+
24
+ Returns:
25
+ 대량보유 상황보고 목록
26
+ """
27
+ response = await self._get(
28
+ "/api/majorstock.json",
29
+ MajorStockListResponse,
30
+ params={"corp_code": corp_code},
31
+ )
32
+ return response.items
33
+
34
+ async def get_executive_stock(
35
+ self,
36
+ corp_code: str,
37
+ ) -> list[ExecutiveStock]:
38
+ """임원/주요주주 소유보고 조회.
39
+
40
+ Args:
41
+ corp_code: 고유번호 (8자리)
42
+
43
+ Returns:
44
+ 임원/주요주주 소유보고 목록
45
+ """
46
+ response = await self._get(
47
+ "/api/elestock.json",
48
+ ExecutiveStockListResponse,
49
+ params={"corp_code": corp_code},
50
+ )
51
+ return response.items
opendart_fss/client.py ADDED
@@ -0,0 +1,96 @@
1
+ """OpenDART API 클라이언트."""
2
+
3
+ import os
4
+ from types import TracebackType
5
+
6
+ import httpx
7
+ from dotenv import load_dotenv
8
+
9
+ from opendart_fss.api.disclosure import DisclosureAPI
10
+ from opendart_fss.api.financial import FinancialAPI
11
+ from opendart_fss.api.major_event import MajorEventAPI
12
+ from opendart_fss.api.registration import RegistrationAPI
13
+ from opendart_fss.api.report import ReportAPI
14
+ from opendart_fss.api.shareholder import ShareholderAPI
15
+
16
+ load_dotenv()
17
+
18
+
19
+ class OpenDartClient:
20
+ """OpenDART API 클라이언트.
21
+
22
+ Example:
23
+ ```python
24
+ async with OpenDartClient(api_key="YOUR_API_KEY") as client:
25
+ # 공시 검색
26
+ disclosures = await client.disclosure.search(
27
+ corp_code="00126380",
28
+ bgn_de="20240101",
29
+ end_de="20241231"
30
+ )
31
+
32
+ # 기업 개황
33
+ company = await client.disclosure.get_company("00126380")
34
+ print(f"회사명: {company.corp_name}")
35
+
36
+ # 재무제표 조회
37
+ financials = await client.financial.get_single_account(
38
+ corp_code="00126380",
39
+ bsns_year="2024",
40
+ reprt_code="11011"
41
+ )
42
+ ```
43
+ """
44
+
45
+ def __init__(
46
+ self,
47
+ api_key: str | None = None,
48
+ *,
49
+ timeout: float = 30.0,
50
+ http_client: httpx.AsyncClient | None = None,
51
+ ) -> None:
52
+ """클라이언트 초기화.
53
+
54
+ Args:
55
+ api_key: OpenDART API 키. 생략 시 OPENDART_API_KEY 환경변수 사용
56
+ timeout: HTTP 요청 타임아웃 (초)
57
+ http_client: 커스텀 httpx.AsyncClient (선택)
58
+
59
+ Raises:
60
+ ValueError: API 키가 제공되지 않고 환경변수도 설정되지 않은 경우
61
+ """
62
+ self.api_key = api_key or os.environ.get("OPENDART_API_KEY")
63
+ if not self.api_key:
64
+ raise ValueError(
65
+ "API key is required. "
66
+ "Provide api_key parameter or set OPENDART_API_KEY environment variable."
67
+ )
68
+ self._timeout = timeout
69
+ self._external_client = http_client is not None
70
+ self._http = http_client or httpx.AsyncClient(timeout=timeout)
71
+
72
+ # API 모듈 초기화
73
+ self.disclosure = DisclosureAPI(self)
74
+ self.report = ReportAPI(self)
75
+ self.financial = FinancialAPI(self)
76
+ self.shareholder = ShareholderAPI(self)
77
+ self.major_event = MajorEventAPI(self)
78
+ self.registration = RegistrationAPI(self)
79
+
80
+ async def __aenter__(self) -> "OpenDartClient":
81
+ """컨텍스트 매니저 진입."""
82
+ return self
83
+
84
+ async def __aexit__(
85
+ self,
86
+ _exc_type: type[BaseException] | None,
87
+ _exc_val: BaseException | None,
88
+ _exc_tb: TracebackType | None,
89
+ ) -> None:
90
+ """컨텍스트 매니저 종료."""
91
+ await self.close()
92
+
93
+ async def close(self) -> None:
94
+ """HTTP 클라이언트 종료."""
95
+ if not self._external_client:
96
+ await self._http.aclose()
@@ -0,0 +1,88 @@
1
+ """OpenDART API 상수 정의."""
2
+
3
+ from enum import StrEnum
4
+
5
+ BASE_URL = "https://opendart.fss.or.kr"
6
+
7
+
8
+ class StatusCode(StrEnum):
9
+ """API 응답 상태 코드."""
10
+
11
+ SUCCESS = "000"
12
+ UNREGISTERED_KEY = "010"
13
+ INACTIVE_KEY = "011"
14
+ INVALID_KEY = "012"
15
+ USAGE_LIMIT_EXCEEDED = "013"
16
+ DAILY_LIMIT_EXCEEDED_FIELD = "014"
17
+ DAILY_LIMIT_EXCEEDED_REQUESTS = "015"
18
+ MONTHLY_LIMIT_EXCEEDED = "016"
19
+ INVALID_PARAMETER = "020"
20
+ MISSING_REQUIRED_PARAMETER = "021"
21
+ INVALID_REPORT_CODE = "022"
22
+ INVALID_DATE = "023"
23
+ NO_DATA = "100"
24
+ FILE_NOT_FOUND = "101"
25
+ SYSTEM_ERROR = "800"
26
+ MAINTENANCE = "900"
27
+ UNKNOWN = "999"
28
+
29
+
30
+ STATUS_MESSAGES: dict[StatusCode, str] = {
31
+ StatusCode.SUCCESS: "정상",
32
+ StatusCode.UNREGISTERED_KEY: "등록되지 않은 키",
33
+ StatusCode.INACTIVE_KEY: "사용할 수 없는 키",
34
+ StatusCode.INVALID_KEY: "잘못된 키",
35
+ StatusCode.USAGE_LIMIT_EXCEEDED: "일시적 사용 제한",
36
+ StatusCode.DAILY_LIMIT_EXCEEDED_FIELD: "필드 일일 조회 한도 초과",
37
+ StatusCode.DAILY_LIMIT_EXCEEDED_REQUESTS: "요청 일일 한도 초과",
38
+ StatusCode.MONTHLY_LIMIT_EXCEEDED: "월간 조회 한도 초과",
39
+ StatusCode.INVALID_PARAMETER: "잘못된 파라미터",
40
+ StatusCode.MISSING_REQUIRED_PARAMETER: "필수 파라미터 누락",
41
+ StatusCode.INVALID_REPORT_CODE: "잘못된 보고서 코드",
42
+ StatusCode.INVALID_DATE: "잘못된 날짜",
43
+ StatusCode.NO_DATA: "조회된 데이터 없음",
44
+ StatusCode.FILE_NOT_FOUND: "파일 없음",
45
+ StatusCode.SYSTEM_ERROR: "시스템 오류",
46
+ StatusCode.MAINTENANCE: "시스템 점검",
47
+ StatusCode.UNKNOWN: "알 수 없는 오류",
48
+ }
49
+
50
+
51
+ class ReportCode(StrEnum):
52
+ """보고서 코드."""
53
+
54
+ Q1 = "11013" # 1분기보고서
55
+ HALF = "11012" # 반기보고서
56
+ Q3 = "11014" # 3분기보고서
57
+ ANNUAL = "11011" # 사업보고서
58
+
59
+
60
+ class CorpClass(StrEnum):
61
+ """기업 분류 코드."""
62
+
63
+ KOSPI = "Y" # 유가증권시장
64
+ KOSDAQ = "K" # 코스닥시장
65
+ KONEX = "N" # 코넥스시장
66
+ ETC = "E" # 기타법인
67
+
68
+
69
+ class DisclosureType(StrEnum):
70
+ """공시 유형 코드."""
71
+
72
+ A = "A" # 정기공시
73
+ B = "B" # 주요사항보고
74
+ C = "C" # 발행공시
75
+ D = "D" # 지분공시
76
+ E = "E" # 기타공시
77
+ F = "F" # 외부감사관련
78
+ G = "G" # 펀드공시
79
+ H = "H" # 자산유동화
80
+ I = "I" # 거래소공시 # noqa: E741
81
+ J = "J" # 공정위공시
82
+
83
+
84
+ class FinancialStatementType(StrEnum):
85
+ """재무제표 구분 코드."""
86
+
87
+ CONSOLIDATED = "CFS" # 연결재무제표
88
+ SEPARATE = "OFS" # 개별재무제표
@@ -0,0 +1,90 @@
1
+ """OpenDART API 예외 클래스."""
2
+
3
+ from opendart_fss.constants import STATUS_MESSAGES, StatusCode
4
+
5
+
6
+ class OpenDartError(Exception):
7
+ """OpenDART API 기본 예외."""
8
+
9
+ def __init__(self, message: str, status: str | None = None):
10
+ self.status = status
11
+ self.message = message
12
+ super().__init__(message)
13
+
14
+
15
+ class APIError(OpenDartError):
16
+ """API 응답 오류."""
17
+
18
+ def __init__(self, status: str, message: str | None = None):
19
+ try:
20
+ status_code = StatusCode(status)
21
+ default_message = STATUS_MESSAGES.get(status_code, "알 수 없는 오류")
22
+ except ValueError:
23
+ default_message = "알 수 없는 오류"
24
+ super().__init__(message or default_message, status)
25
+
26
+
27
+ class AuthenticationError(APIError):
28
+ """인증 관련 오류 (010, 011, 012)."""
29
+
30
+ pass
31
+
32
+
33
+ class RateLimitError(APIError):
34
+ """요청 제한 오류 (013, 014, 015, 016)."""
35
+
36
+ pass
37
+
38
+
39
+ class ValidationError(APIError):
40
+ """파라미터 검증 오류 (020, 021, 022, 023)."""
41
+
42
+ pass
43
+
44
+
45
+ class NotFoundError(APIError):
46
+ """데이터 없음 오류 (100, 101)."""
47
+
48
+ pass
49
+
50
+
51
+ class ServerError(APIError):
52
+ """서버 오류 (800, 900)."""
53
+
54
+ pass
55
+
56
+
57
+ def raise_for_status(status: str, message: str | None = None) -> None:
58
+ """상태 코드에 따른 예외 발생."""
59
+ if status == StatusCode.SUCCESS:
60
+ return
61
+
62
+ error_class: type[APIError]
63
+ if status in (
64
+ StatusCode.UNREGISTERED_KEY,
65
+ StatusCode.INACTIVE_KEY,
66
+ StatusCode.INVALID_KEY,
67
+ ):
68
+ error_class = AuthenticationError
69
+ elif status in (
70
+ StatusCode.USAGE_LIMIT_EXCEEDED,
71
+ StatusCode.DAILY_LIMIT_EXCEEDED_FIELD,
72
+ StatusCode.DAILY_LIMIT_EXCEEDED_REQUESTS,
73
+ StatusCode.MONTHLY_LIMIT_EXCEEDED,
74
+ ):
75
+ error_class = RateLimitError
76
+ elif status in (
77
+ StatusCode.INVALID_PARAMETER,
78
+ StatusCode.MISSING_REQUIRED_PARAMETER,
79
+ StatusCode.INVALID_REPORT_CODE,
80
+ StatusCode.INVALID_DATE,
81
+ ):
82
+ error_class = ValidationError
83
+ elif status in (StatusCode.NO_DATA, StatusCode.FILE_NOT_FOUND):
84
+ error_class = NotFoundError
85
+ elif status in (StatusCode.SYSTEM_ERROR, StatusCode.MAINTENANCE):
86
+ error_class = ServerError
87
+ else:
88
+ error_class = APIError
89
+
90
+ raise error_class(status, message)
@@ -0,0 +1,124 @@
1
+ """OpenDART API 모델."""
2
+
3
+ from opendart_fss.models.base import BaseResponse
4
+ from opendart_fss.models.disclosure import (
5
+ Company,
6
+ CompanyResponse,
7
+ CorpCode,
8
+ Disclosure,
9
+ DisclosureListResponse,
10
+ )
11
+ from opendart_fss.models.financial import (
12
+ FinancialAccount,
13
+ FinancialAccountListResponse,
14
+ FinancialIndicator,
15
+ FinancialIndicatorListResponse,
16
+ XbrlTaxonomy,
17
+ XbrlTaxonomyListResponse,
18
+ )
19
+ from opendart_fss.models.major_event import (
20
+ BonusIssue,
21
+ BonusIssueListResponse,
22
+ CapitalChange,
23
+ CapitalChangeListResponse,
24
+ ConvertibleBond,
25
+ ConvertibleBondListResponse,
26
+ MergerDecision,
27
+ MergerDecisionListResponse,
28
+ SplitDecision,
29
+ SplitDecisionListResponse,
30
+ )
31
+ from opendart_fss.models.registration import (
32
+ DebtSecurities,
33
+ DebtSecuritiesListResponse,
34
+ EquitySecurities,
35
+ EquitySecuritiesListResponse,
36
+ MergerRegistration,
37
+ MergerRegistrationListResponse,
38
+ SplitRegistration,
39
+ SplitRegistrationListResponse,
40
+ )
41
+ from opendart_fss.models.report import (
42
+ DirectorCompensation,
43
+ DirectorCompensationListResponse,
44
+ DividendInfo,
45
+ DividendInfoListResponse,
46
+ Employee,
47
+ EmployeeListResponse,
48
+ Executive,
49
+ ExecutiveListResponse,
50
+ IndividualCompensation,
51
+ IndividualCompensationListResponse,
52
+ LargestShareholder,
53
+ LargestShareholderListResponse,
54
+ StockChange,
55
+ StockChangeListResponse,
56
+ TreasuryStock,
57
+ TreasuryStockListResponse,
58
+ )
59
+ from opendart_fss.models.shareholder import (
60
+ ExecutiveStock,
61
+ ExecutiveStockListResponse,
62
+ MajorStock,
63
+ MajorStockListResponse,
64
+ )
65
+
66
+ __all__ = [
67
+ # Base
68
+ "BaseResponse",
69
+ # Disclosure (DS001)
70
+ "Disclosure",
71
+ "DisclosureListResponse",
72
+ "Company",
73
+ "CompanyResponse",
74
+ "CorpCode",
75
+ # Report (DS002)
76
+ "StockChange",
77
+ "StockChangeListResponse",
78
+ "DividendInfo",
79
+ "DividendInfoListResponse",
80
+ "TreasuryStock",
81
+ "TreasuryStockListResponse",
82
+ "LargestShareholder",
83
+ "LargestShareholderListResponse",
84
+ "Executive",
85
+ "ExecutiveListResponse",
86
+ "Employee",
87
+ "EmployeeListResponse",
88
+ "IndividualCompensation",
89
+ "IndividualCompensationListResponse",
90
+ "DirectorCompensation",
91
+ "DirectorCompensationListResponse",
92
+ # Financial (DS003)
93
+ "FinancialAccount",
94
+ "FinancialAccountListResponse",
95
+ "FinancialIndicator",
96
+ "FinancialIndicatorListResponse",
97
+ "XbrlTaxonomy",
98
+ "XbrlTaxonomyListResponse",
99
+ # Shareholder (DS004)
100
+ "MajorStock",
101
+ "MajorStockListResponse",
102
+ "ExecutiveStock",
103
+ "ExecutiveStockListResponse",
104
+ # Major Event (DS005)
105
+ "CapitalChange",
106
+ "CapitalChangeListResponse",
107
+ "BonusIssue",
108
+ "BonusIssueListResponse",
109
+ "ConvertibleBond",
110
+ "ConvertibleBondListResponse",
111
+ "MergerDecision",
112
+ "MergerDecisionListResponse",
113
+ "SplitDecision",
114
+ "SplitDecisionListResponse",
115
+ # Registration (DS006)
116
+ "EquitySecurities",
117
+ "EquitySecuritiesListResponse",
118
+ "DebtSecurities",
119
+ "DebtSecuritiesListResponse",
120
+ "MergerRegistration",
121
+ "MergerRegistrationListResponse",
122
+ "SplitRegistration",
123
+ "SplitRegistrationListResponse",
124
+ ]
@@ -0,0 +1,10 @@
1
+ """기본 응답 모델."""
2
+
3
+ import msgspec
4
+
5
+
6
+ class BaseResponse(msgspec.Struct, kw_only=True):
7
+ """API 기본 응답."""
8
+
9
+ status: str
10
+ message: str
@@ -0,0 +1,106 @@
1
+ """DS001 공시정보 모델."""
2
+
3
+ import msgspec
4
+
5
+ from opendart_fss.models.base import BaseResponse
6
+
7
+
8
+ class Disclosure(msgspec.Struct, kw_only=True):
9
+ """공시 검색 결과."""
10
+
11
+ corp_code: str # 고유번호
12
+ corp_name: str # 회사명
13
+ stock_code: str | None = None # 종목코드
14
+ corp_cls: str | None = None # 법인구분 (Y/K/N/E)
15
+ report_nm: str | None = None # 보고서명
16
+ rcept_no: str | None = None # 접수번호
17
+ flr_nm: str | None = None # 공시제출인명
18
+ rcept_dt: str | None = None # 접수일자 (YYYYMMDD)
19
+ rm: str | None = None # 비고
20
+
21
+
22
+ class DisclosureListResponse(msgspec.Struct, kw_only=True):
23
+ """공시 검색 응답."""
24
+
25
+ status: str
26
+ message: str
27
+ page_no: int | None = None
28
+ page_count: int | None = None
29
+ total_count: int | None = None
30
+ total_page: int | None = None
31
+ items: list[Disclosure] = msgspec.field(default_factory=list, name="list")
32
+
33
+
34
+ class Company(msgspec.Struct, kw_only=True):
35
+ """기업 개황 정보."""
36
+
37
+ corp_code: str # 고유번호
38
+ corp_name: str # 정식명칭
39
+ corp_name_eng: str | None = None # 영문명칭
40
+ stock_name: str | None = None # 종목명(상장사) 또는 약식명칭(기타법인)
41
+ stock_code: str | None = None # 상장회사인 경우 주식의 종목코드
42
+ ceo_nm: str | None = None # 대표자명
43
+ corp_cls: str | None = None # 법인구분 (Y/K/N/E)
44
+ jurir_no: str | None = None # 법인등록번호
45
+ bizr_no: str | None = None # 사업자등록번호
46
+ adres: str | None = None # 주소
47
+ hm_url: str | None = None # 홈페이지
48
+ ir_url: str | None = None # IR홈페이지
49
+ phn_no: str | None = None # 전화번호
50
+ fax_no: str | None = None # 팩스번호
51
+ induty_code: str | None = None # 업종코드
52
+ est_dt: str | None = None # 설립일 (YYYYMMDD)
53
+ acc_mt: str | None = None # 결산월 (MM)
54
+
55
+
56
+ class CompanyResponse(BaseResponse, kw_only=True):
57
+ """기업 개황 응답."""
58
+
59
+ corp_code: str # 고유번호
60
+ corp_name: str # 정식명칭
61
+ corp_name_eng: str | None = None # 영문명칭
62
+ stock_name: str | None = None # 종목명(상장사) 또는 약식명칭(기타법인)
63
+ stock_code: str | None = None # 상장회사인 경우 주식의 종목코드
64
+ ceo_nm: str | None = None # 대표자명
65
+ corp_cls: str | None = None # 법인구분 (Y/K/N/E)
66
+ jurir_no: str | None = None # 법인등록번호
67
+ bizr_no: str | None = None # 사업자등록번호
68
+ adres: str | None = None # 주소
69
+ hm_url: str | None = None # 홈페이지
70
+ ir_url: str | None = None # IR홈페이지
71
+ phn_no: str | None = None # 전화번호
72
+ fax_no: str | None = None # 팩스번호
73
+ induty_code: str | None = None # 업종코드
74
+ est_dt: str | None = None # 설립일 (YYYYMMDD)
75
+ acc_mt: str | None = None # 결산월 (MM)
76
+
77
+ def to_company(self) -> Company:
78
+ """Company 객체로 변환."""
79
+ return Company(
80
+ corp_code=self.corp_code,
81
+ corp_name=self.corp_name,
82
+ corp_name_eng=self.corp_name_eng,
83
+ stock_name=self.stock_name,
84
+ stock_code=self.stock_code,
85
+ ceo_nm=self.ceo_nm,
86
+ corp_cls=self.corp_cls,
87
+ jurir_no=self.jurir_no,
88
+ bizr_no=self.bizr_no,
89
+ adres=self.adres,
90
+ hm_url=self.hm_url,
91
+ ir_url=self.ir_url,
92
+ phn_no=self.phn_no,
93
+ fax_no=self.fax_no,
94
+ induty_code=self.induty_code,
95
+ est_dt=self.est_dt,
96
+ acc_mt=self.acc_mt,
97
+ )
98
+
99
+
100
+ class CorpCode(msgspec.Struct, kw_only=True):
101
+ """고유번호 정보."""
102
+
103
+ corp_code: str # 고유번호
104
+ corp_name: str # 정식명칭
105
+ stock_code: str | None = None # 종목코드 (상장사만)
106
+ modify_date: str | None = None # 최종변경일 (YYYYMMDD)
@@ -0,0 +1,85 @@
1
+ """DS003 정기보고서 재무정보 모델."""
2
+
3
+ import msgspec
4
+
5
+
6
+ class FinancialAccount(msgspec.Struct, kw_only=True):
7
+ """재무제표 주요계정."""
8
+
9
+ rcept_no: str # 접수번호
10
+ reprt_code: str | None = None # 보고서 코드
11
+ bsns_year: str | None = None # 사업연도
12
+ corp_code: str | None = None # 고유번호
13
+ stock_code: str | None = None # 종목코드
14
+ fs_div: str | None = None # 개별/연결구분 (CFS/OFS)
15
+ fs_nm: str | None = None # 개별/연결명
16
+ sj_div: str | None = None # 재무제표구분 (BS/IS/CIS/CF/SCE)
17
+ sj_nm: str | None = None # 재무제표명
18
+ account_id: str | None = None # 계정ID
19
+ account_nm: str | None = None # 계정명
20
+ account_detail: str | None = None # 계정상세
21
+ thstrm_nm: str | None = None # 당기명
22
+ thstrm_amount: str | None = None # 당기금액
23
+ thstrm_add_amount: str | None = None # 당기누적금액
24
+ frmtrm_nm: str | None = None # 전기명
25
+ frmtrm_amount: str | None = None # 전기금액
26
+ frmtrm_q_nm: str | None = None # 전기명(분/반기)
27
+ frmtrm_q_amount: str | None = None # 전기금액(분/반기)
28
+ frmtrm_add_amount: str | None = None # 전기누적금액
29
+ bfefrmtrm_nm: str | None = None # 전전기명
30
+ bfefrmtrm_amount: str | None = None # 전전기금액
31
+ ord: str | None = None # 계정과목 정렬순서
32
+ currency: str | None = None # 통화단위
33
+
34
+
35
+ class FinancialAccountListResponse(msgspec.Struct, kw_only=True):
36
+ """재무제표 주요계정 응답."""
37
+
38
+ status: str
39
+ message: str
40
+ items: list[FinancialAccount] = msgspec.field(default_factory=list, name="list")
41
+
42
+
43
+ class FinancialIndicator(msgspec.Struct, kw_only=True):
44
+ """재무지표."""
45
+
46
+ rcept_no: str | None = None # 접수번호
47
+ bsns_year: str | None = None # 사업연도
48
+ corp_code: str | None = None # 고유번호
49
+ stock_code: str | None = None # 종목코드
50
+ reprt_code: str | None = None # 보고서 코드
51
+ stlm_dt: str | None = None # 결산기준일
52
+ idx_cl_code: str | None = None # 지표분류코드
53
+ idx_cl_nm: str | None = None # 지표분류명
54
+ idx_code: str | None = None # 지표코드
55
+ idx_nm: str | None = None # 지표명
56
+ idx_val: str | None = None # 지표값
57
+
58
+
59
+ class FinancialIndicatorListResponse(msgspec.Struct, kw_only=True):
60
+ """재무지표 응답."""
61
+
62
+ status: str
63
+ message: str
64
+ items: list[FinancialIndicator] = msgspec.field(default_factory=list, name="list")
65
+
66
+
67
+ class XbrlTaxonomy(msgspec.Struct, kw_only=True):
68
+ """XBRL 택사노미."""
69
+
70
+ sj_div: str # 재무제표구분
71
+ account_id: str | None = None # 계정ID
72
+ account_nm: str | None = None # 계정명
73
+ bsns_de: str | None = None # 개시일자
74
+ label_kor: str | None = None # 한글라벨
75
+ label_eng: str | None = None # 영문라벨
76
+ data_tp: str | None = None # 데이터타입
77
+ ifrs_ref: str | None = None # IFRS참조
78
+
79
+
80
+ class XbrlTaxonomyListResponse(msgspec.Struct, kw_only=True):
81
+ """XBRL 택사노미 응답."""
82
+
83
+ status: str
84
+ message: str
85
+ items: list[XbrlTaxonomy] = msgspec.field(default_factory=list, name="list")