Skip to content

Latest commit

ย 

History

History
634 lines (440 loc) ยท 13.8 KB

File metadata and controls

634 lines (440 loc) ยท 13.8 KB

๊ธฐ์—ฌ ๊ฐ€์ด๋“œ (Contributing Guide)

Python-KIS ํ”„๋กœ์ ํŠธ์— ๊ธฐ์—ฌํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๐ŸŽ‰

์ด ๋ฌธ์„œ๋Š” ํ”„๋กœ์ ํŠธ์— ๊ธฐ์—ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.


๋ชฉ์ฐจ

  1. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •
  2. ๋ธŒ๋žœ์น˜ ์ „๋žต
  3. ์ฝ”๋”ฉ ๊ทœ์น™
  4. Pull Request ํ”„๋กœ์„ธ์Šค
  5. ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ๊ฐ€์ด๋“œ
  6. ๋ฌธ์„œํ™” ๊ฐ€์ด๋“œ
  7. Issue ์ž‘์„ฑ ๊ฐ€์ด๋“œ
  8. ์ปค๋ฎค๋‹ˆํ‹ฐ ํ–‰๋™ ๊ฐ•๋ น

๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •

1. ์ €์žฅ์†Œ ํด๋ก 

git clone https://github.com/Soju06/python-kis.git
cd python-kis

2. Poetry ์„ค์น˜ ๋ฐ ์˜์กด์„ฑ ์„ค์น˜

Poetry๊ฐ€ ์—†๋‹ค๋ฉด ๋จผ์ € ์„ค์น˜:

