fisis 0.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.
- fisis-0.1.0/.agents/plugins/marketplace.json +20 -0
- fisis-0.1.0/.claude-plugin/marketplace.json +27 -0
- fisis-0.1.0/.github/workflows/check.yml +25 -0
- fisis-0.1.0/.github/workflows/publish.yml +61 -0
- fisis-0.1.0/.github/workflows/reusable-check.yml +98 -0
- fisis-0.1.0/.gitignore +33 -0
- fisis-0.1.0/LICENSE +21 -0
- fisis-0.1.0/PKG-INFO +364 -0
- fisis-0.1.0/README.en.md +341 -0
- fisis-0.1.0/README.md +329 -0
- fisis-0.1.0/plugins/fisis/.claude-plugin/plugin.json +19 -0
- fisis-0.1.0/plugins/fisis/.codex-plugin/plugin.json +33 -0
- fisis-0.1.0/plugins/fisis/skills/accounts/SKILL.md +64 -0
- fisis-0.1.0/plugins/fisis/skills/companies/SKILL.md +64 -0
- fisis-0.1.0/plugins/fisis/skills/data/SKILL.md +79 -0
- fisis-0.1.0/plugins/fisis/skills/statistics/SKILL.md +67 -0
- fisis-0.1.0/pyproject.toml +71 -0
- fisis-0.1.0/src/fisis/__init__.py +56 -0
- fisis-0.1.0/src/fisis/__main__.py +8 -0
- fisis-0.1.0/src/fisis/_accessor.py +228 -0
- fisis-0.1.0/src/fisis/_companies.py +567 -0
- fisis-0.1.0/src/fisis/_config.py +63 -0
- fisis-0.1.0/src/fisis/_parse.py +146 -0
- fisis-0.1.0/src/fisis/_transport.py +170 -0
- fisis-0.1.0/src/fisis/cli.py +294 -0
- fisis-0.1.0/src/fisis/client.py +313 -0
- fisis-0.1.0/src/fisis/exceptions.py +78 -0
- fisis-0.1.0/src/fisis/py.typed +0 -0
- fisis-0.1.0/src/fisis/types.py +224 -0
- fisis-0.1.0/tests/test_accessor.py +224 -0
- fisis-0.1.0/tests/test_cli.py +305 -0
- fisis-0.1.0/tests/test_client.py +535 -0
- fisis-0.1.0/tests/test_companies.py +245 -0
- fisis-0.1.0/tests/test_config.py +68 -0
- fisis-0.1.0/tests/test_parse.py +182 -0
- fisis-0.1.0/tests/test_types.py +68 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fisis",
|
|
3
|
+
"interface": {
|
|
4
|
+
"displayName": "fisis"
|
|
5
|
+
},
|
|
6
|
+
"plugins": [
|
|
7
|
+
{
|
|
8
|
+
"name": "fisis",
|
|
9
|
+
"source": {
|
|
10
|
+
"source": "local",
|
|
11
|
+
"path": "./plugins/fisis"
|
|
12
|
+
},
|
|
13
|
+
"policy": {
|
|
14
|
+
"installation": "AVAILABLE",
|
|
15
|
+
"authentication": "ON_INSTALL"
|
|
16
|
+
},
|
|
17
|
+
"category": "Productivity"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fisis",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "seokhoonj"
|
|
5
|
+
},
|
|
6
|
+
"description": "Read FSS FISIS financial-institution statistics from the command line",
|
|
7
|
+
"plugins": [
|
|
8
|
+
{
|
|
9
|
+
"name": "fisis",
|
|
10
|
+
"displayName": "fisis",
|
|
11
|
+
"source": "./plugins/fisis",
|
|
12
|
+
"description": "Read FSS FISIS financial-institution statistics from the command line",
|
|
13
|
+
"author": {
|
|
14
|
+
"name": "seokhoonj"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/seokhoonj/fisis",
|
|
17
|
+
"category": "Productivity",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"fisis",
|
|
20
|
+
"fss",
|
|
21
|
+
"financial statistics",
|
|
22
|
+
"korea",
|
|
23
|
+
"finance"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: check
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
# A newer push to the same branch or PR makes the older run's result obsolete,
|
|
10
|
+
# so cancel it rather than let both run to completion. The event name is in the
|
|
11
|
+
# key so a push never cancels a pull-request run, or vice versa.
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
# The check only reads the code to lint, type, and test it -- it never writes to the
|
|
17
|
+
# repo -- so it runs with the least privilege that still allows a checkout.
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
check:
|
|
23
|
+
# The full check lives in reusable-check.yml so a future release gate can run the
|
|
24
|
+
# identical job on the release commit.
|
|
25
|
+
uses: ./.github/workflows/reusable-check.yml
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
# Publish to PyPI on a GitHub Release, via PyPI Trusted Publishing (OIDC): no API
|
|
4
|
+
# token or password is stored anywhere -- GitHub mints a short-lived identity token
|
|
5
|
+
# that PyPI verifies against the publisher registered for this repo (owner seokhoonj
|
|
6
|
+
# / repo fisis / this workflow / environment "pypi").
|
|
7
|
+
#
|
|
8
|
+
# Three jobs. `gate` runs the same reusable check that check.yml runs, on the
|
|
9
|
+
# release commit, so a red build (a lint/type error, a broken test, a lost py.typed,
|
|
10
|
+
# console script, or runtime dependency) cannot reach an upload. `build` builds the
|
|
11
|
+
# sdist and wheel and hands them to `publish` as an artifact. `publish` -- the only
|
|
12
|
+
# job holding the OIDC token -- downloads that artifact and uploads it, and checks
|
|
13
|
+
# out no source, so the privileged step runs the least code.
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
release:
|
|
17
|
+
types: [published]
|
|
18
|
+
|
|
19
|
+
# Workflow-level floor: any job without its own `permissions:` block still gets a
|
|
20
|
+
# read-only token, so a job added later cannot silently inherit a write-capable
|
|
21
|
+
# default. The build and publish jobs narrow it further below.
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
gate:
|
|
27
|
+
uses: ./.github/workflows/reusable-check.yml
|
|
28
|
+
|
|
29
|
+
build:
|
|
30
|
+
needs: gate
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
timeout-minutes: 15
|
|
33
|
+
permissions:
|
|
34
|
+
contents: read
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
37
|
+
with:
|
|
38
|
+
persist-credentials: false
|
|
39
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
40
|
+
- name: Build sdist and wheel, then check the metadata
|
|
41
|
+
run: |
|
|
42
|
+
uv build
|
|
43
|
+
uvx twine check dist/*
|
|
44
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
45
|
+
with:
|
|
46
|
+
name: dist
|
|
47
|
+
path: dist/
|
|
48
|
+
|
|
49
|
+
publish:
|
|
50
|
+
needs: build
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
timeout-minutes: 15
|
|
53
|
+
environment: pypi
|
|
54
|
+
permissions:
|
|
55
|
+
id-token: write # OIDC; this is what replaces a stored token
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
58
|
+
with:
|
|
59
|
+
name: dist
|
|
60
|
+
path: dist/
|
|
61
|
+
- uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
name: reusable check
|
|
2
|
+
|
|
3
|
+
# The full check -- tests, lint, types, and the packaging assertions -- factored
|
|
4
|
+
# into one reusable job so both `check.yml` (on push / PR) and the release gate in
|
|
5
|
+
# `publish.yml` run the *identical* thing. One definition is what makes "publish
|
|
6
|
+
# gates on the full check" true; a second hand-maintained copy would drift, and a
|
|
7
|
+
# check added here silently would not gate releases.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
workflow_call:
|
|
11
|
+
|
|
12
|
+
# The floor lives on the shared body, not only on `check.yml`: `publish.yml`'s gate
|
|
13
|
+
# calls this same workflow, and if the floor were only on `check.yml` the gate would
|
|
14
|
+
# run this check with the repo-default (possibly write) token. Declared here, the
|
|
15
|
+
# check is read-only from every caller. A reusable workflow can only downscope from
|
|
16
|
+
# the caller, so this never widens anyone's token.
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
check:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
timeout-minutes: 15
|
|
24
|
+
strategy:
|
|
25
|
+
fail-fast: false
|
|
26
|
+
matrix:
|
|
27
|
+
# Every minor release from the requires-python floor (>=3.11) through the
|
|
28
|
+
# current stable CPython -- the same set the trove classifiers advertise, so
|
|
29
|
+
# each is an audit of the other (no version claimed but untested).
|
|
30
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
31
|
+
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
34
|
+
with:
|
|
35
|
+
persist-credentials: false
|
|
36
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
37
|
+
|
|
38
|
+
- name: Install
|
|
39
|
+
# A venv per matrix version, not `uv pip --system`: the runner's system
|
|
40
|
+
# Python is externally managed and is one fixed version whatever the matrix
|
|
41
|
+
# says. This is also what the README tells a person to run.
|
|
42
|
+
run: |
|
|
43
|
+
uv venv --python ${{ matrix.python-version }}
|
|
44
|
+
uv pip install -e ".[dev]"
|
|
45
|
+
.venv/bin/python -c "import sys; print('testing on', sys.version)"
|
|
46
|
+
|
|
47
|
+
- name: Test
|
|
48
|
+
run: .venv/bin/pytest -q
|
|
49
|
+
|
|
50
|
+
- name: Lint
|
|
51
|
+
run: .venv/bin/ruff check src tests
|
|
52
|
+
|
|
53
|
+
- name: Types
|
|
54
|
+
run: .venv/bin/mypy src
|
|
55
|
+
|
|
56
|
+
- name: Confirm the only runtime dependency is httpx
|
|
57
|
+
# A bare install must pull in nothing but httpx; a second runtime dependency
|
|
58
|
+
# creeping into `dependencies` is caught here rather than in a user's
|
|
59
|
+
# environment.
|
|
60
|
+
run: |
|
|
61
|
+
uv venv /tmp/bare --python ${{ matrix.python-version }}
|
|
62
|
+
uv pip install --python /tmp/bare/bin/python .
|
|
63
|
+
/tmp/bare/bin/python -c "
|
|
64
|
+
import re
|
|
65
|
+
import importlib.metadata as md
|
|
66
|
+
requires = md.requires('fisis') or []
|
|
67
|
+
runtime = [r for r in requires if 'extra ==' not in r]
|
|
68
|
+
# Each requirement's bare name (before any version/marker/extra), PEP 503
|
|
69
|
+
# normalized; the runtime set must be exactly httpx.
|
|
70
|
+
names = sorted(re.split(r'[<>=!~;\[\s]', r, maxsplit=1)[0].replace('_', '-').lower() for r in runtime)
|
|
71
|
+
assert names == ['httpx'], f'unexpected runtime dependencies: {runtime}'
|
|
72
|
+
import fisis
|
|
73
|
+
print('fisis imports with only httpx')
|
|
74
|
+
"
|
|
75
|
+
# The console script runs, and its top-level --version prints (not shoved
|
|
76
|
+
# into a required subcommand).
|
|
77
|
+
/tmp/bare/bin/fisis --version
|
|
78
|
+
|
|
79
|
+
- name: Confirm a user's type checker can see the hints
|
|
80
|
+
# Every hint in this package is invisible to a user unless py.typed ships
|
|
81
|
+
# alongside it (PEP 561), and the source cannot answer whether it did:
|
|
82
|
+
# src/fisis/py.typed can sit in git while the built wheel omits it. So ask
|
|
83
|
+
# it the way a user does -- install the built package into a clean
|
|
84
|
+
# environment and run their checker over their code.
|
|
85
|
+
run: |
|
|
86
|
+
uv venv /tmp/typed --python ${{ matrix.python-version }}
|
|
87
|
+
uv pip install --python /tmp/typed/bin/python . mypy
|
|
88
|
+
cat > /tmp/user_code.py <<'PY'
|
|
89
|
+
from fisis import FISIS
|
|
90
|
+
|
|
91
|
+
# list_no takes str; an int is not, so a checker that can see the shipped
|
|
92
|
+
# hints must reject it. If py.typed is missing from the wheel, mypy skips
|
|
93
|
+
# fisis instead and emits no such error.
|
|
94
|
+
FISIS(api_key="k").list_accounts(list_no=123)
|
|
95
|
+
PY
|
|
96
|
+
/tmp/typed/bin/mypy /tmp/user_code.py > /tmp/mypy_out 2>&1 || true
|
|
97
|
+
cat /tmp/mypy_out
|
|
98
|
+
grep -q 'incompatible type' /tmp/mypy_out
|
fisis-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
.env
|
|
11
|
+
|
|
12
|
+
# uv
|
|
13
|
+
uv.lock
|
|
14
|
+
|
|
15
|
+
# Tooling caches
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
.mypy_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
|
|
22
|
+
# Local scratch (never tracked)
|
|
23
|
+
dev/
|
|
24
|
+
refs/
|
|
25
|
+
|
|
26
|
+
# AI coding agents
|
|
27
|
+
CLAUDE.md
|
|
28
|
+
.claude/
|
|
29
|
+
AGENTS.md
|
|
30
|
+
AGENT.md
|
|
31
|
+
.codex/
|
|
32
|
+
GEMINI.md
|
|
33
|
+
.gemini/
|
fisis-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Seokhoon Joo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
fisis-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fisis
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the FISIS (Financial Supervisory Service Financial Statistics Information System) Open API
|
|
5
|
+
Project-URL: Homepage, https://github.com/seokhoonj/fisis
|
|
6
|
+
Project-URL: Source, https://github.com/seokhoonj/fisis
|
|
7
|
+
Project-URL: Issues, https://github.com/seokhoonj/fisis/issues
|
|
8
|
+
Author-email: Seokhoon Joo <seokhoonj@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: data,finance,financial statistics,fisis,fss,korea
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: httpx>=0.27
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
30
|
+
Provides-Extra: pandas
|
|
31
|
+
Requires-Dist: pandas; extra == 'pandas'
|
|
32
|
+
Provides-Extra: polars
|
|
33
|
+
Requires-Dist: polars; extra == 'polars'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# fisis
|
|
37
|
+
|
|
38
|
+
[](https://github.com/seokhoonj/fisis/actions/workflows/check.yml)
|
|
39
|
+
[](https://pypi.org/project/fisis/)
|
|
40
|
+
[](https://pypi.org/project/fisis/)
|
|
41
|
+
[](https://github.com/seokhoonj/fisis/blob/main/LICENSE)
|
|
42
|
+
|
|
43
|
+
[English](https://github.com/seokhoonj/fisis/blob/main/README.en.md) | **한국어**
|
|
44
|
+
|
|
45
|
+
금융감독원 **금융통계정보시스템(FISIS)** 의 금융회사 감독통계를 읽어옵니다.
|
|
46
|
+
|
|
47
|
+
은행·생명보험·손해보험·증권·카드·저축은행·여신전문 등 금융권역별 회사 목록과
|
|
48
|
+
통계표·계정항목, 그리고 분기·반기·연간 시계열 통계자료를 다룹니다. FISIS가 담는 것은
|
|
49
|
+
금융회사가 감독당국에 제출하는 **업무보고서 기반 감독통계**입니다. 기업 공시서류를 모으는
|
|
50
|
+
**DART(전자공시)** 와 달리, 여기서만 구조화되어 나오는 **감독지표**가 핵심입니다.
|
|
51
|
+
|
|
52
|
+
| 권역 | 대표 감독지표 |
|
|
53
|
+
|---|---|
|
|
54
|
+
| 은행 | BIS 자기자본비율, 고정이하여신비율, 연체율, 예대금리차, ROA·ROE |
|
|
55
|
+
| 증권 | 영업용순자본비율(NCR), 자산건전성, 레버리지 |
|
|
56
|
+
| 카드 | 연체채권비율, 신용·직불·선불 카드이용실적 |
|
|
57
|
+
| 생명보험 | 지급여력비율(RBC/K-ICS), 13·25회 계약유지율, 경영효율지표, 신계약·보유계약·보험료수입 |
|
|
58
|
+
| 손해보험 | 지급여력비율, 계약유지율, 경영효율지표, 보험료수입·보유보험료(장기·자동차·일반) |
|
|
59
|
+
|
|
60
|
+
**DART와 함께** — 재무제표는 DART(전자공시)가 더 충실(주석·XBRL·연결/별도)하고, fisis는 같은
|
|
61
|
+
**감독 별도** 기준으로 재무제표와 감독지표를 한 소스에서 봅니다. 재무제표성 지표만 DART와
|
|
62
|
+
겹치고(삼성생명 별도 자산총계는 두 소스가 일치), 나머지 감독지표는 fisis 전용입니다. DART 숫자와 교차 검증하려면 [opendart-client](https://github.com/seokhoonj/opendart-client)를 함께 쓰세요.
|
|
63
|
+
|
|
64
|
+
| group | indicator | dart | fisis |
|
|
65
|
+
|---|---|---|---|
|
|
66
|
+
| 공통 | `balance_sheet_assets` · `balance_sheet_liabilities` · `income_statement` | ✅ | ✅ |
|
|
67
|
+
| bank | `capital_adequacy` · `delinquency` · `npl_ratio` · `productivity` | ❌ | ✅ |
|
|
68
|
+
| securities | `net_capital_ratio` · `leverage` | ❌ | ✅ |
|
|
69
|
+
| card | `delinquency` · `credit_card_usage` · `purchase_volume` | ❌ | ✅ |
|
|
70
|
+
| life · nonlife | `solvency` (RBC/K-ICS) · `persistency` · `efficiency` · `premium_income` · `retained_premium` (손보) | ❌ | ✅ |
|
|
71
|
+
|
|
72
|
+
자주 쓰는 지표는 **접근자**(`fisis.life.company("삼성생명").persistency(start_month="202312",
|
|
73
|
+
end_month="202312")`)로 바로 꺼내고, 그 밖의 통계는 통계표 코드로 조회합니다.
|
|
74
|
+
|
|
75
|
+
## 1. 설치
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pip install fisis # 코어
|
|
79
|
+
pip install fisis[pandas] # + Data.to_pandas()
|
|
80
|
+
pip install fisis[polars] # + Data.to_polars()
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
이 패키지는 FISIS API 키가 필요합니다. <https://fisis.fss.or.kr/> 의 오픈API 신청에서
|
|
84
|
+
무료로 발급받으세요(비영리는 즉시 발급). 발급하신 키를 넣는 방법은 다음과 같습니다.
|
|
85
|
+
|
|
86
|
+
**방법 1 — 코드에서 직접 넣기** (바로 한 번 써볼 때)
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from fisis import FISIS
|
|
90
|
+
|
|
91
|
+
fisis = FISIS(api_key="발급받은-키")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**방법 2 — 파일에 저장해서 계속 쓰기** (권장 — 한 번 저장하면 매번 안 넣어도 됩니다)
|
|
95
|
+
|
|
96
|
+
`~/.config/fisis/credentials.json` 파일을 만들고 아래를 넣으세요.
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{ "FISIS_API_KEY": "발급받은-키" }
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
그러면 이후로는 인자 없이 `FISIS()`만 써도 이 키를 자동으로 찾습니다.
|
|
103
|
+
탐색 순서는 생성자 인자 → 환경변수 → 파일입니다.
|
|
104
|
+
|
|
105
|
+
> 환경변수를 선호하면, macOS·Linux는 터미널에서 `export FISIS_API_KEY="발급받은-키"`,
|
|
106
|
+
> Windows는 PowerShell에서 `setx FISIS_API_KEY "발급받은-키"`.
|
|
107
|
+
|
|
108
|
+
## 2. 빠른 시작
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from fisis import FISIS
|
|
112
|
+
|
|
113
|
+
fisis = FISIS() # 저장한 키를 자동으로 찾음
|
|
114
|
+
sl = fisis.life.company("삼성생명") # 회사 손잡이 (코드 "0010595" 도 가능)
|
|
115
|
+
data = sl.persistency(start_month="202312", end_month="202312") # 13·25회 계약유지율
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
반환은 `Data` — 값은 `.rows`(`dict`의 목록), 열별 단위는 `.columns`, 결산일은
|
|
119
|
+
`.date_of_settlement`. 행은 표(DataFrame)로 한 줄에 바뀝니다(pandas는 필수가 아닙니다).
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
data.rows # [{'base_month': ..., 'account_nm': '13회차 계약유지율', '비율': ...}, ...]
|
|
123
|
+
|
|
124
|
+
# pandas / polars — 설치돼 있으면 변환 헬퍼로 바로
|
|
125
|
+
data.to_pandas()
|
|
126
|
+
data.to_polars()
|
|
127
|
+
|
|
128
|
+
# 또는 직접
|
|
129
|
+
import pandas as pd
|
|
130
|
+
pd.DataFrame(data.rows)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`sector`·`category`·`term`·`lang`은 열거형 멤버, 벤더 코드(`"H"`, `"Q"`), 멤버 이름
|
|
134
|
+
(`"life"`, `"quarterly"`) 어느 쪽으로 넣어도 됩니다.
|
|
135
|
+
|
|
136
|
+
## 3. 권역 접근자
|
|
137
|
+
|
|
138
|
+
권역(`fisis.life`, `fisis.bank`, ...)은 명시적으로 정의돼 있어 편집기에서 점(`.`)을 치면
|
|
139
|
+
자동완성됩니다. 권역에서 회사를 고르고, 회사 손잡이에서 지표를 부릅니다.
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
FISIS() # 5개 권역은 이름 붙은 지표, 나머지 17개는 코드로만
|
|
143
|
+
│ 각 권역: .company("<name>" | "<code>") 로 회사(CompanyView)를 얻어 지표를 이름으로 호출
|
|
144
|
+
│
|
|
145
|
+
├─ bank
|
|
146
|
+
│ ├─ .capital_adequacy() # 자본적정성 (BIS)
|
|
147
|
+
│ ├─ .delinquency() .npl_ratio() # 연체율 · 고정이하여신
|
|
148
|
+
│ ├─ .deposits() .loans() # 예수금 · 대출금
|
|
149
|
+
│ ├─ .balance_sheet_assets() # 재무상태표 (자산)
|
|
150
|
+
│ ├─ .balance_sheet_liabilities() # 재무상태표 (부채·자본)
|
|
151
|
+
│ ├─ .income_statement() # 손익
|
|
152
|
+
│ └─ ... # 전체 지표는 아래 권역별 표
|
|
153
|
+
├─ life
|
|
154
|
+
│ ├─ .solvency() # 지급여력 (RBC/K-ICS)
|
|
155
|
+
│ ├─ .persistency() .agent_retention() # 계약유지율 · 설계사정착률
|
|
156
|
+
│ ├─ .new_business() .premium_income() # 신계약 · 보험료수입
|
|
157
|
+
│ ├─ .balance_sheet_assets() # 재무상태표 (자산)
|
|
158
|
+
│ ├─ .balance_sheet_liabilities() # 재무상태표 (부채·자본)
|
|
159
|
+
│ ├─ .income_statement() # 손익
|
|
160
|
+
│ └─ ...
|
|
161
|
+
├─ nonlife
|
|
162
|
+
│ ├─ .solvency() .persistency() .efficiency() # 지급여력 · 유지율 · 경영효율
|
|
163
|
+
│ ├─ .premium_income() .retained_premium() # 보험료수입 · 보유보험료(장기·자동차·일반)
|
|
164
|
+
│ ├─ .balance_sheet_assets() # 재무상태표 (자산)
|
|
165
|
+
│ ├─ .balance_sheet_liabilities() # 재무상태표 (부채·자본)
|
|
166
|
+
│ ├─ .income_statement() # 손익
|
|
167
|
+
│ └─ ...
|
|
168
|
+
├─ securities
|
|
169
|
+
│ ├─ .net_capital_ratio() .leverage() # NCR · 레버리지
|
|
170
|
+
│ ├─ .securities_trading() .derivatives_trading() # 증권 · 파생 거래현황
|
|
171
|
+
│ ├─ .balance_sheet_assets() # 재무상태표 (자산)
|
|
172
|
+
│ ├─ .balance_sheet_liabilities() # 재무상태표 (부채·자본)
|
|
173
|
+
│ ├─ .income_statement() # 손익
|
|
174
|
+
│ └─ ...
|
|
175
|
+
├─ card
|
|
176
|
+
│ ├─ .delinquency() # 연체채권
|
|
177
|
+
│ ├─ .credit_card_usage() .purchase_volume() # 카드이용 · 구매실적
|
|
178
|
+
│ ├─ .balance_sheet_assets() # 재무상태표 (자산)
|
|
179
|
+
│ ├─ .balance_sheet_liabilities() # 재무상태표 (부채·자본)
|
|
180
|
+
│ ├─ .income_statement() # 손익
|
|
181
|
+
│ └─ ...
|
|
182
|
+
│
|
|
183
|
+
│ * 모든 회사 공통: .fetch(list_no=..., term=..., ...) -> Data(행 + 단위 + 결산일)
|
|
184
|
+
│
|
|
185
|
+
└─ (+17 sectors) # foreign_bank · savings_bank · capital · futures ...
|
|
186
|
+
└─ .company("<code>").fetch(list_no=...) # 이름 붙은 지표 없이 코드로만
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`company(key)`는 `key`가 전부 숫자면 그것을 `finance_cd`로 바로 쓰고(조회 없음), 아니면
|
|
190
|
+
회사 목록을 받아 `finance_nm`으로 맞춥니다(정확히 일치 우선, 없으면 유일한 부분일치).
|
|
191
|
+
일치가 없거나 부분일치가 둘 이상이면 후보(이름·코드)를 알려주며 `ValueError`가 납니다.
|
|
192
|
+
이름 매칭은 요청한 `lang`의 회사 목록을 사용합니다(기본값은 한국어). 영문 회사명은
|
|
193
|
+
`lang="en"`으로 찾거나, 언어와 무관한 숫자 코드를 쓰세요.
|
|
194
|
+
|
|
195
|
+
각 지표 메서드는 `start_month`·`end_month`(YYYYMM)를 받고, `term`은 그 지표가 실제로
|
|
196
|
+
받는 값을 기본값으로 둡니다(대부분 분기 `Q`, 유지율은 반기 `H`, 정착률은 연간 `Y`).
|
|
197
|
+
반환값은 `Data` 하나입니다 — 값은 `.rows`, 열별 **단위**는 `.columns`, **결산일**은
|
|
198
|
+
`.date_of_settlement`에 담겨 옵니다.
|
|
199
|
+
|
|
200
|
+
### 은행 `fisis.bank`
|
|
201
|
+
|
|
202
|
+
| 메서드 | 지표 | 코드 |
|
|
203
|
+
|---|---|---|
|
|
204
|
+
| `capital_adequacy` | 자본적정성 (BIS) | SA014 |
|
|
205
|
+
| `asset_quality` | 여신건전성 | SA015 |
|
|
206
|
+
| `profitability` | 수익성 (ROA·ROE·예대금리차) | SA017 |
|
|
207
|
+
| `liquidity` | 유동성 | SA018 |
|
|
208
|
+
| `productivity` | 생산성 | SA019 |
|
|
209
|
+
| `delinquency` | 연체율 | SA040 |
|
|
210
|
+
| `npl_ratio` | 고정이하여신 | SA041 |
|
|
211
|
+
| `deposits` `loans` | 예수금·대출금 | SA028 · SA043 |
|
|
212
|
+
| `balance_sheet_assets` `balance_sheet_liabilities` `income_statement` | 재무상태표(자산 / 부채·자본)·손익 | SA003 · SA004 · SA021 |
|
|
213
|
+
|
|
214
|
+
### 증권 `fisis.securities`
|
|
215
|
+
|
|
216
|
+
| 메서드 | 지표 | 코드 |
|
|
217
|
+
|---|---|---|
|
|
218
|
+
| `net_capital_ratio` | 영업용순자본비율 (NCR) | SF308 |
|
|
219
|
+
| `leverage` | 레버리지 비율 | SF331 |
|
|
220
|
+
| `asset_quality` `liquidity` `profitability` | 자산건전성·유동성·수익성 | SF311 · SF209 · SF210 |
|
|
221
|
+
| `securities_trading` `derivatives_trading` | 증권·파생상품 거래현황 | SF316 · SF317 |
|
|
222
|
+
| `balance_sheet_assets` `balance_sheet_liabilities` `income_statement` | 재무상태표(자산 / 부채·자본)·손익 | SF303 · SF304 · SF307 |
|
|
223
|
+
|
|
224
|
+
### 신용카드 `fisis.card`
|
|
225
|
+
|
|
226
|
+
| 메서드 | 지표 | 코드 |
|
|
227
|
+
|---|---|---|
|
|
228
|
+
| `capital_adequacy` `asset_quality` `profitability` `liquidity` | 자본적정성·여신건전성·수익성·유동성 | SC007 · SC008 · SC009 · SC010 |
|
|
229
|
+
| `delinquency` | 연체채권비율 | SC117 |
|
|
230
|
+
| `credit_card_usage` `debit_card_usage` `purchase_volume` | 신용·직불 카드이용실적·구매실적 | SC013 · SC014 · SC016 |
|
|
231
|
+
| `balance_sheet_assets` `balance_sheet_liabilities` `income_statement` | 재무상태표(자산 / 부채·자본)·손익 | SC103 · SC104 · SC218 |
|
|
232
|
+
|
|
233
|
+
### 생명보험 `fisis.life` / 손해보험 `fisis.nonlife`
|
|
234
|
+
|
|
235
|
+
| 메서드 | 지표 | 코드(생·손보) |
|
|
236
|
+
|---|---|---|
|
|
237
|
+
| `solvency` | 지급여력비율 (RBC/K-ICS) | SH021 / SI021 |
|
|
238
|
+
| `efficiency` | 경영효율지표 | SH114 / SI114 |
|
|
239
|
+
| `persistency` | 계약유지율 (13·25회) | SH025 / SI025 |
|
|
240
|
+
| `agent_retention` | 설계사정착률 | SH022 / SI022 |
|
|
241
|
+
| `asset_quality` | 자산건전성 | SH112 / SI112 |
|
|
242
|
+
| `liquidity` | 유동성 | SH115 / SI115 |
|
|
243
|
+
| `balance_sheet_assets` | 요약재무상태표 (자산) | SH150 / SI146 |
|
|
244
|
+
| `balance_sheet_liabilities` | 요약재무상태표 (부채·자본) | SH151 / SI147 |
|
|
245
|
+
| `income_statement` | 요약손익계산서 | SH154 / SI150 |
|
|
246
|
+
| `new_business` `in_force` `premium_income` | 신계약·보유계약·보험료수입 | SH160 · SH161 · SH166 (생보) |
|
|
247
|
+
| `premium_income` `retained_premium` | 보험료수입(수납형태)·보유보험료(장기·자동차·일반) | SI027 · SI138 (손보) |
|
|
248
|
+
|
|
249
|
+
권역 속성 — **이름 붙은 지표가 있는 5개**: `bank` `life` `nonlife` `securities` `card`.
|
|
250
|
+
**코드로만 조회하는 17개**: `foreign_bank` `futures` `asset_management` `investment_advisory`
|
|
251
|
+
`merchant_bank` `leasing` `capital` `new_tech` `savings_bank` `credit_union` `nonghyup`
|
|
252
|
+
`suhyup` `forestry_coop` `real_estate_trust` `holding` `trust_common` `derivatives_common`.
|
|
253
|
+
|
|
254
|
+
## 4. 평면 메서드 — 탐색 흐름
|
|
255
|
+
|
|
256
|
+
이름 붙은 지표가 없는 통계표나 다른 권역은, 코드를 한 단계씩 찾아 내려갑니다. FISIS는
|
|
257
|
+
시계열을 **회사(`finance_cd`) + 통계표(`list_no`) + 계정항목(`account_cd`)** 으로
|
|
258
|
+
식별합니다.
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
from fisis import FISIS, Sector, Term
|
|
262
|
+
|
|
263
|
+
fisis = FISIS()
|
|
264
|
+
|
|
265
|
+
companies = fisis.list_companies(sector=Sector.LIFE) # 회사 -> finance_cd
|
|
266
|
+
statistics = fisis.list_statistics(sector=Sector.LIFE) # 통계표 -> list_no
|
|
267
|
+
accounts = fisis.list_accounts(list_no=statistics[0]["list_no"]) # 계정항목 -> account_cd
|
|
268
|
+
|
|
269
|
+
data = fisis.fetch_data( # 통계자료 (YYYYMM, 최대 40분기)
|
|
270
|
+
finance_cd=companies[0]["finance_cd"],
|
|
271
|
+
list_no=statistics[0]["list_no"],
|
|
272
|
+
term=Term.QUARTERLY, start_month="202403", end_month="202412",
|
|
273
|
+
)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
FISIS 원본 응답의 값 열은 `a`·`b`·`c`·`d` 같은 무의미한 이름이지만, `fetch_data`가 응답의
|
|
277
|
+
컬럼 설명으로 자동 해석해 사람이 읽는 이름(예: `말잔`·`평잔`)으로 돌려줍니다. 반환값은
|
|
278
|
+
행에 더해 열별 이름·단위(`Column`)와 결산일을 담은 `Data` 하나입니다.
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
data.rows # [{'base_month': '202403', '말잔': ...}, ...]
|
|
282
|
+
[(c.name, c.unit) for c in data.columns] # 예: [('금액', '원'), ('구성비', '%')]
|
|
283
|
+
data.date_of_settlement # 예: '12/31'
|
|
284
|
+
|
|
285
|
+
# 행은 pandas·polars가 바로 먹는 records 형식입니다(값은 FISIS가 주는 대로 문자열 —
|
|
286
|
+
# 필요한 열만 캐스팅하세요). 변환 헬퍼는 해당 라이브러리가 설치돼 있을 때 씁니다:
|
|
287
|
+
data.to_polars() # polars.DataFrame
|
|
288
|
+
data.to_pandas() # pandas.DataFrame
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## 5. 커맨드라인
|
|
292
|
+
|
|
293
|
+
설치하면 `fisis` 명령이 함께 깔립니다.
|
|
294
|
+
|
|
295
|
+
```sh
|
|
296
|
+
fisis companies --sector life # 권역의 회사 목록
|
|
297
|
+
fisis statistics --sector life --category key_metrics # 통계표 목록
|
|
298
|
+
fisis accounts SH025 # 통계표의 계정항목
|
|
299
|
+
fisis data 0010595 SH025 --term H --start 202312 --end 202312 # 통계자료 (유지율)
|
|
300
|
+
fisis data 0010595 SH150 --term Q --start 202403 --end 202403 --table # + 열별 단위·결산일
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
`--json`으로 전체 결과를, `fisis <명령> --help`로 옵션을 봅니다.
|
|
304
|
+
|
|
305
|
+
## 6. AI 코딩 에이전트에서 사용
|
|
306
|
+
|
|
307
|
+
- 이 저장소는 Claude Code·Codex용 플러그인 마켓플레이스도 겸합니다.
|
|
308
|
+
- `companies`·`statistics`·`accounts`·`data` 스킬을 제공하며, 각각 같은 이름의 `fisis` 명령에
|
|
309
|
+
대응합니다.
|
|
310
|
+
- 먼저 패키지를 설치하고 API 키를 설정하세요.
|
|
311
|
+
|
|
312
|
+
### 6.1 Claude Code
|
|
313
|
+
|
|
314
|
+
Claude Code 채팅창에서 마켓플레이스를 추가하고 설치합니다:
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
/plugin marketplace add seokhoonj/fisis
|
|
318
|
+
/plugin install fisis@fisis
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
설치 후 평범하게 물어보거나("생명보험사 목록 보여줘", "삼성생명 유지율 가져와"), 스킬을 직접
|
|
322
|
+
부르세요 — `/fisis:companies --sector life`, `/fisis:data 0010595 SH025 --term H ...`.
|
|
323
|
+
|
|
324
|
+
### 6.2 Codex
|
|
325
|
+
|
|
326
|
+
터미널에서 마켓플레이스를 추가하고 설치합니다:
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
codex plugin marketplace add seokhoonj/fisis
|
|
330
|
+
codex plugin add fisis@fisis
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### 6.3 플러그인 없이 (symlink)
|
|
334
|
+
|
|
335
|
+
플러그인으로 설치하지 않고 쓰려면, 스킬을 각 에이전트의 스킬 디렉터리에 symlink합니다.
|
|
336
|
+
|
|
337
|
+
```sh
|
|
338
|
+
ln -s "$PWD/plugins/fisis/skills/data" ~/.claude/skills/data # Claude Code → /data
|
|
339
|
+
ln -s "$PWD/plugins/fisis/skills/data" ~/.codex/skills/data # Codex → $fisis:data
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Claude Code는 바로 인식하고, Codex는 재시작해야 로딩됩니다.
|
|
343
|
+
|
|
344
|
+
## 7. 에러
|
|
345
|
+
|
|
346
|
+
| 예외 | 언제 |
|
|
347
|
+
|---|---|
|
|
348
|
+
| `FISISConfigError` | API 키를 찾지 못했을 때 |
|
|
349
|
+
| `FISISAuthError` | FISIS가 키를 거부했을 때 (미등록·중지·삭제·샘플 키) |
|
|
350
|
+
| `FISISRateLimitError` | 일일검색 허용횟수 초과(err 020) 또는 HTTP 429 |
|
|
351
|
+
| `FISISResponseError` | FISIS가 에러를 돌려줬을 때 (`.code`·`.message`, 예: 40분기 초과 = 103) |
|
|
352
|
+
| `FISISNetworkError` | 네트워크가 끝내 안 됐을 때 |
|
|
353
|
+
|
|
354
|
+
- 모든 예외는 `FISISError`의 하위입니다.
|
|
355
|
+
- 조회 결과가 없으면 에러가 아니라 빈 결과로 옵니다 (카탈로그 조회는 빈 목록, `fetch_data`·지표 메서드는 행이 빈 `Data`).
|
|
356
|
+
- 여러 회사·통계표를 잇달아 읽을 때는 `FISIS(delay_seconds=0.3)`으로 간격을 둡니다.
|
|
357
|
+
- 에러 메시지와 표현에는 API 키가 절대 담기지 않습니다.
|
|
358
|
+
|
|
359
|
+
## 8. 라이선스
|
|
360
|
+
|
|
361
|
+
코드: MIT © Seokhoon Joo.
|
|
362
|
+
|
|
363
|
+
데이터: FISIS 통계정보의 출처는 금융감독원 금융통계정보시스템이며, 국가승인통계가 아닌
|
|
364
|
+
업무보고서 기반 자료입니다. 데이터 이용 시 FISIS 이용약관과 출처 표기를 따르세요.
|