financechatbotkit 2.0.0__tar.gz → 3.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.
- financechatbotkit-3.1.0/PKG-INFO +228 -0
- financechatbotkit-3.1.0/README.md +204 -0
- {financechatbotkit-2.0.0 → financechatbotkit-3.1.0}/pyproject.toml +25 -5
- financechatbotkit-3.1.0/src/financechatbotkit/__init__.py +0 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/__init__.py +90 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/dart/__init__.py +21 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/dart/api_client.py +66 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/dart/tree_to_outline.py +287 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/dart/xml_to_dict.py +116 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/dart/xml_to_tree.py +360 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/dart/zip_extractor.py +46 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/exceptions.py +25 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/kind/__init__.py +41 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/kind/download.py +282 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/kind/parser.py +236 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/kind/query.py +375 -0
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/kind/workflow.py +352 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/price/workflow.py +59 -12
- financechatbotkit-3.1.0/src/financechatbotkit/orchestrator/storage.py +77 -0
- financechatbotkit-3.1.0/src/financechatbotkit/telebotkit/__init__.py +75 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/bot/__init__.py +5 -5
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/bot/client.py +1 -1
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/firestore/__init__.py +5 -5
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/firestore/documents.py +2 -2
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/firestore/fetch.py +1 -1
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/firestore/locks.py +1 -1
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/firestore/upload.py +2 -2
- financechatbotkit-3.1.0/src/financechatbotkit/utilitykit/__init__.py +52 -0
- financechatbotkit-3.1.0/src/financechatbotkit/utilitykit/excel/__init__.py +20 -0
- financechatbotkit-3.1.0/src/financechatbotkit/utilitykit/excel/table_builders.py +117 -0
- financechatbotkit-3.1.0/src/financechatbotkit/utilitykit/excel/types.py +10 -0
- financechatbotkit-3.1.0/src/financechatbotkit/utilitykit/excel/value_utils.py +74 -0
- financechatbotkit-3.1.0/src/financechatbotkit/utilitykit/excel/xlsx_reader.py +38 -0
- financechatbotkit-3.1.0/src/financechatbotkit/utilitykit/excel/xlsx_writer.py +175 -0
- financechatbotkit-3.1.0/src/financechatbotkit.egg-info/PKG-INFO +228 -0
- financechatbotkit-3.1.0/src/financechatbotkit.egg-info/SOURCES.txt +72 -0
- financechatbotkit-3.1.0/src/financechatbotkit.egg-info/entry_points.txt +2 -0
- financechatbotkit-3.1.0/src/financechatbotkit.egg-info/requires.txt +22 -0
- financechatbotkit-3.1.0/src/financechatbotkit.egg-info/top_level.txt +1 -0
- {financechatbotkit-2.0.0 → financechatbotkit-3.1.0}/tests/test_bond_workflow.py +2 -2
- financechatbotkit-3.1.0/tests/test_dart_archive.py +29 -0
- financechatbotkit-3.1.0/tests/test_dart_xml_json.py +29 -0
- {financechatbotkit-2.0.0 → financechatbotkit-3.1.0}/tests/test_fnguide_workflow.py +9 -9
- financechatbotkit-3.1.0/tests/test_kind_download.py +379 -0
- financechatbotkit-3.1.0/tests/test_kind_json_conversion.py +114 -0
- {financechatbotkit-2.0.0 → financechatbotkit-3.1.0}/tests/test_price_workflow.py +123 -10
- {financechatbotkit-2.0.0 → financechatbotkit-3.1.0}/tests/test_update_raw_data.py +1 -1
- financechatbotkit-3.1.0/tests/test_utilitykit_excel.py +192 -0
- {financechatbotkit-2.0.0 → financechatbotkit-3.1.0}/tests/test_workflow.py +3 -3
- financechatbotkit-2.0.0/PKG-INFO +0 -11
- financechatbotkit-2.0.0/README.md +0 -52
- financechatbotkit-2.0.0/src/financechatbotkit.egg-info/PKG-INFO +0 -11
- financechatbotkit-2.0.0/src/financechatbotkit.egg-info/SOURCES.txt +0 -47
- financechatbotkit-2.0.0/src/financechatbotkit.egg-info/entry_points.txt +0 -2
- financechatbotkit-2.0.0/src/financechatbotkit.egg-info/requires.txt +0 -6
- financechatbotkit-2.0.0/src/financechatbotkit.egg-info/top_level.txt +0 -2
- financechatbotkit-2.0.0/src/orchestrator/__init__.py +0 -29
- financechatbotkit-2.0.0/src/orchestrator/exceptions.py +0 -17
- financechatbotkit-2.0.0/src/telebotkit/__init__.py +0 -51
- {financechatbotkit-2.0.0 → financechatbotkit-3.1.0}/setup.cfg +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/bond/__init__.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/bond/base_reader.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/bond/getBondBasiInfo.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/bond/getBondWithOptiCallRede.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/bond/getEarlExerOpti.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/bond/getIssuIssuItemStat.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/bond/getOptiExer.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/bond/getOptiExerPricAdju.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/bond/workflow.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/fnguide/__init__.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/fnguide/workflow.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/mapping/__init__.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/mapping/data/__init__.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/mapping/data/corp_codes_raw.json +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/mapping/update_raw_data.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/mapping/workflow.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/orchestrator/price/__init__.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/bot/reply.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/bot/router.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/bot/safety.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/bot/telegram.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/firestore/client.py +0 -0
- {financechatbotkit-2.0.0/src → financechatbotkit-3.1.0/src/financechatbotkit}/telebotkit/sheets.py +0 -0
- {financechatbotkit-2.0.0 → financechatbotkit-3.1.0}/src/financechatbotkit.egg-info/dependency_links.txt +0 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: financechatbotkit
|
|
3
|
+
Version: 3.1.0
|
|
4
|
+
Summary: FinanceChatbot workflows (orchestrator) and Telegram/Firestore helpers (TeleBotKit)
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: httpx<1,>=0.27
|
|
8
|
+
Requires-Dist: python-dotenv<2,>=1
|
|
9
|
+
Provides-Extra: orchestrator
|
|
10
|
+
Requires-Dist: beautifulsoup4<5,>=4.12; extra == "orchestrator"
|
|
11
|
+
Requires-Dist: finance-datareader==0.9.110; extra == "orchestrator"
|
|
12
|
+
Requires-Dist: lxml>=5; extra == "orchestrator"
|
|
13
|
+
Provides-Extra: firestore
|
|
14
|
+
Requires-Dist: google-cloud-firestore>=2.16.0; extra == "firestore"
|
|
15
|
+
Requires-Dist: google-api-core>=2.15.0; extra == "firestore"
|
|
16
|
+
Requires-Dist: google-auth>=2.28.0; extra == "firestore"
|
|
17
|
+
Provides-Extra: excel
|
|
18
|
+
Requires-Dist: openpyxl>=3.1.0; extra == "excel"
|
|
19
|
+
Provides-Extra: all
|
|
20
|
+
Requires-Dist: financechatbotkit[excel,firestore,orchestrator]; extra == "all"
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
24
|
+
|
|
25
|
+
## FinanceChatbot
|
|
26
|
+
|
|
27
|
+
`FinanceChatbot` bundles three installable code areas under `src/`:
|
|
28
|
+
|
|
29
|
+
- `orchestrator`: finance data workflows
|
|
30
|
+
- `utilitykit`: reusable utility helpers
|
|
31
|
+
- `telebotkit`: Telegram / Firestore helpers
|
|
32
|
+
|
|
33
|
+
The package name is `financechatbotkit`, and it currently requires Python 3.11+.
|
|
34
|
+
|
|
35
|
+
## Orchestrator
|
|
36
|
+
|
|
37
|
+
`orchestrator` is the main workflow library for:
|
|
38
|
+
|
|
39
|
+
- `mapping`
|
|
40
|
+
- `price`
|
|
41
|
+
- `fnguide`
|
|
42
|
+
- `bond`
|
|
43
|
+
- `kind`
|
|
44
|
+
|
|
45
|
+
### Public API
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from orchestrator import (
|
|
49
|
+
FnGuideWorkflow,
|
|
50
|
+
KindWorkflow,
|
|
51
|
+
MappingWorkflow,
|
|
52
|
+
MarketBondWorkflow,
|
|
53
|
+
PricePeriodWorkflow,
|
|
54
|
+
)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Feature-level imports are also available:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from orchestrator.mapping import MappingWorkflow
|
|
61
|
+
from orchestrator.price import PricePeriodWorkflow
|
|
62
|
+
from orchestrator.fnguide import FnGuideWorkflow
|
|
63
|
+
from orchestrator.bond import MarketBondWorkflow
|
|
64
|
+
from orchestrator.kind import KindWorkflow, parse_kind_html_to_json
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Most workflow classes return a normalized payload shaped like:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
{
|
|
71
|
+
"input": {...},
|
|
72
|
+
"data": {...},
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`price` workflows support `price_fields="close"` (default), `price_fields="oclh"`, `price_fields="oclhv"`, `price_fields="oclhva"`, and comma-separated field lists such as `price_fields="volume,amount"` to control which price columns are returned. `PricePeriodWorkflow` also supports `price_source="krx"` when KRX `Amount` data is required for VWAP.
|
|
77
|
+
|
|
78
|
+
### Workflow Classes
|
|
79
|
+
|
|
80
|
+
The main usage pattern is class-based:
|
|
81
|
+
|
|
82
|
+
- `MappingWorkflow`
|
|
83
|
+
- `PricePeriodWorkflow`
|
|
84
|
+
- `PriceSnapshotWorkflow`
|
|
85
|
+
- `FnGuideWorkflow`
|
|
86
|
+
- `MarketBondWorkflow`
|
|
87
|
+
- `KindWorkflow`
|
|
88
|
+
|
|
89
|
+
For example, `FnGuideWorkflow` is used like this:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from orchestrator.fnguide import FnGuideWorkflow
|
|
93
|
+
|
|
94
|
+
workflow = FnGuideWorkflow()
|
|
95
|
+
result = workflow.run(stock_code="005930", statement_type="consolidated")
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### KIND Workflow
|
|
99
|
+
|
|
100
|
+
`kind` is slightly different from the other workflow modules because it supports both:
|
|
101
|
+
|
|
102
|
+
- request payload construction and raw response download
|
|
103
|
+
- HTML file parsing into structured JSON
|
|
104
|
+
|
|
105
|
+
The recommended entry point is `KindWorkflow`.
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from pathlib import Path
|
|
109
|
+
|
|
110
|
+
from orchestrator.kind import KindWorkflow
|
|
111
|
+
from run import KIND_REQUEST_HEADERS
|
|
112
|
+
|
|
113
|
+
workflow = KindWorkflow()
|
|
114
|
+
result = workflow.run(
|
|
115
|
+
output_directory=Path("resources/kind_2012"),
|
|
116
|
+
request_headers=KIND_REQUEST_HEADERS,
|
|
117
|
+
start_date="2012-01-01",
|
|
118
|
+
end_date="2012-12-31",
|
|
119
|
+
start_page=1,
|
|
120
|
+
end_page=10,
|
|
121
|
+
disclosure_type_groups={"01": ["0119"]},
|
|
122
|
+
last_report_only=True,
|
|
123
|
+
save=True,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
print(result["input_snapshot_path"])
|
|
127
|
+
print(result["checkpoint_path"])
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`KindWorkflow` stores normalized input state and, when `save=True`, writes:
|
|
131
|
+
|
|
132
|
+
- raw `.body` files page by page
|
|
133
|
+
- `kind_workflow.input.json`
|
|
134
|
+
- `kind_workflow.checkpoint.json`
|
|
135
|
+
|
|
136
|
+
This makes long-running downloads easier to inspect and recover.
|
|
137
|
+
|
|
138
|
+
Lower-level helpers remain available when needed:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from orchestrator.kind import (
|
|
142
|
+
build_kind_search_request_data,
|
|
143
|
+
parse_kind_file_to_json,
|
|
144
|
+
parse_kind_html_to_json,
|
|
145
|
+
save_kind_search_results,
|
|
146
|
+
)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Example Script
|
|
150
|
+
|
|
151
|
+
`run.py` shows one concrete KIND pipeline:
|
|
152
|
+
|
|
153
|
+
1. Download paged KIND responses through `KindWorkflow`
|
|
154
|
+
2. Merge downloaded `.body` files into a single JSON file
|
|
155
|
+
3. Convert the merged JSON into Excel using `utilitykit`
|
|
156
|
+
|
|
157
|
+
## UtilityKit
|
|
158
|
+
|
|
159
|
+
`utilitykit` is a shared utilities package for repo-wide helpers that do not belong to `orchestrator`.
|
|
160
|
+
|
|
161
|
+
Current public utilities:
|
|
162
|
+
|
|
163
|
+
- `utilitykit.excel.read_xlsx_sheet_as_json()`
|
|
164
|
+
- `utilitykit.excel.write_json_to_xlsx()`
|
|
165
|
+
- `utilitykit.excel.records_to_table()`
|
|
166
|
+
- `utilitykit.excel.project_records_to_table()`
|
|
167
|
+
- `utilitykit.excel.row_cell_records_to_table()`
|
|
168
|
+
|
|
169
|
+
### Excel Examples
|
|
170
|
+
|
|
171
|
+
Read an Excel sheet as `list[list]` using A1-start automatic bounds detection:
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from utilitykit import read_xlsx_sheet_as_json
|
|
175
|
+
|
|
176
|
+
table = read_xlsx_sheet_as_json("sample.xlsx", sheet_name="Data")
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Write row-oriented data:
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from utilitykit import write_json_to_xlsx
|
|
183
|
+
|
|
184
|
+
write_json_to_xlsx(
|
|
185
|
+
[
|
|
186
|
+
{"company": "Samsung", "sales": 100},
|
|
187
|
+
{"company": "LG", "sales": 80},
|
|
188
|
+
],
|
|
189
|
+
"rows.xlsx",
|
|
190
|
+
sheet_name="Rows",
|
|
191
|
+
axis="rows",
|
|
192
|
+
item_mode="dict",
|
|
193
|
+
)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Write column-oriented data:
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
from utilitykit import write_json_to_xlsx
|
|
200
|
+
|
|
201
|
+
write_json_to_xlsx(
|
|
202
|
+
{"company": ["Samsung", "LG"], "sales": [100, 80]},
|
|
203
|
+
"columns.xlsx",
|
|
204
|
+
sheet_name="Columns",
|
|
205
|
+
axis="columns",
|
|
206
|
+
item_mode="dict",
|
|
207
|
+
)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## TeleBotKit
|
|
211
|
+
|
|
212
|
+
`TeleBotKit` is a shared helper package that lives under `src/telebotkit` and is packaged together with this project.
|
|
213
|
+
|
|
214
|
+
It provides helpers for:
|
|
215
|
+
|
|
216
|
+
- Telegram bot command parsing, routing, MarkdownV2 escaping, and reply payload generation (`telebotkit.bot`)
|
|
217
|
+
- Firestore client bootstrap, typed repositories, shared document access, and lease/lock helpers (`telebotkit.firestore`)
|
|
218
|
+
- Excel row parsing and typed JSON payload generation for Firestore imports (`telebotkit.sheets`)
|
|
219
|
+
|
|
220
|
+
### Example Usage
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
from telebotkit.bot import Reply, Router
|
|
224
|
+
from telebotkit.firestore import DocumentStore, get_client
|
|
225
|
+
from telebotkit.sheets import build_typed_rows_payload_from_xlsx
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
See `src/telebotkit/README.md` for fuller API documentation and examples.
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
## FinanceChatbot
|
|
2
|
+
|
|
3
|
+
`FinanceChatbot` bundles three installable code areas under `src/`:
|
|
4
|
+
|
|
5
|
+
- `orchestrator`: finance data workflows
|
|
6
|
+
- `utilitykit`: reusable utility helpers
|
|
7
|
+
- `telebotkit`: Telegram / Firestore helpers
|
|
8
|
+
|
|
9
|
+
The package name is `financechatbotkit`, and it currently requires Python 3.11+.
|
|
10
|
+
|
|
11
|
+
## Orchestrator
|
|
12
|
+
|
|
13
|
+
`orchestrator` is the main workflow library for:
|
|
14
|
+
|
|
15
|
+
- `mapping`
|
|
16
|
+
- `price`
|
|
17
|
+
- `fnguide`
|
|
18
|
+
- `bond`
|
|
19
|
+
- `kind`
|
|
20
|
+
|
|
21
|
+
### Public API
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from orchestrator import (
|
|
25
|
+
FnGuideWorkflow,
|
|
26
|
+
KindWorkflow,
|
|
27
|
+
MappingWorkflow,
|
|
28
|
+
MarketBondWorkflow,
|
|
29
|
+
PricePeriodWorkflow,
|
|
30
|
+
)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Feature-level imports are also available:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from orchestrator.mapping import MappingWorkflow
|
|
37
|
+
from orchestrator.price import PricePeriodWorkflow
|
|
38
|
+
from orchestrator.fnguide import FnGuideWorkflow
|
|
39
|
+
from orchestrator.bond import MarketBondWorkflow
|
|
40
|
+
from orchestrator.kind import KindWorkflow, parse_kind_html_to_json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Most workflow classes return a normalized payload shaped like:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
{
|
|
47
|
+
"input": {...},
|
|
48
|
+
"data": {...},
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`price` workflows support `price_fields="close"` (default), `price_fields="oclh"`, `price_fields="oclhv"`, `price_fields="oclhva"`, and comma-separated field lists such as `price_fields="volume,amount"` to control which price columns are returned. `PricePeriodWorkflow` also supports `price_source="krx"` when KRX `Amount` data is required for VWAP.
|
|
53
|
+
|
|
54
|
+
### Workflow Classes
|
|
55
|
+
|
|
56
|
+
The main usage pattern is class-based:
|
|
57
|
+
|
|
58
|
+
- `MappingWorkflow`
|
|
59
|
+
- `PricePeriodWorkflow`
|
|
60
|
+
- `PriceSnapshotWorkflow`
|
|
61
|
+
- `FnGuideWorkflow`
|
|
62
|
+
- `MarketBondWorkflow`
|
|
63
|
+
- `KindWorkflow`
|
|
64
|
+
|
|
65
|
+
For example, `FnGuideWorkflow` is used like this:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from orchestrator.fnguide import FnGuideWorkflow
|
|
69
|
+
|
|
70
|
+
workflow = FnGuideWorkflow()
|
|
71
|
+
result = workflow.run(stock_code="005930", statement_type="consolidated")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### KIND Workflow
|
|
75
|
+
|
|
76
|
+
`kind` is slightly different from the other workflow modules because it supports both:
|
|
77
|
+
|
|
78
|
+
- request payload construction and raw response download
|
|
79
|
+
- HTML file parsing into structured JSON
|
|
80
|
+
|
|
81
|
+
The recommended entry point is `KindWorkflow`.
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from pathlib import Path
|
|
85
|
+
|
|
86
|
+
from orchestrator.kind import KindWorkflow
|
|
87
|
+
from run import KIND_REQUEST_HEADERS
|
|
88
|
+
|
|
89
|
+
workflow = KindWorkflow()
|
|
90
|
+
result = workflow.run(
|
|
91
|
+
output_directory=Path("resources/kind_2012"),
|
|
92
|
+
request_headers=KIND_REQUEST_HEADERS,
|
|
93
|
+
start_date="2012-01-01",
|
|
94
|
+
end_date="2012-12-31",
|
|
95
|
+
start_page=1,
|
|
96
|
+
end_page=10,
|
|
97
|
+
disclosure_type_groups={"01": ["0119"]},
|
|
98
|
+
last_report_only=True,
|
|
99
|
+
save=True,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
print(result["input_snapshot_path"])
|
|
103
|
+
print(result["checkpoint_path"])
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`KindWorkflow` stores normalized input state and, when `save=True`, writes:
|
|
107
|
+
|
|
108
|
+
- raw `.body` files page by page
|
|
109
|
+
- `kind_workflow.input.json`
|
|
110
|
+
- `kind_workflow.checkpoint.json`
|
|
111
|
+
|
|
112
|
+
This makes long-running downloads easier to inspect and recover.
|
|
113
|
+
|
|
114
|
+
Lower-level helpers remain available when needed:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from orchestrator.kind import (
|
|
118
|
+
build_kind_search_request_data,
|
|
119
|
+
parse_kind_file_to_json,
|
|
120
|
+
parse_kind_html_to_json,
|
|
121
|
+
save_kind_search_results,
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Example Script
|
|
126
|
+
|
|
127
|
+
`run.py` shows one concrete KIND pipeline:
|
|
128
|
+
|
|
129
|
+
1. Download paged KIND responses through `KindWorkflow`
|
|
130
|
+
2. Merge downloaded `.body` files into a single JSON file
|
|
131
|
+
3. Convert the merged JSON into Excel using `utilitykit`
|
|
132
|
+
|
|
133
|
+
## UtilityKit
|
|
134
|
+
|
|
135
|
+
`utilitykit` is a shared utilities package for repo-wide helpers that do not belong to `orchestrator`.
|
|
136
|
+
|
|
137
|
+
Current public utilities:
|
|
138
|
+
|
|
139
|
+
- `utilitykit.excel.read_xlsx_sheet_as_json()`
|
|
140
|
+
- `utilitykit.excel.write_json_to_xlsx()`
|
|
141
|
+
- `utilitykit.excel.records_to_table()`
|
|
142
|
+
- `utilitykit.excel.project_records_to_table()`
|
|
143
|
+
- `utilitykit.excel.row_cell_records_to_table()`
|
|
144
|
+
|
|
145
|
+
### Excel Examples
|
|
146
|
+
|
|
147
|
+
Read an Excel sheet as `list[list]` using A1-start automatic bounds detection:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from utilitykit import read_xlsx_sheet_as_json
|
|
151
|
+
|
|
152
|
+
table = read_xlsx_sheet_as_json("sample.xlsx", sheet_name="Data")
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Write row-oriented data:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from utilitykit import write_json_to_xlsx
|
|
159
|
+
|
|
160
|
+
write_json_to_xlsx(
|
|
161
|
+
[
|
|
162
|
+
{"company": "Samsung", "sales": 100},
|
|
163
|
+
{"company": "LG", "sales": 80},
|
|
164
|
+
],
|
|
165
|
+
"rows.xlsx",
|
|
166
|
+
sheet_name="Rows",
|
|
167
|
+
axis="rows",
|
|
168
|
+
item_mode="dict",
|
|
169
|
+
)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Write column-oriented data:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from utilitykit import write_json_to_xlsx
|
|
176
|
+
|
|
177
|
+
write_json_to_xlsx(
|
|
178
|
+
{"company": ["Samsung", "LG"], "sales": [100, 80]},
|
|
179
|
+
"columns.xlsx",
|
|
180
|
+
sheet_name="Columns",
|
|
181
|
+
axis="columns",
|
|
182
|
+
item_mode="dict",
|
|
183
|
+
)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## TeleBotKit
|
|
187
|
+
|
|
188
|
+
`TeleBotKit` is a shared helper package that lives under `src/telebotkit` and is packaged together with this project.
|
|
189
|
+
|
|
190
|
+
It provides helpers for:
|
|
191
|
+
|
|
192
|
+
- Telegram bot command parsing, routing, MarkdownV2 escaping, and reply payload generation (`telebotkit.bot`)
|
|
193
|
+
- Firestore client bootstrap, typed repositories, shared document access, and lease/lock helpers (`telebotkit.firestore`)
|
|
194
|
+
- Excel row parsing and typed JSON payload generation for Firestore imports (`telebotkit.sheets`)
|
|
195
|
+
|
|
196
|
+
### Example Usage
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
from telebotkit.bot import Reply, Router
|
|
200
|
+
from telebotkit.firestore import DocumentStore, get_client
|
|
201
|
+
from telebotkit.sheets import build_typed_rows_payload_from_xlsx
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
See `src/telebotkit/README.md` for fuller API documentation and examples.
|
|
@@ -4,27 +4,47 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "financechatbotkit"
|
|
7
|
-
version = "
|
|
7
|
+
version = "3.1.0"
|
|
8
8
|
description = "FinanceChatbot workflows (orchestrator) and Telegram/Firestore helpers (TeleBotKit)"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
|
|
10
12
|
dependencies = [
|
|
11
|
-
"finance-datareader==0.9.110",
|
|
12
13
|
"httpx>=0.27,<1",
|
|
14
|
+
"python-dotenv>=1,<2",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
orchestrator = [
|
|
19
|
+
"beautifulsoup4>=4.12,<5",
|
|
20
|
+
"finance-datareader==0.9.110",
|
|
21
|
+
"lxml>=5",
|
|
22
|
+
]
|
|
23
|
+
firestore = [
|
|
13
24
|
"google-cloud-firestore>=2.16.0",
|
|
14
25
|
"google-api-core>=2.15.0",
|
|
15
26
|
"google-auth>=2.28.0",
|
|
27
|
+
]
|
|
28
|
+
excel = [
|
|
16
29
|
"openpyxl>=3.1.0",
|
|
17
30
|
]
|
|
31
|
+
all = [
|
|
32
|
+
"financechatbotkit[orchestrator,firestore,excel]"
|
|
33
|
+
]
|
|
34
|
+
dev = [
|
|
35
|
+
"pytest>=8",
|
|
36
|
+
"pytest-asyncio>=0.23",
|
|
37
|
+
]
|
|
18
38
|
|
|
19
39
|
[project.scripts]
|
|
20
|
-
orchestrator-update-corp-codes = "orchestrator.mapping.update_raw_data:main"
|
|
40
|
+
orchestrator-update-corp-codes = "financechatbotkit.orchestrator.mapping.update_raw_data:main"
|
|
21
41
|
|
|
22
42
|
[tool.setuptools]
|
|
23
43
|
package-dir = {"" = "src"}
|
|
24
44
|
|
|
25
45
|
[tool.setuptools.packages.find]
|
|
26
46
|
where = ["src"]
|
|
27
|
-
include = ["
|
|
47
|
+
include = ["financechatbotkit*"]
|
|
28
48
|
|
|
29
49
|
[tool.setuptools.package-data]
|
|
30
|
-
"orchestrator.mapping" = ["data/*.json"]
|
|
50
|
+
"financechatbotkit.orchestrator.mapping" = ["data/*.json"]
|
|
File without changes
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""FinanceChatbot workflow library."""
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from .bond import MarketBondWorkflow, run_market_bond_workflow
|
|
8
|
+
from .exceptions import DownloadError, InvalidInputError, MappingWorkflowError, NotFoundError
|
|
9
|
+
from .fnguide import FnGuideWorkflow, run_fnguide_workflow
|
|
10
|
+
from .kind import (
|
|
11
|
+
KindSavedFileCallback,
|
|
12
|
+
KindWorkflowCheckpoint,
|
|
13
|
+
KindWorkflow,
|
|
14
|
+
KindWorkflowInput,
|
|
15
|
+
ParseMode,
|
|
16
|
+
build_kind_search_request_data,
|
|
17
|
+
parse_kind_file_to_json,
|
|
18
|
+
parse_kind_html_to_json,
|
|
19
|
+
save_kind_search_results,
|
|
20
|
+
)
|
|
21
|
+
from .mapping import MappingWorkflow, run_mapping_workflow
|
|
22
|
+
from .price import (
|
|
23
|
+
PricePeriodWorkflow,
|
|
24
|
+
PriceSnapshotWorkflow,
|
|
25
|
+
run_price_period_workflow,
|
|
26
|
+
run_price_snapshot_workflow,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def __getattr__(name):
|
|
30
|
+
module_mapping = {
|
|
31
|
+
"MarketBondWorkflow": "bond",
|
|
32
|
+
"run_market_bond_workflow": "bond",
|
|
33
|
+
"DownloadError": "exceptions",
|
|
34
|
+
"InvalidInputError": "exceptions",
|
|
35
|
+
"MappingWorkflowError": "exceptions",
|
|
36
|
+
"NotFoundError": "exceptions",
|
|
37
|
+
"FnGuideWorkflow": "fnguide",
|
|
38
|
+
"run_fnguide_workflow": "fnguide",
|
|
39
|
+
"KindSavedFileCallback": "kind",
|
|
40
|
+
"KindWorkflowCheckpoint": "kind",
|
|
41
|
+
"KindWorkflow": "kind",
|
|
42
|
+
"KindWorkflowInput": "kind",
|
|
43
|
+
"ParseMode": "kind",
|
|
44
|
+
"build_kind_search_request_data": "kind",
|
|
45
|
+
"parse_kind_file_to_json": "kind",
|
|
46
|
+
"parse_kind_html_to_json": "kind",
|
|
47
|
+
"save_kind_search_results": "kind",
|
|
48
|
+
"MappingWorkflow": "mapping",
|
|
49
|
+
"run_mapping_workflow": "mapping",
|
|
50
|
+
"PricePeriodWorkflow": "price",
|
|
51
|
+
"PriceSnapshotWorkflow": "price",
|
|
52
|
+
"run_price_period_workflow": "price",
|
|
53
|
+
"run_price_snapshot_workflow": "price",
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if name in module_mapping:
|
|
57
|
+
module_name = module_mapping[name]
|
|
58
|
+
module = importlib.import_module(f".{module_name}", package=__name__)
|
|
59
|
+
return getattr(module, name)
|
|
60
|
+
|
|
61
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
62
|
+
|
|
63
|
+
def __dir__():
|
|
64
|
+
return __all__
|
|
65
|
+
|
|
66
|
+
__all__ = [
|
|
67
|
+
"DownloadError",
|
|
68
|
+
"FnGuideWorkflow",
|
|
69
|
+
"InvalidInputError",
|
|
70
|
+
"KindSavedFileCallback",
|
|
71
|
+
"KindWorkflowCheckpoint",
|
|
72
|
+
"KindWorkflow",
|
|
73
|
+
"KindWorkflowInput",
|
|
74
|
+
"MappingWorkflow",
|
|
75
|
+
"MappingWorkflowError",
|
|
76
|
+
"MarketBondWorkflow",
|
|
77
|
+
"NotFoundError",
|
|
78
|
+
"ParseMode",
|
|
79
|
+
"PricePeriodWorkflow",
|
|
80
|
+
"PriceSnapshotWorkflow",
|
|
81
|
+
"build_kind_search_request_data",
|
|
82
|
+
"parse_kind_file_to_json",
|
|
83
|
+
"parse_kind_html_to_json",
|
|
84
|
+
"run_fnguide_workflow",
|
|
85
|
+
"run_market_bond_workflow",
|
|
86
|
+
"run_mapping_workflow",
|
|
87
|
+
"run_price_period_workflow",
|
|
88
|
+
"run_price_snapshot_workflow",
|
|
89
|
+
"save_kind_search_results",
|
|
90
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Open DART 공시 API 클라이언트. 아직 미완성."""
|
|
2
|
+
|
|
3
|
+
from .zip_extractor import extract_dart_zip
|
|
4
|
+
from .api_client import DART_OPEN_API_BASE, fetch_dart_json, fetch_dart_bytes, fetch_dart
|
|
5
|
+
from .xml_to_dict import xml_markup_to_json, xml_to_soup
|
|
6
|
+
from .xml_to_tree import parse_dart_xml
|
|
7
|
+
from .tree_to_outline import build_outline_nested, iter_outline_from_structure, render_outline_lines
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"DART_OPEN_API_BASE",
|
|
11
|
+
"extract_dart_zip",
|
|
12
|
+
"fetch_dart",
|
|
13
|
+
"fetch_dart_bytes",
|
|
14
|
+
"fetch_dart_json",
|
|
15
|
+
"xml_markup_to_json",
|
|
16
|
+
"xml_to_soup",
|
|
17
|
+
"parse_dart_xml",
|
|
18
|
+
"build_outline_nested",
|
|
19
|
+
"iter_outline_from_structure",
|
|
20
|
+
"render_outline_lines",
|
|
21
|
+
]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Open DART (금융감독원 전자공시) API — 기본 httpx 동기 요청."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
|
|
10
|
+
from ..exceptions import DownloadError
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
DART_OPEN_API_BASE = "https://opendart.fss.or.kr/api"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def fetch_dart(
|
|
18
|
+
*,
|
|
19
|
+
path: str,
|
|
20
|
+
api_key: str,
|
|
21
|
+
params: dict[str, Any] | None = None,
|
|
22
|
+
timeout: float = 30.0,
|
|
23
|
+
) -> httpx.Response:
|
|
24
|
+
"""Open DART API에 GET 요청 후 응답 객체를 반환한다."""
|
|
25
|
+
url = f"{DART_OPEN_API_BASE}/{path.lstrip('/')}"
|
|
26
|
+
query: dict[str, Any] = {"crtfc_key": api_key}
|
|
27
|
+
if params:
|
|
28
|
+
query.update(params)
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
response = httpx.get(
|
|
32
|
+
url,
|
|
33
|
+
params=query,
|
|
34
|
+
timeout=timeout,
|
|
35
|
+
follow_redirects=True,
|
|
36
|
+
)
|
|
37
|
+
response.raise_for_status()
|
|
38
|
+
except httpx.HTTPError as exc:
|
|
39
|
+
logger.warning("DART request failed for %s: %s", url, exc)
|
|
40
|
+
raise DownloadError(f"Failed to fetch DART API: {url}") from exc
|
|
41
|
+
|
|
42
|
+
return response
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def fetch_dart_json(
|
|
46
|
+
*,
|
|
47
|
+
path: str,
|
|
48
|
+
api_key: str,
|
|
49
|
+
params: dict[str, Any] | None = None,
|
|
50
|
+
timeout: float = 30.0,
|
|
51
|
+
) -> dict[str, Any]:
|
|
52
|
+
"""Open DART API에 GET 요청 후 JSON을 파싱해 반환한다."""
|
|
53
|
+
response = fetch_dart(path=path, api_key=api_key, params=params, timeout=timeout)
|
|
54
|
+
return response.json()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def fetch_dart_bytes(
|
|
58
|
+
*,
|
|
59
|
+
path: str,
|
|
60
|
+
api_key: str,
|
|
61
|
+
params: dict[str, Any] | None = None,
|
|
62
|
+
timeout: float = 30.0,
|
|
63
|
+
) -> bytes:
|
|
64
|
+
"""Open DART API에 GET 요청 후 바이너리(Bytes)를 반환한다."""
|
|
65
|
+
response = fetch_dart(path=path, api_key=api_key, params=params, timeout=timeout)
|
|
66
|
+
return response.content
|