# Windows (PowerShell)
(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -

# Linux/macOS
curl -sSL https://install.python-poetry.org | python3 -

ํ”„๋กœ์ ํŠธ ์˜์กด์„ฑ ์„ค์น˜:

poetry install --with=dev

3. ๊ฐ€์ƒํ™˜๊ฒฝ ํ™œ์„ฑํ™”

poetry shell

4. Pre-commit ํ›… ์„ค์ • (์„ ํƒ)

poetry run pre-commit install

5. ํ…Œ์ŠคํŠธ ์‹คํ–‰ ํ™•์ธ

# ์ „์ฒด ํ…Œ์ŠคํŠธ
poetry run pytest

# ์ปค๋ฒ„๋ฆฌ์ง€ ํฌํ•จ
poetry run pytest --cov=pykis --cov-report=html

# ํŠน์ • ํ…Œ์ŠคํŠธ๋งŒ
poetry run pytest tests/unit/test_public_api_imports.py

๋ธŒ๋žœ์น˜ ์ „๋žต

๋ธŒ๋žœ์น˜ ๋ช…๋ช… ๊ทœ์น™

feature/<๊ธฐ๋Šฅ๋ช…>     # ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€
fix/<๋ฒ„๊ทธ๋ช…>         # ๋ฒ„๊ทธ ์ˆ˜์ •
docs/<๋ฌธ์„œ๋ช…>        # ๋ฌธ์„œ ์ˆ˜์ •
refactor/<๊ฐœ์„ ๋ช…>    # ๋ฆฌํŒฉํ† ๋ง
test/<ํ…Œ์ŠคํŠธ๋ช…>      # ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€
chore/<์ž‘์—…๋ช…>       # ๋นŒ๋“œ/์„ค์ • ๋ณ€๊ฒฝ

๋ธŒ๋žœ์น˜ ์ƒ์„ฑ ์˜ˆ์‹œ

# ์ƒˆ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
git checkout -b feature/add-futures-api

# ๋ฒ„๊ทธ ์ˆ˜์ •
git checkout -b fix/websocket-reconnect

# ๋ฌธ์„œ ๊ฐœ์„ 
git checkout -b docs/update-quickstart

์ž‘์—… ํ๋ฆ„

  1. main์—์„œ ์ƒˆ ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ
  2. ๋ณ€๊ฒฝ์‚ฌํ•ญ ์ปค๋ฐ‹
  3. Push ํ›„ Pull Request ์ƒ์„ฑ
  4. ๋ฆฌ๋ทฐ ๋ฐ ํ…Œ์ŠคํŠธ ํ†ต๊ณผ
  5. main์— ๋ณ‘ํ•ฉ

์ฝ”๋”ฉ ๊ทœ์น™

1. Python ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ

PEP 8 ์ค€์ˆ˜๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ํ•˜๋˜, ํ”„๋กœ์ ํŠธ ๊ทœ์น™ ์šฐ์„ :

# โœ… ๊ถŒ์žฅ
def get_quote(symbol: str, market: str = "KRX") -> Quote:
    """์‹œ์„ธ ์ •๋ณด๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
    
    Args:
        symbol: ์ข…๋ชฉ ์ฝ”๋“œ (์˜ˆ: "005930")
        market: ์‹œ์žฅ ์ฝ”๋“œ (๊ธฐ๋ณธ๊ฐ’: "KRX")
    
    Returns:
        ์‹œ์„ธ ์ •๋ณด ๊ฐ์ฒด
    
    Raises:
        KisAPIError: API ํ˜ธ์ถœ ์‹คํŒจ ์‹œ
    """
    return self.kis.api(...)

# โŒ ์ง€์–‘
def getQuote(symbol, market="KRX"):  # ์นด๋ฉœ์ผ€์ด์Šค, ํƒ€์ž… ํžŒํŠธ ์—†์Œ
    return self.kis.api(...)

2. ํƒ€์ž… ํžŒํŒ… ํ•„์ˆ˜

๋ชจ๋“  ๊ณต๊ฐœ ํ•จ์ˆ˜/๋ฉ”์„œ๋“œ์— ํƒ€์ž… ํžŒํŠธ ์ถ”๊ฐ€:

from typing import Optional, List, Dict, Any

def process_orders(
    orders: List[Order],
    filter_func: Optional[Callable[[Order], bool]] = None
) -> Dict[str, Any]:
    ...

3. Docstring ์ž‘์„ฑ

๋ชจ๋“  ๊ณต๊ฐœ API์— Google ์Šคํƒ€์ผ Docstring ์ž‘์„ฑ:

def buy_stock(self, symbol: str, quantity: int, price: int) -> Order:
    """์ฃผ์‹ ๋งค์ˆ˜ ์ฃผ๋ฌธ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
    
    Args:
        symbol: ์ข…๋ชฉ ์ฝ”๋“œ (6์ž๋ฆฌ)
        quantity: ์ฃผ๋ฌธ ์ˆ˜๋Ÿ‰
        price: ์ฃผ๋ฌธ ๊ฐ€๊ฒฉ (์›)
    
    Returns:
        ์ฃผ๋ฌธ ์ •๋ณด ๊ฐ์ฒด
    
    Raises:
        KisAPIError: ์ฃผ๋ฌธ ์‹คํŒจ ์‹œ
        ValueError: ์ž˜๋ชป๋œ ํŒŒ๋ผ๋ฏธํ„ฐ
    
    Example:
        >>> order = kis.stock("005930").buy(qty=10, price=65000)
        >>> print(order.order_number)
    """
    ...

4. ๋ช…๋ช… ๊ทœ์น™

ํƒ€์ž… ๊ทœ์น™ ์˜ˆ์‹œ
ํด๋ž˜์Šค PascalCase KisQuote, PyKis
ํ•จ์ˆ˜/๋ฉ”์„œ๋“œ snake_case get_balance(), place_order()
์ƒ์ˆ˜ UPPER_SNAKE_CASE MAX_RETRY, API_VERSION
๋‚ด๋ถ€ ๋ณ€์ˆ˜ snake_case order_count, balance_info
Private _์ ‘๋‘์‚ฌ _internal_method()

5. Import ์ˆœ์„œ

# 1. ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
import os
import sys
from typing import Optional

# 2. ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
import requests
from websocket import WebSocket

# 3. ๋กœ์ปฌ ๋ชจ๋“ˆ
from pykis.client.auth import KisAuth
from pykis.types import Quote

Pull Request ํ”„๋กœ์„ธ์Šค

1. PR ์ƒ์„ฑ ์ „ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • ๋ชจ๋“  ํ…Œ์ŠคํŠธ ํ†ต๊ณผ (poetry run pytest)
  • ํƒ€์ž… ์ฒดํฌ ํ†ต๊ณผ (IDE์—์„œ ํ™•์ธ)
  • ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ํฌํ•จ
  • ๊ณต๊ฐœ API๋Š” Docstring ์ž‘์„ฑ
  • CHANGELOG.md ์—…๋ฐ์ดํŠธ (์ฃผ์š” ๋ณ€๊ฒฝ์‚ฌํ•ญ)
  • ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ๊ทœ์น™ ์ค€์ˆ˜

2. PR ํ…œํ”Œ๋ฆฟ

## ๋ณ€๊ฒฝ ์‚ฌํ•ญ

- ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ / ๋ฒ„๊ทธ ์ˆ˜์ • / ๋ฆฌํŒฉํ† ๋ง ์„ค๋ช…

## ๊ด€๋ จ Issue

Closes #123

## ํ…Œ์ŠคํŠธ

- [ ] ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€/์ˆ˜์ •
- [ ] ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€/์ˆ˜์ •
- [ ] ์ˆ˜๋™ ํ…Œ์ŠคํŠธ ์™„๋ฃŒ

## ๋ฌธ์„œ

- [ ] README.md ์—…๋ฐ์ดํŠธ (ํ•„์š”์‹œ)
- [ ] QUICKSTART.md ์—…๋ฐ์ดํŠธ (ํ•„์š”์‹œ)
- [ ] API ๋ฌธ์„œ ์—…๋ฐ์ดํŠธ (ํ•„์š”์‹œ)

## Breaking Changes

- ์žˆ๋‹ค๋ฉด ๋ช…์‹œ, ์—†์œผ๋ฉด "์—†์Œ"

## ์Šคํฌ๋ฆฐ์ƒท (์„ ํƒ)

(์‹œ๊ฐ์  ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์žˆ๋‹ค๋ฉด ์ฒจ๋ถ€)

3. ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ๊ทœ์น™

ํ˜•์‹: <ํƒ€์ž…>(<๋ฒ”์œ„>): <์ œ๋ชฉ>

ํƒ€์ž…:

  • feat: ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ
  • fix: ๋ฒ„๊ทธ ์ˆ˜์ •
  • docs: ๋ฌธ์„œ ๋ณ€๊ฒฝ
  • style: ์ฝ”๋“œ ํฌ๋งทํŒ… (๊ธฐ๋Šฅ ๋ณ€๊ฒฝ ์—†์Œ)
  • refactor: ๋ฆฌํŒฉํ† ๋ง
  • test: ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€/์ˆ˜์ •
  • chore: ๋นŒ๋“œ/์„ค์ • ๋ณ€๊ฒฝ

์˜ˆ์‹œ:

feat(api): add futures trading API
fix(websocket): resolve reconnection issue
docs(quickstart): update config.yaml example
refactor(helpers): simplify load_config logic
test(unit): add tests for load_config with profiles

4. PR ๋ฆฌ๋ทฐ ํ”„๋กœ์„ธ์Šค

  1. ์ž๋™ ๊ฒ€์‚ฌ: GitHub Actions CI ์‹คํ–‰

    • ํ…Œ์ŠคํŠธ ์‹คํ–‰
    • ์ปค๋ฒ„๋ฆฌ์ง€ ์ฒดํฌ (์ตœ์†Œ 80%)
    • ์ฝ”๋“œ ์Šคํƒ€์ผ ๊ฒ€์‚ฌ
  2. ๋ฆฌ๋ทฐ์–ด ์ง€์ •: ๋ฉ”์ธํ…Œ์ด๋„ˆ๊ฐ€ ๋ฆฌ๋ทฐ

  3. ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜: ๋ฆฌ๋ทฐ ์ฝ”๋ฉ˜ํŠธ์— ์‘๋‹ต ๋ฐ ์ˆ˜์ •

  4. ์Šน์ธ ํ›„ ๋ณ‘ํ•ฉ: ๋ฆฌ๋ทฐ์–ด๊ฐ€ ์Šน์ธํ•˜๋ฉด main์— ๋ณ‘ํ•ฉ


ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ๊ฐ€์ด๋“œ

1. ํ…Œ์ŠคํŠธ ๊ตฌ์กฐ

tests/
โ”œโ”€โ”€ unit/                    # ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (API ํ˜ธ์ถœ ์—†์ด)
โ”‚   โ”œโ”€โ”€ test_public_api_imports.py
โ”‚   โ”œโ”€โ”€ test_simple_helpers.py
โ”‚   โ””โ”€โ”€ test_load_config.py
โ”‚
โ”œโ”€โ”€ integration/             # ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ (์‹ค์ œ API ํ˜ธ์ถœ)
โ”‚   โ”œโ”€โ”€ test_stock_quote.py
โ”‚   โ”œโ”€โ”€ test_account_balance.py
โ”‚   โ””โ”€โ”€ test_websocket.py
โ”‚
โ””โ”€โ”€ fixtures/                # ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ
    โ”œโ”€โ”€ config_sample.yaml
    โ””โ”€โ”€ mock_responses.json

2. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์˜ˆ์‹œ

# tests/unit/test_helpers.py
import pytest
from pykis.helpers import load_config

def test_load_config_single_profile():
    """๋‹จ์ผ ํ”„๋กœํ•„ ์„ค์ • ํŒŒ์ผ ๋กœ๋“œ ํ…Œ์ŠคํŠธ"""
    cfg = load_config("config.example.virtual.yaml")
    
    assert cfg["id"] == "YOUR_VIRTUAL_ID"
    assert cfg["virtual"] is True

def test_load_config_multi_profile_default():
    """๋‹ค์ค‘ ํ”„๋กœํ•„ ์„ค์ • ํŒŒ์ผ์—์„œ ๊ธฐ๋ณธ ํ”„๋กœํ•„ ๋กœ๋“œ"""
    cfg = load_config("config.example.yaml")
    
    assert cfg["id"] == "YOUR_VIRTUAL_ID"  # default = virtual

def test_load_config_multi_profile_explicit():
    """๋‹ค์ค‘ ํ”„๋กœํ•„ ์„ค์ • ํŒŒ์ผ์—์„œ ๋ช…์‹œ์  ํ”„๋กœํ•„ ์„ ํƒ"""
    cfg = load_config("config.example.yaml", profile="real")
    
    assert cfg["id"] == "YOUR_REAL_ID"
    assert cfg["virtual"] is False

def test_load_config_profile_not_found():
    """์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ”„๋กœํ•„ ์„ ํƒ ์‹œ ์—๋Ÿฌ"""
    with pytest.raises(ValueError, match="Profile 'unknown' not found"):
        load_config("config.example.yaml", profile="unknown")

3. ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์˜ˆ์‹œ

# tests/integration/test_stock_quote.py
import pytest
from pykis import PyKis, KisAuth

@pytest.fixture
def kis_client():
    """์‹ค์ œ KIS ํด๋ผ์ด์–ธํŠธ (๋ชจ์˜ํˆฌ์ž)"""
    auth = KisAuth(
        id=os.environ["KIS_ID"],
        account=os.environ["KIS_ACCOUNT"],
        appkey=os.environ["KIS_APPKEY"],
        secretkey=os.environ["KIS_SECRET"],
        virtual=True,
    )
    return PyKis(auth)

def test_get_quote_samsung(kis_client):
    """์‚ผ์„ฑ์ „์ž ์‹œ์„ธ ์กฐํšŒ"""
    quote = kis_client.stock("005930").quote()
    
    assert quote.symbol == "005930"
    assert quote.name == "์‚ผ์„ฑ์ „์ž"
    assert quote.price > 0
    assert quote.volume >= 0

4. ํ…Œ์ŠคํŠธ ์‹คํ–‰

# ์ „์ฒด ํ…Œ์ŠคํŠธ
poetry run pytest

# ํŠน์ • ํŒŒ์ผ๋งŒ
poetry run pytest tests/unit/test_helpers.py

# ํŠน์ • ํ…Œ์ŠคํŠธ๋งŒ
poetry run pytest tests/unit/test_helpers.py::test_load_config_single_profile

# ์ปค๋ฒ„๋ฆฌ์ง€ ํฌํ•จ
poetry run pytest --cov=pykis --cov-report=html

๋ฌธ์„œํ™” ๊ฐ€์ด๋“œ

1. ๋ฌธ์„œ ๊ตฌ์กฐ

docs/
โ”œโ”€โ”€ INDEX.md                  # ๋ฌธ์„œ ์ธ๋ฑ์Šค
โ”œโ”€โ”€ QUICKSTART.md             # ๋น ๋ฅธ ์‹œ์ž‘ (๋ฃจํŠธ์—๋„ ๋ณต์‚ฌ)
โ”œโ”€โ”€ SIMPLEKIS_GUIDE.md        # SimpleKIS ๊ฐ€์ด๋“œ
โ”‚
โ”œโ”€โ”€ architecture/             # ์•„ํ‚คํ…์ฒ˜ ๋ฌธ์„œ
โ”‚   โ””โ”€โ”€ ARCHITECTURE.md
โ”‚
โ”œโ”€โ”€ developer/                # ๊ฐœ๋ฐœ์ž ๊ฐ€์ด๋“œ
โ”‚   โ””โ”€โ”€ DEVELOPER_GUIDE.md
โ”‚
โ”œโ”€โ”€ user/                     # ์‚ฌ์šฉ์ž ๊ฐ€์ด๋“œ
โ”‚   โ””โ”€โ”€ USER_GUIDE.md
โ”‚
โ””โ”€โ”€ reports/                  # ๋ณด๊ณ ์„œ
    โ”œโ”€โ”€ ARCHITECTURE_REPORT_V3_KR.md
    โ””โ”€โ”€ CODE_REVIEW.md

2. ๋ฌธ์„œ ์ž‘์„ฑ ๊ทœ์น™

๋งˆํฌ๋‹ค์šด ์Šคํƒ€์ผ:

# ์ œ๋ชฉ 1 (H1) - ๋ฌธ์„œ ์ œ๋ชฉ์—๋งŒ ์‚ฌ์šฉ

## ์ œ๋ชฉ 2 (H2) - ์ฃผ์š” ์„น์…˜

### ์ œ๋ชฉ 3 (H3) - ํ•˜์œ„ ์„น์…˜

#### ์ œ๋ชฉ 4 (H4) - ์„ธ๋ถ€ ํ•ญ๋ชฉ

**๊ตต๊ฒŒ**, *๊ธฐ์šธ์ž„*, `์ธ๋ผ์ธ ์ฝ”๋“œ`

- ๋ชฉ๋ก ํ•ญ๋ชฉ 1
- ๋ชฉ๋ก ํ•ญ๋ชฉ 2

1. ์ˆœ์„œ ๋ชฉ๋ก 1
2. ์ˆœ์„œ ๋ชฉ๋ก 2

[๋งํฌ ํ…์ŠคํŠธ](URL)

```python
# ์ฝ”๋“œ ๋ธ”๋ก
def example():
    pass

**์˜ˆ์ œ ์ฝ”๋“œ**:
- ์‹ค์ œ ์ž‘๋™ํ•˜๋Š” ์ฝ”๋“œ ์ž‘์„ฑ
- ์ฃผ์„์œผ๋กœ ์„ค๋ช… ์ถ”๊ฐ€
- ๋ฏผ๊ฐ ์ •๋ณด ์ œ์™ธ (config ์˜ˆ์ œ๋Š” `YOUR_*` ์‚ฌ์šฉ)

### 3. API ๋ ˆํผ๋Ÿฐ์Šค ์ž๋™ ์ƒ์„ฑ

```bash
# (ํ–ฅํ›„ ์ถ”๊ฐ€ ์˜ˆ์ •)
poetry run sphinx-apidoc -o docs/api pykis
poetry run sphinx-build -b html docs docs/_build

Issue ์ž‘์„ฑ ๊ฐ€์ด๋“œ

1. ๋ฒ„๊ทธ ๋ฆฌํฌํŠธ

## ๋ฒ„๊ทธ ์„ค๋ช…

(๋ฒ„๊ทธ ํ˜„์ƒ์„ ๋ช…ํ™•ํžˆ ์„ค๋ช…)

## ์žฌํ˜„ ๋ฐฉ๋ฒ•

1. ...
2. ...
3. ...

## ์˜ˆ์ƒ ๋™์ž‘

(์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ–ˆ์„ ๋•Œ์˜ ๊ฒฐ๊ณผ)

## ์‹ค์ œ ๋™์ž‘

(์‹ค์ œ๋กœ ๋ฐœ์ƒํ•œ ํ˜„์ƒ)

## ํ™˜๊ฒฝ

- OS: Windows 11 / macOS 14 / Ubuntu 22.04
- Python ๋ฒ„์ „: 3.11.5
- python-kis ๋ฒ„์ „: 2.1.7
- ์„ค์น˜ ๋ฐฉ๋ฒ•: pip / poetry

## ์—๋Ÿฌ ๋กœ๊ทธ

```python
(์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋˜๋Š” ์Šคํƒ ํŠธ๋ ˆ์ด์Šค ๋ถ™์—ฌ๋„ฃ๊ธฐ)

์ถ”๊ฐ€ ์ •๋ณด

(์Šคํฌ๋ฆฐ์ƒท, ๊ด€๋ จ ์ฝ”๋“œ ๋“ฑ)


### 2. ๊ธฐ๋Šฅ ์ œ์•ˆ

```markdown
## ์ œ์•ˆ ๋ฐฐ๊ฒฝ

(์™œ ์ด ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ์ง€)

## ์ œ์•ˆ ๋‚ด์šฉ

(์–ด๋–ค ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€์ง€)

## ์‚ฌ์šฉ ์˜ˆ์‹œ

```python
# ์ œ์•ˆํ•˜๋Š” API ์‚ฌ์šฉ๋ฒ•
result = kis.new_feature(...)

๋Œ€์•ˆ ๊ณ ๋ ค

(๋‹ค๋ฅธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”์ง€)

๊ธฐํƒ€

(์ถ”๊ฐ€ ์˜๊ฒฌ)


---

## ์ปค๋ฎค๋‹ˆํ‹ฐ ํ–‰๋™ ๊ฐ•๋ น

### ์šฐ๋ฆฌ์˜ ์•ฝ์†

- ๐Ÿค **์กด์ค‘**: ๋ชจ๋“  ๊ธฐ์—ฌ์ž๋ฅผ ์กด์ค‘ํ•ฉ๋‹ˆ๋‹ค
- ๐ŸŒˆ **ํฌ์šฉ**: ๋‹ค์–‘์„ฑ์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค
- ๐Ÿ’ฌ **๊ฑด์„ค์  ํ”ผ๋“œ๋ฐฑ**: ๊ธ์ •์ ์ด๊ณ  ๊ฑด์„ค์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค
- ๐Ÿš€ **ํ˜‘์—…**: ํ•จ๊ป˜ ๋” ๋‚˜์€ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค

### ๊ธˆ์ง€ ํ–‰๋™

- ๐Ÿšซ ๊ฐœ์ธ ๊ณต๊ฒฉ ๋˜๋Š” ๋น„๋ฐฉ
- ๐Ÿšซ ๊ดด๋กญํž˜ ๋˜๋Š” ์ฐจ๋ณ„
- ๐Ÿšซ ์ŠคํŒธ ๋˜๋Š” ํ™๋ณด์„ฑ ๊ฒŒ์‹œ๋ฌผ
- ๐Ÿšซ ๋ถ€์ ์ ˆํ•œ ์ฝ˜ํ…์ธ 

### ์œ„๋ฐ˜ ์‹œ ์กฐ์น˜

๊ฒฝ๊ณ  โ†’ ์ผ์‹œ ์ •์ง€ โ†’ ์˜๊ตฌ ์ฐจ๋‹จ

---

## FAQ

### Q1: ์ฝ”๋“œ๋ฅผ ์ฒ˜์Œ ๊ธฐ์—ฌํ•˜๋Š”๋ฐ ์–ด๋””์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์•ผ ํ•˜๋‚˜์š”?

**A**: [Good First Issue](https://github.com/Soju06/python-kis/labels/good%20first%20issue) ๋ผ๋ฒจ์ด ๋ถ™์€ ์ด์Šˆ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์„ธ์š”.

### Q2: ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋ ค๋ฉด ์‹ค์ œ API ํ‚ค๊ฐ€ ํ•„์š”ํ•œ๊ฐ€์š”?

**A**: ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” API ํ‚ค ์—†์ด ์ž‘์„ฑ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋Š” ๋ชจ์˜ํˆฌ์ž API ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

### Q3: ๋ฌธ์„œ๋งŒ ์ˆ˜์ •ํ•˜๊ณ  ์‹ถ์€๋ฐ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์ „์ฒด๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•˜๋‚˜์š”?

**A**: ์•„๋‹ˆ์š”. GitHub ์›น ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ์ง์ ‘ ๋งˆํฌ๋‹ค์šด ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜๊ณ  PR์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

### Q4: PR์ด ์Šน์ธ๋˜๊ธฐ๊นŒ์ง€ ์–ผ๋งˆ๋‚˜ ๊ฑธ๋ฆฌ๋‚˜์š”?

**A**: ์ผ๋ฐ˜์ ์œผ๋กœ 1-3์ผ ๋‚ด์— ๋ฆฌ๋ทฐ๊ฐ€ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ๋ณ€๊ฒฝ์‚ฌํ•ญ์€ ๋” ์˜ค๋ž˜ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

### Q5: Breaking Change๋ฅผ ์ œ์•ˆํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

**A**: Issue๋ฅผ ๋จผ์ € ์ƒ์„ฑํ•˜์—ฌ ์ปค๋ฎค๋‹ˆํ‹ฐ ์˜๊ฒฌ์„ ์ˆ˜๋ ดํ•œ ํ›„ PR์„ ์ž‘์„ฑํ•˜์„ธ์š”.

### Q6: ์žฌ์‹œ๋„ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋‚˜์š”?

**A**: 429/5xx ์—๋Ÿฌ์— ๋Œ€ํ•œ ์ž๋™ ์žฌ์‹œ๋„๋ฅผ ์›ํ•˜๋ฉด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”:

```python
from pykis.utils.retry import with_retry

@with_retry(max_retries=5, initial_delay=2.0)
def fetch_quote(symbol):
    return kis.stock(symbol).quote()

Q7: JSON ๋กœ๊น…์„ ์–ด๋–ป๊ฒŒ ํ™œ์„ฑํ™”ํ•˜๋‚˜์š”?

A: ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ELK/Datadog๊ณผ ์—ฐ๋™ํ•˜๋ ค๋ฉด:

from pykis.logging import enable_json_logging

enable_json_logging()
# ์ดํ›„ ๋กœ๊ทธ๋Š” JSON ํ˜•์‹์œผ๋กœ ์ถœ๋ ฅ๋จ

Q8: ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋Š” ์–ด๋–ป๊ฒŒ ํ•˜๋‚˜์š”?

A: ์ƒˆ๋กœ์šด ์˜ˆ์™ธ ํด๋ž˜์Šค๋“ค์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

from pykis.exceptions import (
    KisConnectionError,
    KisAuthenticationError,
    KisRateLimitError,
    KisServerError,
)

try:
    quote = kis.stock("005930").quote()
except KisRateLimitError:
    # ์†๋„ ์ œํ•œ - ์žฌ์‹œ๋„ ๊ฐ€๋Šฅ
    pass
except KisAuthenticationError:
    # ์ธ์ฆ ์‹คํŒจ - ํŠน๋ณ„ ์ฒ˜๋ฆฌ
    pass

๋ผ์ด์„ ์Šค

๊ธฐ์—ฌํ•œ ์ฝ”๋“œ๋Š” ํ”„๋กœ์ ํŠธ์˜ MIT ๋ผ์ด์„ ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.


๊ฐ์‚ฌ ์ธ์‚ฌ

Python-KIS์— ๊ธฐ์—ฌํ•ด ์ฃผ์‹  ๋ชจ๋“  ๋ถ„๋“ค๊ป˜ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค! ๐Ÿ™


์งˆ๋ฌธ์ด ์žˆ์œผ์‹œ๋ฉด GitHub Discussions ๋˜๋Š” Issue๋ฅผ ํ†ตํ•ด ๋ฌธ์˜ํ•˜์„ธ์š”.