Kiwoom Open Api Plus Python


Keywords
kiwoom, kiwoom-open-api, backtrader, cybos-plus, grpc, kosdaq, kospi, krx, pyqt5, pyside2, python, system-trading, windows
Licenses
MIT/Apache-2.0/CNRI-Python-GPL-Compatible
Install
pip install koapy==0.8.3

Documentation

KOAPY

PyPI Version

PyPI Python Versions

PyPI Status

CI Build Status

Documentation Build Status

Codecov Coverage

Requires.io Requirements Status

PyPI License

Gitter Chat

Code Style: Black

Kiwoom Open Api Plus Python

Introduction

KOAPY ๋Š” ํ‚ค์›€์ฆ๊ถŒ์˜ OpenAPI+ ๋ฅผ Python ์—์„œ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํŒจํ‚ค์ง€ ๋ฐ ํˆด์ž…๋‹ˆ๋‹ค.

ํ‚ค์›€์—์„œ ์ œ๊ณตํ•˜๋Š” OpenAPI+ ๋ฅผ ํ™œ์šฉํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ๊ตฌ์ฒด์ ์ธ ์ง€์‹๋“ค์„ ์ „ํ˜€ ์•Œ์ง€ ๋ชปํ•ด๋„, ๊ธฐ๋ณธ์ ์ธ Python ์— ๋Œ€ํ•œ ์ง€์‹๋งŒ ์–ด๋Š ์ •๋„ ์žˆ๋‹ค๋ฉด ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์— ์ดˆ์ ์„ ๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด Python ๊ธฐ์ค€์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ๋‚ด์šฉ๋“ค์„ ์ž˜ ๋ชจ๋ฅด๋”๋ผ๋„ ์ถฉ๋ถ„ํžˆ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  • ํ‚ค์›€์—์„œ ์ œ๊ณตํ•˜๋Š” OpenAPI+ ์˜ OCX ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ตฌ์กฐ
  • OCX ๋ฅผ Python ์—์„œ ๊ตฌ๋™ํ•˜๊ธฐ ์œ„ํ•ด PyQt5/PySide2 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ QAxWidget_ ์ƒ์„ฑ
  • ์ปจํŠธ๋กค์—์„œ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์œ„ํ•ด dynamicCall_ ํ•จ์ˆ˜ ์‚ฌ์šฉ
  • ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์ ์ ˆํ•œ signal_/slot_ ์„ค์ • ๋ฐ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ

Showcase

ํ…Œ์ด๋ธ” ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ pandas ์ž„ํฌํŠธ

์—”ํŠธ๋ฆฌํฌ์ธํŠธ ๊ฐ์ฒด ์ƒ์„ฑ

ํ‚ค์›€์ฆ๊ถŒ ์„œ๋ฒ„์™€์˜ ์—ฐ๊ฒฐ ํ™•์ธ ๋ฐ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ

์ข…๋ชฉ ๋ฆฌ์ŠคํŠธ ๋ฐ ์ข…๋ชฉ ์ฝ”๋“œ์™€ ์ด๋ฆ„ ํ™•์ธ

๋‹จ์ผ ์ข…๋ชฉ์˜ ๊ธฐ๋ณธ์ •๋ณด ํ™•์ธ

>>> info = entrypoint.GetStockBasicInfoAsDict(code)
>>> info
{'์ข…๋ชฉ์ฝ”๋“œ': '005930', '์ข…๋ชฉ๋ช…': '์‚ผ์„ฑ์ „์ž', '๊ฒฐ์‚ฐ์›”': '12', '์•ก๋ฉด๊ฐ€': '100', '์ž๋ณธ๊ธˆ': '7780', '์ƒ์žฅ์ฃผ์‹': '5969783', '์‹ ์šฉ๋น„์œจ': '+0.12', '์—ฐ์ค‘์ตœ๊ณ ': '+79800', '์—ฐ์ค‘์ตœ์ €': '-71200', '์‹œ๊ฐ€์ด์•ก': '4417639', '์‹œ๊ฐ€์ด์•ก๋น„์ค‘': '', '์™ธ์ธ์†Œ์ง„๋ฅ ': '+52.09', '๋Œ€์šฉ๊ฐ€': '57170', 'PER': '19.27', 'EPS': '3841', 'ROE': '10.0', 'PBR': '1.88', 'EV': '5.09', 'BPS': '39406', '๋งค์ถœ์•ก': '2368070', '์˜์—…์ด์ต': '359939', '๋‹น๊ธฐ์ˆœ์ด์ต': '264078', '250์ตœ๊ณ ': '+86400', '250์ตœ์ €': '-68300', '์‹œ๊ฐ€': '+74300', '๊ณ ๊ฐ€': '+74600', '์ €๊ฐ€': '+73400', '์ƒํ•œ๊ฐ€': '+95200', 'ํ•˜ํ•œ๊ฐ€': '-51400', '๊ธฐ์ค€๊ฐ€': '73300', '์˜ˆ์ƒ์ฒด๊ฒฐ๊ฐ€': '-0', '์˜ˆ์ƒ์ฒด๊ฒฐ์ˆ˜๋Ÿ‰': '0', '250์ตœ๊ณ ๊ฐ€์ผ': '20210202', '250์ตœ๊ณ ๊ฐ€๋Œ€๋น„์œจ': '-14.35', '250์ตœ์ €๊ฐ€์ผ': '20211013', '250์ตœ์ €๊ฐ€๋Œ€๋น„์œจ': '+8.35', 'ํ˜„์žฌ๊ฐ€': '+74000', '๋Œ€๋น„๊ธฐํ˜ธ': '2', '์ „์ผ๋Œ€๋น„': '+700', '๋“ฑ๋ฝ์œจ': '+0.95', '๊ฑฐ๋ž˜๋Ÿ‰': '12730034', '๊ฑฐ๋ž˜๋Œ€๋น„': '-71.74', '์•ก๋ฉด๊ฐ€๋‹จ์œ„': '์›', '์œ ํ†ต์ฃผ์‹': '4459119', '์œ ํ†ต๋น„์œจ': '74.7'}

๋ณต์ˆ˜ ์ข…๋ชฉ์˜ ๊ธฐ๋ณธ์ •๋ณด ํ™•์ธ

>>> code_list_info = entrypoint.GetStockQuoteInfoAsDataFrame(code_list)
>>> code_list_info
        ์ข…๋ชฉ์ฝ”๋“œ                      ์ข…๋ชฉ๋ช…     ํ˜„์žฌ๊ฐ€    ๊ธฐ์ค€๊ฐ€   ์ „์ผ๋Œ€๋น„ ์ „์ผ๋Œ€๋น„๊ธฐํ˜ธ    ๋“ฑ๋ฝ์œจ  \
0     000020                     ๋™ํ™”์•ฝํ’ˆ  +12450  12300   +150      2  +1.22
1     000040                    KR๋ชจํ„ฐ์Šค    +810    790    +20      2  +2.53
2     000050                       ๊ฒฝ๋ฐฉ  +14450  14200   +250      2  +1.76
3     000060                    ๋ฉ”๋ฆฌ์ธ ํ™”์žฌ   49450  49450      0      3   0.00
4     000070                    ์‚ผ์–‘ํ™€๋”ฉ์Šค  +90700  88400  +2300      2  +2.60
...      ...                      ...     ...    ...    ...    ...    ...
1744  580031  KB ์ธ๋ฒ„์Šค KOSDAQ150 ์„ ๋ฌผ ETN  -10930  10960    -30      5  -0.27
1745  580032     KB ๋ ˆ๋ฒ„๋ฆฌ์ง€ ๊ตฌ๋ฆฌ ์„ ๋ฌผ ETN(H)  -20515  20560    -45      5  -0.22
1746  580033   KB ์ธ๋ฒ„์Šค 2X ๊ตฌ๋ฆฌ ์„ ๋ฌผ ETN(H)  +18350  18280    +70      2  +0.38
1747  580010         KB Wise ๋ถ„ํ• ๋งค๋งค ETN  +10820  10770    +50      2  +0.46
1748  590018       ๋ฏธ๋ž˜์—์…‹ ์ค‘๊ตญ ์‹ฌ์ฒœ 100 ETN  +18810  18645   +165      2  +0.88

        ๊ฑฐ๋ž˜๋Ÿ‰   ๊ฑฐ๋ž˜๋Œ€๊ธˆ   ์ฒด๊ฒฐ๋Ÿ‰  ...    ELW๋งŒ๊ธฐ์ผ ๋ฏธ๊ฒฐ์ œ์•ฝ์ • ๋ฏธ๊ฒฐ์ œ์ „์ผ๋Œ€๋น„ ์ด๋ก ๊ฐ€ ๋‚ด์žฌ๋ณ€๋™์„ฑ ๋ธํƒ€ ๊ฐ๋งˆ ์Ž„ํƒ€ ๋ฒ ๊ฐ€  \
0     135513   1670  +500  ...  00000000
1     230165    186   -10  ...  00000000
2       6214     89    97  ...  00000000
3     411584  20423    -4  ...  00000000
4       9052    813    +5  ...  00000000
...      ...    ...   ...  ...       ...   ...     ...  ..   ... .. .. .. ..
1744       2      0    -1  ...  00000000
1745       0      0        ...  00000000
1746      17      0   +10  ...  00000000
1747       0      0        ...  00000000
1748       1      0    +1  ...  00000000

    ๋กœ
0
1
2
3
4
...  ..
1744
1745
1746
1747
1748

[1749 rows x 63 columns]

ํŠน์ • ์ข…๋ชฉ์˜ ์ฐจํŠธ ๋ฐ์ดํ„ฐ ํ™•์ธ

ํ‚ค์›€์ฆ๊ถŒ์˜ TR ๋ฉ”ํƒ€ ์ •๋ณด ํ™•์ธ

OPT10001 TR ์š”์ฒญ ์ „์†ก ๋ฐ ์‘๋‹ต ์ฒ˜๋ฆฌ (์‹ฑ๊ธ€๋ฐ์ดํ„ฐ)

>>> opt10001_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code("opt10001")
>>> opt10001_info
KiwoomOpenApiPlusTrInfo('opt10001', '์ฃผ์‹๊ธฐ๋ณธ์ •๋ณด์š”์ฒญ', 'STOCK', '', '1', '', [KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ฝ”๋“œ', 0, 6, 9001)], '์ฃผ์‹๊ธฐ๋ณธ์ •๋ณด', [KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ฝ”๋“œ', 0, 20, 389), KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ๋ช…', 20, 50, 302), KiwoomOpenApiPlusTrInfo.Field('๊ฒฐ์‚ฐ์›”', 40, 20, 315), KiwoomOpenApiPlusTrInfo.Field('์•ก๋ฉด๊ฐ€', 60, 20, 310), KiwoomOpenApiPlusTrInfo.Field('์ž๋ณธ๊ธˆ', 80, 20, 309), KiwoomOpenApiPlusTrInfo.Field('์ƒ์žฅ์ฃผ์‹', 100, 20, 312), KiwoomOpenApiPlusTrInfo.Field('์‹ ์šฉ๋น„์œจ', 120, 20, 329), KiwoomOpenApiPlusTrInfo.Field('์—ฐ์ค‘์ตœ๊ณ ', 140, 20, 1006), KiwoomOpenApiPlusTrInfo.Field('์—ฐ์ค‘์ตœ์ €', 160, 20, 1009), KiwoomOpenApiPlusTrInfo.Field('์‹œ๊ฐ€์ด์•ก', 180, 20, 311), KiwoomOpenApiPlusTrInfo.Field('์‹œ๊ฐ€์ด์•ก๋น„์ค‘', 200, 20, 336), KiwoomOpenApiPlusTrInfo.Field('์™ธ์ธ์†Œ์ง„๋ฅ ', 220, 20, 314), KiwoomOpenApiPlusTrInfo.Field('๋Œ€์šฉ๊ฐ€', 240, 20, 308), KiwoomOpenApiPlusTrInfo.Field('PER', 260, 20, 1600), KiwoomOpenApiPlusTrInfo.Field('EPS', 280, 20, 1604), KiwoomOpenApiPlusTrInfo.Field('ROE', 300, 20, 1630), KiwoomOpenApiPlusTrInfo.Field('PBR', 320, 20, 1601), KiwoomOpenApiPlusTrInfo.Field('EV', 340, 20, 1608), KiwoomOpenApiPlusTrInfo.Field('BPS', 360, 20, 1605), KiwoomOpenApiPlusTrInfo.Field('๋งค์ถœ์•ก', 380, 20, 1610), KiwoomOpenApiPlusTrInfo.Field('์˜์—…์ด์ต', 400, 20, 1611), KiwoomOpenApiPlusTrInfo.Field('๋‹น๊ธฐ์ˆœ์ด์ต', 420, 20, 1614), KiwoomOpenApiPlusTrInfo.Field('250์ตœ๊ณ ', 440, 20, 1000), KiwoomOpenApiPlusTrInfo.Field('250์ตœ์ €', 460, 20, 1003), KiwoomOpenApiPlusTrInfo.Field('์‹œ๊ฐ€', 480, 20, 16), KiwoomOpenApiPlusTrInfo.Field('๊ณ ๊ฐ€', 500, 20, 17), KiwoomOpenApiPlusTrInfo.Field('์ €๊ฐ€', 520, 20, 18), KiwoomOpenApiPlusTrInfo.Field('์ƒํ•œ๊ฐ€', 540, 20, 305), KiwoomOpenApiPlusTrInfo.Field('ํ•˜ํ•œ๊ฐ€', 560, 20, 306), KiwoomOpenApiPlusTrInfo.Field('๊ธฐ์ค€๊ฐ€', 580, 20, 307), KiwoomOpenApiPlusTrInfo.Field('์˜ˆ์ƒ์ฒด๊ฒฐ๊ฐ€', 600, 20, 10023), KiwoomOpenApiPlusTrInfo.Field('์˜ˆ์ƒ์ฒด๊ฒฐ์ˆ˜๋Ÿ‰', 620, 20, 10024), KiwoomOpenApiPlusTrInfo.Field('250์ตœ๊ณ ๊ฐ€์ผ', 640, 20, 1001), KiwoomOpenApiPlusTrInfo.Field('250์ตœ๊ณ ๊ฐ€๋Œ€๋น„์œจ', 660, 20, 1002), KiwoomOpenApiPlusTrInfo.Field('250์ตœ์ €๊ฐ€์ผ', 680, 20, 1004), KiwoomOpenApiPlusTrInfo.Field('250์ตœ์ €๊ฐ€๋Œ€๋น„์œจ', 700, 20, 1005), KiwoomOpenApiPlusTrInfo.Field('ํ˜„์žฌ๊ฐ€', 720, 20, 10), KiwoomOpenApiPlusTrInfo.Field('๋Œ€๋น„๊ธฐํ˜ธ', 740, 20, 25), KiwoomOpenApiPlusTrInfo.Field('์ „์ผ๋Œ€๋น„', 760, 20, 11), KiwoomOpenApiPlusTrInfo.Field('๋“ฑ๋ฝ์œจ', 780, 20, 12), KiwoomOpenApiPlusTrInfo.Field('๊ฑฐ๋ž˜๋Ÿ‰', 800, 20, 13), KiwoomOpenApiPlusTrInfo.Field('๊ฑฐ๋ž˜๋Œ€๋น„', 820, 20, 30), KiwoomOpenApiPlusTrInfo.Field('์•ก๋ฉด๊ฐ€๋‹จ์œ„', 840, 20, 796), KiwoomOpenApiPlusTrInfo.Field('์œ ํ†ต์ฃผ์‹', 840, 20, 1683), KiwoomOpenApiPlusTrInfo.Field('์œ ํ†ต๋น„์œจ', 840, 20, 1684)], '', [])

>>> opt10001_info.inputs
[KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ฝ”๋“œ', 0, 6, 9001)]

>>> opt10001_info.single_outputs
[KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ฝ”๋“œ', 0, 20, 389), KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ๋ช…', 20, 50, 302), KiwoomOpenApiPlusTrInfo.Field('๊ฒฐ์‚ฐ์›”', 40, 20, 315), KiwoomOpenApiPlusTrInfo.Field('์•ก๋ฉด๊ฐ€', 60, 20, 310), KiwoomOpenApiPlusTrInfo.Field('์ž๋ณธ๊ธˆ', 80, 20, 309), KiwoomOpenApiPlusTrInfo.Field('์ƒ์žฅ์ฃผ์‹', 100, 20, 312), KiwoomOpenApiPlusTrInfo.Field('์‹ ์šฉ๋น„์œจ', 120, 20, 329), KiwoomOpenApiPlusTrInfo.Field('์—ฐ์ค‘์ตœ๊ณ ', 140, 20, 1006), KiwoomOpenApiPlusTrInfo.Field('์—ฐ์ค‘์ตœ์ €', 160, 20, 1009), KiwoomOpenApiPlusTrInfo.Field('์‹œ๊ฐ€์ด์•ก', 180, 20, 311), KiwoomOpenApiPlusTrInfo.Field('์‹œ๊ฐ€์ด์•ก๋น„์ค‘', 200, 20, 336), KiwoomOpenApiPlusTrInfo.Field('์™ธ์ธ์†Œ์ง„๋ฅ ', 220, 20, 314), KiwoomOpenApiPlusTrInfo.Field('๋Œ€์šฉ๊ฐ€', 240, 20, 308), KiwoomOpenApiPlusTrInfo.Field('PER', 260, 20, 1600), KiwoomOpenApiPlusTrInfo.Field('EPS', 280, 20, 1604), KiwoomOpenApiPlusTrInfo.Field('ROE', 300, 20, 1630), KiwoomOpenApiPlusTrInfo.Field('PBR', 320, 20, 1601), KiwoomOpenApiPlusTrInfo.Field('EV', 340, 20, 1608), KiwoomOpenApiPlusTrInfo.Field('BPS', 360, 20, 1605), KiwoomOpenApiPlusTrInfo.Field('๋งค์ถœ์•ก', 380, 20, 1610), KiwoomOpenApiPlusTrInfo.Field('์˜์—…์ด์ต', 400, 20, 1611), KiwoomOpenApiPlusTrInfo.Field('๋‹น๊ธฐ์ˆœ์ด์ต', 420, 20, 1614), KiwoomOpenApiPlusTrInfo.Field('250์ตœ๊ณ ', 440, 20, 1000), KiwoomOpenApiPlusTrInfo.Field('250์ตœ์ €', 460, 20, 1003), KiwoomOpenApiPlusTrInfo.Field('์‹œ๊ฐ€', 480, 20, 16), KiwoomOpenApiPlusTrInfo.Field('๊ณ ๊ฐ€', 500, 20, 17), KiwoomOpenApiPlusTrInfo.Field('์ €๊ฐ€', 520, 20, 18), KiwoomOpenApiPlusTrInfo.Field('์ƒํ•œ๊ฐ€', 540, 20, 305), KiwoomOpenApiPlusTrInfo.Field('ํ•˜ํ•œ๊ฐ€', 560, 20, 306), KiwoomOpenApiPlusTrInfo.Field('๊ธฐ์ค€๊ฐ€', 580, 20, 307), KiwoomOpenApiPlusTrInfo.Field('์˜ˆ์ƒ์ฒด๊ฒฐ๊ฐ€', 600, 20, 10023), KiwoomOpenApiPlusTrInfo.Field('์˜ˆ์ƒ์ฒด๊ฒฐ์ˆ˜๋Ÿ‰', 620, 20, 10024), KiwoomOpenApiPlusTrInfo.Field('250์ตœ๊ณ ๊ฐ€์ผ', 640, 20, 1001), KiwoomOpenApiPlusTrInfo.Field('250์ตœ๊ณ ๊ฐ€๋Œ€๋น„์œจ', 660, 20, 1002), KiwoomOpenApiPlusTrInfo.Field('250์ตœ์ €๊ฐ€์ผ', 680, 20, 1004), KiwoomOpenApiPlusTrInfo.Field('250์ตœ์ €๊ฐ€๋Œ€๋น„์œจ', 700, 20, 1005), KiwoomOpenApiPlusTrInfo.Field('ํ˜„์žฌ๊ฐ€', 720, 20, 10), KiwoomOpenApiPlusTrInfo.Field('๋Œ€๋น„๊ธฐํ˜ธ', 740, 20, 25), KiwoomOpenApiPlusTrInfo.Field('์ „์ผ๋Œ€๋น„', 760, 20, 11), KiwoomOpenApiPlusTrInfo.Field('๋“ฑ๋ฝ์œจ', 780, 20, 12), KiwoomOpenApiPlusTrInfo.Field('๊ฑฐ๋ž˜๋Ÿ‰', 800, 20, 13), KiwoomOpenApiPlusTrInfo.Field('๊ฑฐ๋ž˜๋Œ€๋น„', 820, 20, 30), KiwoomOpenApiPlusTrInfo.Field('์•ก๋ฉด๊ฐ€๋‹จ์œ„', 840, 20, 796), KiwoomOpenApiPlusTrInfo.Field('์œ ํ†ต์ฃผ์‹', 840, 20, 1683), KiwoomOpenApiPlusTrInfo.Field('์œ ํ†ต๋น„์œจ', 840, 20, 1684)]

>>> opt10001_info.multi_outputs
[]
>>> request_name = "์ฃผ์‹๊ธฐ๋ณธ์ •๋ณด์š”์ฒญ"  # ์‚ฌ์šฉ์ž ๊ตฌ๋ถ„๋ช…, ๊ตฌ๋ถ„๊ฐ€๋Šฅํ•œ ์ž„์˜์˜ ๋ฌธ์ž์—ด
>>> tr_code = "opt10001"
>>> screen_no = "0001"  # ํ™”๋ฉด๋ฒˆํ˜ธ, 0000 ์„ ์ œ์™ธํ•œ 4์ž๋ฆฌ ์ˆซ์ž ์ž„์˜๋กœ ์ง€์ •, None ์˜ ๊ฒฝ์šฐ ๋‚ด๋ถ€์ ์œผ๋กœ ํ™”๋ฉด๋ฒˆํ˜ธ ์ž๋™ํ• ๋‹น
>>> inputs = {
...    "์ข…๋ชฉ์ฝ”๋“œ": "005930",  # ์‚ผ์„ฑ์ „์ž ์ข…๋ชฉ์ฝ”๋“œ
... }

>>> output = {}

>>> for event in entrypoint.TransactionCall(request_name, tr_code, screen_no, inputs):
...     names = event.single_data.names
...     values = event.single_data.values
...     for name, value in zip(names, values):
...         output[name] = value

>>> output
{'์ข…๋ชฉ์ฝ”๋“œ': '005930', '์ข…๋ชฉ๋ช…': '์‚ผ์„ฑ์ „์ž', '๊ฒฐ์‚ฐ์›”': '12', '์•ก๋ฉด๊ฐ€': '100', '์ž๋ณธ๊ธˆ': '7780', '์ƒ์žฅ์ฃผ์‹': '5969783', '์‹ ์šฉ๋น„์œจ': '+0.12', '์—ฐ์ค‘์ตœ๊ณ ': '+79800', '์—ฐ์ค‘์ตœ์ €': '-71200', '์‹œ๊ฐ€์ด์•ก': '4417639', '์‹œ๊ฐ€์ด์•ก๋น„์ค‘': '', '์™ธ์ธ์†Œ์ง„๋ฅ ': '+52.09', '๋Œ€์šฉ๊ฐ€': '57170', 'PER': '19.27', 'EPS': '3841', 'ROE': '10.0', 'PBR': '1.88', 'EV': '5.09', 'BPS': '39406', '๋งค์ถœ์•ก': '2368070', '์˜์—…์ด์ต': '359939', '๋‹น๊ธฐ์ˆœ์ด์ต': '264078', '250์ตœ๊ณ ': '+86400', '250์ตœ์ €': '-68300', '์‹œ๊ฐ€': '+74300', '๊ณ ๊ฐ€': '+74600', '์ €๊ฐ€': '+73400', '์ƒํ•œ๊ฐ€': '+95200', 'ํ•˜ํ•œ๊ฐ€': '-51400', '๊ธฐ์ค€๊ฐ€': '73300', '์˜ˆ์ƒ์ฒด๊ฒฐ๊ฐ€': '-0', '์˜ˆ์ƒ์ฒด๊ฒฐ์ˆ˜๋Ÿ‰': '0', '250์ตœ๊ณ ๊ฐ€์ผ': '20210202', '250์ตœ๊ณ ๊ฐ€๋Œ€๋น„์œจ': '-14.35', '250์ตœ์ €๊ฐ€์ผ': '20211013', '250์ตœ์ €๊ฐ€๋Œ€๋น„์œจ': '+8.35', 'ํ˜„์žฌ๊ฐ€': '+74000', '๋Œ€๋น„๊ธฐํ˜ธ': '2', '์ „์ผ๋Œ€๋น„': '+700', '๋“ฑ๋ฝ์œจ': '+0.95', '๊ฑฐ๋ž˜๋Ÿ‰': '12730034', '๊ฑฐ๋ž˜๋Œ€๋น„': '-71.74', '์•ก๋ฉด๊ฐ€๋‹จ์œ„': '์›', '์œ ํ†ต์ฃผ์‹': '4459119', '์œ ํ†ต๋น„์œจ': '74.7'}

OPT10081 TR ์š”์ฒญ ์ „์†ก ๋ฐ ์‘๋‹ต ์ฒ˜๋ฆฌ (๋ฉ€ํ‹ฐ๋ฐ์ดํ„ฐ)

>>> opt10081_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code("opt10081")
>>> opt10081_info
KiwoomOpenApiPlusTrInfo('opt10081', '์ฃผ์‹์ผ๋ด‰์ฐจํŠธ์กฐํšŒ์š”์ฒญ', 'SCHART', '', '1', '3003', [KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ฝ”๋“œ', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('๊ธฐ์ค€์ผ์ž', 20, 20, 9004), KiwoomOpenApiPlusTrInfo.Field('์ˆ˜์ •์ฃผ๊ฐ€๊ตฌ๋ถ„', 40, 20, 9055)], '์ฃผ์‹์ผ๋ด‰์ฐจํŠธ', [KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ฝ”๋“œ', 0, 20, 9001)], '์ฃผ์‹์ผ๋ด‰์ฐจํŠธ์กฐํšŒ', [KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ฝ”๋“œ', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('ํ˜„์žฌ๊ฐ€', 0, 20, 10), KiwoomOpenApiPlusTrInfo.Field('๊ฑฐ๋ž˜๋Ÿ‰', 40, 20, 13), KiwoomOpenApiPlusTrInfo.Field('๊ฑฐ๋ž˜๋Œ€๊ธˆ', 60, 20, 14), KiwoomOpenApiPlusTrInfo.Field('์ผ์ž', 80, 20, 22), KiwoomOpenApiPlusTrInfo.Field('์‹œ๊ฐ€', 100, 20, 16), KiwoomOpenApiPlusTrInfo.Field('๊ณ ๊ฐ€', 120, 20, 17), KiwoomOpenApiPlusTrInfo.Field('์ €๊ฐ€', 140, 20, 18), KiwoomOpenApiPlusTrInfo.Field('์ˆ˜์ •์ฃผ๊ฐ€๊ตฌ๋ถ„', 160, 20, 3502), KiwoomOpenApiPlusTrInfo.Field('์ˆ˜์ •๋น„์œจ', 180, 20, 3503), KiwoomOpenApiPlusTrInfo.Field('๋Œ€์—…์ข…๊ตฌ๋ถ„', 200, 20, 317), KiwoomOpenApiPlusTrInfo.Field('์†Œ์—…์ข…๊ตฌ๋ถ„', 220, 20, 318), KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ •๋ณด', 240, 20, 370), KiwoomOpenApiPlusTrInfo.Field('์ˆ˜์ •์ฃผ๊ฐ€์ด๋ฒคํŠธ', 260, 20, 3501), KiwoomOpenApiPlusTrInfo.Field('์ „์ผ์ข…๊ฐ€', 280, 20, 346)])

>>> opt10081_info.inputs
[KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ฝ”๋“œ', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('๊ธฐ์ค€์ผ์ž', 20, 20, 9004), KiwoomOpenApiPlusTrInfo.Field('์ˆ˜์ •์ฃผ๊ฐ€๊ตฌ๋ถ„', 40, 20, 9055)]

>>> opt10081_info.single_outputs
[KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ฝ”๋“œ', 0, 20, 9001)]

>>> opt10081_info.multi_outputs
[KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ฝ”๋“œ', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('ํ˜„์žฌ๊ฐ€', 0, 20, 10), KiwoomOpenApiPlusTrInfo.Field('๊ฑฐ๋ž˜๋Ÿ‰', 40, 20, 13), KiwoomOpenApiPlusTrInfo.Field('๊ฑฐ๋ž˜๋Œ€๊ธˆ', 60, 20, 14), KiwoomOpenApiPlusTrInfo.Field('์ผ์ž', 80, 20, 22), KiwoomOpenApiPlusTrInfo.Field('์‹œ๊ฐ€', 100, 20, 16), KiwoomOpenApiPlusTrInfo.Field('๊ณ ๊ฐ€', 120, 20, 17), KiwoomOpenApiPlusTrInfo.Field('์ €๊ฐ€', 140, 20, 18), KiwoomOpenApiPlusTrInfo.Field('์ˆ˜์ •์ฃผ๊ฐ€๊ตฌ๋ถ„', 160, 20, 3502), KiwoomOpenApiPlusTrInfo.Field('์ˆ˜์ •๋น„์œจ', 180, 20, 3503), KiwoomOpenApiPlusTrInfo.Field('๋Œ€์—…์ข…๊ตฌ๋ถ„', 200, 20, 317), KiwoomOpenApiPlusTrInfo.Field('์†Œ์—…์ข…๊ตฌ๋ถ„', 220, 20, 318), KiwoomOpenApiPlusTrInfo.Field('์ข…๋ชฉ์ •๋ณด', 240, 20, 370), KiwoomOpenApiPlusTrInfo.Field('์ˆ˜์ •์ฃผ๊ฐ€์ด๋ฒคํŠธ', 260, 20, 3501), KiwoomOpenApiPlusTrInfo.Field('์ „์ผ์ข…๊ฐ€', 280, 20, 346)]
>>> request_name = "์ฃผ์‹์ผ๋ด‰์ฐจํŠธ์กฐํšŒ์š”์ฒญ"  # ์‚ฌ์šฉ์ž ๊ตฌ๋ถ„๋ช…, ๊ตฌ๋ถ„๊ฐ€๋Šฅํ•œ ์ž„์˜์˜ ๋ฌธ์ž์—ด
>>> tr_code = "opt10081"
>>> screen_no = "0001"  # ํ™”๋ฉด๋ฒˆํ˜ธ, 0000 ์„ ์ œ์™ธํ•œ 4์ž๋ฆฌ ์ˆซ์ž ์ž„์˜๋กœ ์ง€์ •, None ์˜ ๊ฒฝ์šฐ ๋‚ด๋ถ€์ ์œผ๋กœ ํ™”๋ฉด๋ฒˆํ˜ธ ์ž๋™ํ• ๋‹น
>>> inputs = {
...     "์ข…๋ชฉ์ฝ”๋“œ": "005930",  # ์‚ผ์„ฑ์ „์ž ์ข…๋ชฉ์ฝ”๋“œ
...     "๊ธฐ์ค€์ผ์ž": "20220206",  # ๊ฐ€์žฅ ์ตœ๊ทผ ๋‚ ์งœ์˜ YYYYMMDD ํฌ๋งท
...     "์ˆ˜์ •์ฃผ๊ฐ€๊ตฌ๋ถ„": "0",  # 0:์ผ๋ฐ˜์ฃผ๊ฐ€, 1:์ˆ˜์ •์ฃผ๊ฐ€
... }

>>> data_list = []

>>> for event in entrypoint.TransactionCall(request_name, tr_code, screen_no, inputs):
...     columns = event.multi_data.names
...     records = [values.values for values in event.multi_data.values]
...     data = pd.DataFrame.from_records(records, columns=columns)
...     data_list.append(data)

>>> data = pd.concat(data_list, axis=0).reset_index(drop=True)
>>> data
        ์ข…๋ชฉ์ฝ”๋“œ    ํ˜„์žฌ๊ฐ€       ๊ฑฐ๋ž˜๋Ÿ‰     ๊ฑฐ๋ž˜๋Œ€๊ธˆ        ์ผ์ž     ์‹œ๊ฐ€     ๊ณ ๊ฐ€     ์ €๊ฐ€ ์ˆ˜์ •์ฃผ๊ฐ€๊ตฌ๋ถ„  \
0     005930  74000  12730034   941413  20220204  74300  74600  73400
1             73300  17744721  1314506  20220203  74900  74900  73300
2             73300  21367447  1552586  20220128  71300  73700  71200
3             71300  22274777  1603685  20220127  73800  74000  71300
4             73300  12976730   955547  20220126  73900  74400  73100
...      ...    ...       ...      ...       ...    ...    ...    ...    ...
9797           8010      4970        1  19850109   8240   8240   7950
9798           8300     12930        4  19850108   8400   8400   8300
9799           8410     11810        3  19850107   8400   8500   8390
9800           8390      1660        0  19850105   8400   8440   8390
9801           8450      1710        0  19850104   8500   8500   8450

    ์ˆ˜์ •๋น„์œจ ๋Œ€์—…์ข…๊ตฌ๋ถ„ ์†Œ์—…์ข…๊ตฌ๋ถ„ ์ข…๋ชฉ์ •๋ณด ์ˆ˜์ •์ฃผ๊ฐ€์ด๋ฒคํŠธ ์ „์ผ์ข…๊ฐ€
0
1
2
3
4
...   ...   ...   ...  ...     ...  ...
9797
9798
9799
9800
9801

[9802 rows x 15 columns]

์กฐ๊ฑด๊ฒ€์ƒ‰ ์กฐ๊ฑด์‹ ์„ค์ • ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

๋ถˆ๋Ÿฌ์˜จ ์กฐ๊ฑด์‹ ๋ชฉ๋ก ํ™•์ธ

์กฐ๊ฑด์‹ ๋‹จ์ˆœ ๊ฒ€์ƒ‰

>>> condition_name = "๋Œ€ํ˜• ์ €ํ‰๊ฐ€ ์šฐ๋Ÿ‰์ฃผ"
>>> condition_met_code_list, condition_met_code_list_info = entrypoint.GetCodeListByCondition(condition_name, with_info=True)

>>> condition_met_code_list
['000240', '001800', '001880', '003230', '003550', '004000', '006040', '006390', '006650', '007700', '009970', '011780', '014830', '020000', '021240', '025540', '030520', '033290', '033780', '036830', '042420', '056190', '057050', '060150', '064960', '069080', '081660', '095660', '096530', '110790', '111770', '137310', '161390', '161890', '185750', '192080', '192400', '200130', '243070', '271560', '284740', '285130', '294870', '300720', '950130']

>>> condition_met_code_list_info  # same as entrypoint.GetStockQuoteInfoAsDataFrame(condition_met_code_list)
      ์ข…๋ชฉ์ฝ”๋“œ        ์ข…๋ชฉ๋ช…      ํ˜„์žฌ๊ฐ€     ๊ธฐ์ค€๊ฐ€   ์ „์ผ๋Œ€๋น„ ์ „์ผ๋Œ€๋น„๊ธฐํ˜ธ     ๋“ฑ๋ฝ์œจ      ๊ฑฐ๋ž˜๋Ÿ‰    ๊ฑฐ๋ž˜๋Œ€๊ธˆ  \
0   000240     ํ•œ๊ตญ์•ค์ปดํผ๋‹ˆ   +13500   13400   +100      2   +0.75    56484     760
1   001800     ์˜ค๋ฆฌ์˜จํ™€๋”ฉ์Šค   +14600   14250   +350      2   +2.46    69827    1008
2   001880       DL๊ฑด์„ค   -27950   28050   -100      5   -0.36    20925     583
3   003230       ์‚ผ์–‘์‹ํ’ˆ   +91300   90000  +1300      2   +1.44    58660    5289
4   003550         LG   +76300   74600  +1700      2   +2.28   249415   18925
..     ...        ...      ...     ...    ...    ...     ...      ...     ...
40  284740      ์ฟ ์ฟ ํ™ˆ์‹œ์Šค   +36700   35900   +800      2   +2.23    30134    1102
41  285130      SK์ผ€๋ฏธ์นผ  +130500  129500  +1000      2   +0.77    58032    7544
42  294870  HDCํ˜„๋Œ€์‚ฐ์—…๊ฐœ๋ฐœ   +15600   14600  +1000      2   +6.85  3145356   49106
43  300720      ํ•œ์ผ์‹œ๋ฉ˜ํŠธ   +19250   18750   +500      2   +2.67   159419    3021
44  950130     ์—‘์„ธ์Šค๋ฐ”์ด์˜ค   -18400   22400  -4000      5  -17.86  5877689  119649

    ์ฒด๊ฒฐ๋Ÿ‰  ...    ELW๋งŒ๊ธฐ์ผ ๋ฏธ๊ฒฐ์ œ์•ฝ์ • ๋ฏธ๊ฒฐ์ œ์ „์ผ๋Œ€๋น„ ์ด๋ก ๊ฐ€ ๋‚ด์žฌ๋ณ€๋™์„ฑ ๋ธํƒ€ ๊ฐ๋งˆ ์Ž„ํƒ€ ๋ฒ ๊ฐ€ ๋กœ
0   5549  ...  00000000
1     +1  ...  00000000
2    369  ...  00000000
3     +2  ...  00000000
4   +100  ...  00000000
..   ...  ...       ...   ...     ...  ..   ... .. .. .. .. ..
40    -3  ...  00000000
41    -1  ...  00000000
42   -25  ...  00000000
43    -4  ...  00000000
44   -36  ...  00000000

[45 rows x 63 columns]

GRPC ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ ๊ด€๋ จ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ (๋ฐ๋ชจ ๋ชฉ์ )

์กฐ๊ฑด์‹ ์‹ค์‹œ๊ฐ„ ๊ฒ€์ƒ‰

๊ณ„์ขŒ์ •๋ณด ํ™•์ธ

์ฃผ๋ฌธ ์š”์ฒญ (์‚ผ์„ฑ์ „์ž ์‹œ์žฅ๊ฐ€ ๋งค์ˆ˜)

>>> request_name = "์‚ผ์„ฑ์ „์ž 1์ฃผ ์‹œ์žฅ๊ฐ€ ์‹ ๊ทœ ๋งค์ˆ˜"  # ์‚ฌ์šฉ์ž ๊ตฌ๋ถ„๋ช…, ๊ตฌ๋ถ„๊ฐ€๋Šฅํ•œ ์ž„์˜์˜ ๋ฌธ์ž์—ด
>>> screen_no = "0001"  # ํ™”๋ฉด๋ฒˆํ˜ธ, 0000 ์„ ์ œ์™ธํ•œ 4์ž๋ฆฌ ์ˆซ์ž ์ž„์˜๋กœ ์ง€์ •, None ์˜ ๊ฒฝ์šฐ ๋‚ด๋ถ€์ ์œผ๋กœ ํ™”๋ฉด๋ฒˆํ˜ธ ์ž๋™ํ• ๋‹น
>>> account_no = "8014526011"  # ๊ณ„์ขŒ๋ฒˆํ˜ธ 10์ž๋ฆฌ, ์—ฌ๊ธฐ์„œ๋Š” ๊ณ„์ขŒ๋ฒˆํ˜ธ ๋ชฉ๋ก์—์„œ ์ฒซ๋ฒˆ์งธ๋กœ ๋ฐœ๊ฒฌํ•œ ๊ณ„์ขŒ๋ฒˆํ˜ธ๋กœ ๋งค์ˆ˜์ฒ˜๋ฆฌ
>>> order_type = 1  # ์ฃผ๋ฌธ์œ ํ˜•, 1:์‹ ๊ทœ๋งค์ˆ˜
>>> code = "005930"  # ์ข…๋ชฉ์ฝ”๋“œ, ์•ž์˜ ์‚ผ์„ฑ์ „์ž ์ข…๋ชฉ์ฝ”๋“œ
>>> quantity = 1  # ์ฃผ๋ฌธ์ˆ˜๋Ÿ‰, 1์ฃผ ๋งค์ˆ˜
>>> price = 0  # ์ฃผ๋ฌธ๊ฐ€๊ฒฉ, ์‹œ์žฅ๊ฐ€ ๋งค์ˆ˜๋Š” ๊ฐ€๊ฒฉ ์„ค์ • ์˜๋ฏธ ์—†์œผ๋ฏ€๋กœ ๊ธฐ๋ณธ๊ฐ’ 0 ์œผ๋กœ ์„ค์ •
>>> quote_type = "03"  # ๊ฑฐ๋ž˜๊ตฌ๋ถ„, 03:์‹œ์žฅ๊ฐ€
>>> original_order_no = ""  # ์›์ฃผ๋ฌธ๋ฒˆํ˜ธ, ์ฃผ๋ฌธ ์ •์ •/์ทจ์†Œ ๋“ฑ์—์„œ ์‚ฌ์šฉ

>>> stream = entrypoint.OrderCall(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no)

>>> for event in warn_on_rpc_error(stream):
...     if event.name == "OnReceiveTrData":
...         order_no = event.single_data.values[0]
...     elif event.name == "OnReceiveChejanData":
...         gubun = event.arguments[0].string_value
...         data = dict(zip(event.single_data.names, event.single_data.values))
...         if gubun == "0":
...             status = data["์ฃผ๋ฌธ์ƒํƒœ"]
...             if status == "์ ‘์ˆ˜":
...                 pass
...             elif status == "์ฒด๊ฒฐ":
...                 orders_filled = data["์ฒด๊ฒฐ๋Ÿ‰"]
...                 orders_left = data["๋ฏธ์ฒด๊ฒฐ์ˆ˜๋Ÿ‰"]
...             elif status == "ํ™•์ธ":
...                 org_order_no = data["์›์ฃผ๋ฌธ๋ฒˆํ˜ธ"]
...                 assert original_order_no == org_order_no
...         elif gubun in ["1", "4"]:
...             stocks = data["๋ณด์œ ์ˆ˜๋Ÿ‰"]

ํ‚ค์›€์ฆ๊ถŒ์˜ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ๋ฉ”ํƒ€ ์ •๋ณด ํ™•์ธ

>>> realtype_descs = [realtype.desc for realtype in realtype_list]
>>> realtype_descs
['์ฃผ์‹์‹œ์„ธ', '์ฃผ์‹์ฒด๊ฒฐ', '์ฃผ์‹์ƒํ•˜ํ•œ', '์ฃผ์‹์šฐ์„ ํ˜ธ๊ฐ€', '์ฃผ์‹ํ˜ธ๊ฐ€์ž”๋Ÿ‰', '์ฃผ์‹์‹œ๊ฐ„์™ธํ˜ธ๊ฐ€', '์ฃผ์‹๋‹น์ผ๊ฑฐ๋ž˜์›', 'ETF NAV', 'ELW ์ง€ํ‘œ', 'ELW ์ด๋ก ๊ฐ€', '์ฃผ์‹์˜ˆ์ƒ์ฒด๊ฒฐ', '์ฃผ์‹์ข…๋ชฉ์ •๋ณด', '์ž„์˜์—ฐ์žฅ์ •๋ณด', 'ECN์ฃผ์‹์‹œ์„ธ', 'ECN์ฃผ์‹์ฒด๊ฒฐ', 'ECN์ฃผ์‹์šฐ์„ ํ˜ธ๊ฐ€', 'ECN์ฃผ์‹ํ˜ธ๊ฐ€์ž”๋Ÿ‰', 'ECN์ฃผ์‹์‹œ๊ฐ„์™ธํ˜ธ๊ฐ€', 'ECN์ฃผ์‹๋‹น์ผ๊ฑฐ๋ž˜์›', '์‹œ๊ฐ„์™ธ์ข…๋ชฉ์ •๋ณด', '์ฃผ์‹๊ฑฐ๋ž˜์›', '์ฃผ์‹๊ฑฐ๋ž˜์›(1LINE)', '์ข…๋ชฉ๋ณ„ํ”„๋กœ๊ทธ๋žจ๋งค๋งค', 'VI์ •์ ์˜ˆ์ƒ๊ฐ€', 'VI๋ฐœ๋™/ํ•ด์ œ-์ข…๋ชฉ๋ณ„', '์ข…๋ชฉ๋ณ„ํ”„๋กœ๊ทธ๋žจ๋งค๋งค2', '์ข…๋ชฉํˆฌ์ž์ž(์ž ์ •)', '์ข…๋ชฉํˆฌ์ž์ž(๊ฑฐ๋ž˜์†Œ)', '๋Œ€์ฃผ๊ฐ€๋Šฅ์ˆ˜๋Ÿ‰', '์„ ๋ฌผ์˜ต์…˜์šฐ์„ ํ˜ธ๊ฐ€', '์„ ๋ฌผ์‹œ์„ธ', '์„ ๋ฌผํ˜ธ๊ฐ€์ž”๋Ÿ‰', '์„ ๋ฌผ์ด๋ก ๊ฐ€', '์„ ๋ฌผ๊ธฐ์ดˆ์ž์‚ฐ์‹œ์„ธ', '์‹ค์‹œ๊ฐ„์ƒํ•˜ํ•œ๊ฐ€', '์˜ต์…˜์‹œ์„ธ', '์˜ต์…˜ํ˜ธ๊ฐ€์ž”๋Ÿ‰', '์˜ต์…˜์ด๋ก ๊ฐ€', '์ฃผ์‹์˜ต์…˜์‹œ์„ธ', '์ฃผ์‹์˜ต์…˜ํ˜ธ๊ฐ€์ž”๋Ÿ‰', '์ฃผ์‹์˜ต์…˜์ด๋ก ๊ฐ€', '์—…์ข…์ง€์ˆ˜', '์—…์ข…๋“ฑ๋ฝ', '์ž์ฒด์—…์ข…์ง€์ˆ˜', '์˜ˆ์ƒ์—…์ข…์ง€์ˆ˜', '์‹œํ™ฉ/๋‰ด์Šค', 'ํ™˜๋ฅ ', '์žฅ์‹œ์ž‘์‹œ๊ฐ„', 'ํˆฌ์ž์žticker', '์ƒํ•˜ํ•œ๊ฐ€ํญ๋ณ€๊ฒฝ', 'VI๋ฐœ๋™/ํ•ด์ œ', 'ํˆฌ์ž์ž๋ณ„๋งค๋งค', 'ํ”„๋กœ๊ทธ๋žจ๋งค๋งค', 'ํ•ด์™ธ์‹œ์„ธ', '์ฃผ๋ฌธ์ฒด๊ฒฐ', 'ํŒŒ์ƒ์ž”๊ณ ', 'ํ˜„๋ฌผ์ž”๊ณ ', '์˜ˆ์ˆ˜๊ธˆ', 'ํ•ด์™ธ์ฃผ๋ฌธ์ฒด๊ฒฐ', 'ํ•ด์™ธ์ž”๊ณ ', '์ˆœ๊ฐ„์ฒด๊ฒฐ๋Ÿ‰', '์ฃผ๋ฌธ์ฒด๊ฒฐ์„œ๋ฒ„์ƒํƒœ', '์ฆ๊ฑฐ๊ธˆ', 'CFD์ฃผ๋ฌธ', 'CFD์ฒด๊ฒฐ', 'CFD๋งˆ์ง„์ฝœ๊ฒฝ๊ณ ', 'CFD์ž…์ถœ๊ณ ', '์ž์œ ํฌ๋ฉง', '์กฐ๊ฑด๊ฒ€์ƒ‰', '์ผ๋ฐ˜์‹ ํ˜ธ', '๋ฆฌ์–ผ์ž”๊ณ ', 'ํ•ด์™ธ๋ฆฌ์–ผ์ž”๊ณ ', '๋ฆฌ์–ผ์ž”๊ณ ์ดํ•ฉ', 'ํ•ด์™ธ์ž”๊ณ ์ดํ•ฉ', '์Šคํ†ฑ๋กœ์Šค', '์„ ๋ฌผ์˜ต์…˜ํ•ฉ๊ณ„', '์Šคํ†ฑ์ฃผ๋ฌธ', 'CFD์ฃผ๋ฌธ์ฒด๊ฒฐ', 'CFD๋ฆฌ์–ผ์ž”๊ณ ', 'CFD๋ฆฌ์–ผ์ž”๊ณ ์ดํ•ฉ', '๋ชจ๋‹ˆํ„ฐ๋ง ์‹ค์‹œ๊ฐ„LOG', '์ฃผ์‹์„ ๋ฌผํ˜ธ๊ฐ€์ž”๋Ÿ‰', '์‹ค์‹œ๊ฐ„์ฆ๊ฑฐ๊ธˆ', 'X-Ray์ˆœ๊ฐ„์ฒด๊ฒฐ๋Ÿ‰', '๋งค์ž…์ธ๋„์ฒด๊ฒฐ', '๋งค์ž…์ธ๋„ํ˜ธ๊ฐ€', '์ฝ”๋„ฅ์Šค๊ฒฝ๋งค๋งค์ฒด๊ฒฐ', '๋ฐ์ดํ„ฐ์…‹์‹ค์‹œ๊ฐ„', 'ํ™์ฝฉ์ฒด๊ฒฐ', 'ํ™์ฝฉ์‹œ์„ธ', 'ํ™์ฝฉํ˜ธ๊ฐ€์ž”๋Ÿ‰', 'ํ™์ฝฉ๋‹จ์ผ๊ฐ€์‹œ์„ธ', 'ํ™์ฝฉ์—…์ข…์ง€์ˆ˜', 'ํ™์ฝฉ์‹ค์‹œ๊ฐ„์ƒํ•˜ํ•œ๊ฐ€', '์ˆ˜๋™์ž๋™์ฃผ๋ฌธ', '์ž๋™์ฃผ๋ฌธ๊ฒฐ๊ณผ', 'TS๊ณ ์ €๋ณ€๊ฒฝ', '์ž”๊ณ ํŽธ์ž…', '๊ธฐ์ค€๊ฐ€๋ณ€๊ฒฝ', '๋ฉ€ํ‹ฐ์ฐจ๋‹จ', '์ž”๊ณ ์ฒญ์‚ฐ์‚ญ์ œ', 'ํ›„๊ฐ•ํ‰์ฒด๊ฒฐ', 'ํ›„๊ฐ•ํ‰์‹œ์„ธ', 'ํ›„๊ฐ•ํ‰ํ˜ธ๊ฐ€์ž”๋Ÿ‰', 'ํ›„๊ฐ•ํ‰๋‹จ์ผ๊ฐ€์‹œ์„ธ', 'ํ›„๊ฐ•ํ‰์—…์ข…์ง€์ˆ˜', '๋ฏธ์ฒด๊ฒฐํ†ต๋ณด์‹œ์Šคํ…œ', '์ฑ„๋„K์‹ค์‹œ๊ฐ„ํ‹ฐ์ปค', '๋น…๋ฐ์ดํ„ฐ์ข…๋ชฉ1๋ถ„', '๋น…๋ฐ์ดํ„ฐ์ข…๋ชฉ10๋ถ„', '๋น…๋ฐ์ดํ„ฐ์ข…๋ชฉ1์‹œ๊ฐ„', '๋น…๋ฐ์ดํ„ฐ์ข…๋ชฉ๋‹น์ผ', '๋น…๋ฐ์ดํ„ฐ๋‰ด์Šค', '์‹ ํ˜ธ๊ด€๋ฆฌ์žํˆฌ์ž์ •๋ณด', '๋น…๋ฐ์ดํ„ฐ๊ธ‰์ƒ์Šน', '๋น…๋ฐ์ดํ„ฐ์ข…๋ชฉ30์ดˆ', '์•Œ-์ข…๋ชฉํฌ์ฐฉ์ดํƒˆ', '์•Œ-๋งค๋„๊ฐ์‹œ์‹œ์ž‘', '์•Œ-๋งค๋„๊ฐ์‹œํฌ์ฐฉ', '์•Œ-์ฃผ๋ฌธ๊ฒฐ๊ณผ', '์•Œ-์ฒญ์‚ฐ์‹œ์ž‘', '์•Œ-์ฒญ์‚ฐ์™„๋ฃŒ', '์•Œ-๊ฐ์‹œ์‹œ์ž‘', '์•Œ-๋‚ด์กฐ๊ฑด์‹์ˆ˜์ •', '์•Œ-์ฃผ๋ฌธ์กฐ๊ฑด์ˆ˜์ •', '์•Œ-์ œํ•œ์—ฌ๋ถ€', '์•Œ-๋ฉ€ํ‹ฐ์ฐจ๋‹จ', '์•Œ-TS๋ณ€๊ฒฝ', '์•Œ-๋ชจ์˜์ฃผ๋ฌธ์ฒด๊ฒฐ', '์•Œ-๋ชจ์˜ํ˜„๋ฌผ์ž”๊ณ ', '์•Œ-๋ชจ์˜ ์ฃผ๋ฌธ์ฒด๊ฒฐ', '์•Œ-๋ชจ์˜ ๋ฆฌ์–ผ์ž”๊ณ ', '์•Œ-๋ชจ์˜๋ฆฌ์–ผ์ž”๊ณ ์ดํ•ฉ', '์ฑ„๊ถŒ์ฒด๊ฒฐ', '์ฑ„๊ถŒํ˜ธ๊ฐ€์ž”๋Ÿ‰', '์†Œ์•ก์ฑ„๊ถŒ์ฒด๊ฒฐ', '์†Œ์•ก์ฑ„๊ถŒํ˜ธ๊ฐ€์ž”๋Ÿ‰', 'CME์‹œ์„ธ', 'CME๋ฏธ๊ฒฐ์ œ์•ฝ์ •', 'CMEํ˜ธ๊ฐ€์ž”๋Ÿ‰', 'EUF์‹œ์„ธ', 'EUFํ˜ธ๊ฐ€์ž”๋Ÿ‰', 'EUREX์‹œ์„ธ', 'EUREXํ˜ธ๊ฐ€', '๋ฐฐ์น˜๋ฐ์ดํ„ฐ๊ฐฑ์‹ ', '์ข…๋ชฉ๋งˆ์Šคํ„ฐ๊ฐฑ์‹ ', 'ํ•ด์™ธ์ฃผ์‹์ฃผ๋ฌธ', 'ํ•ด์™ธ์ฃผ์‹์ฒด๊ฒฐ', 'ํ•ด์™ธ์‹ค์‹œ๊ฐ„์ž”๊ณ ์กฐํšŒ', '๋ฏธ๊ตญ์ž…์ถœ๊ณ ', '๋ฏธ๊ตญ์ข…๋ชฉ๋ณ€๊ฒฝ', 'CME/EUREX์ฃผ๋ฌธ', 'CME/EUREX์ฒด๊ฒฐ', 'CME๋ฐฐ์น˜', 'EUREX๋ฐฐ์น˜', 'CME๋ฏธ์ฒด๊ฒฐ', 'CME์‹ค์‹œ๊ฐ„์ž”๊ณ ', 'CME์ž”๊ณ ํ•ฉ', '๋ถ„ํ• ๋ฐ˜๋ณต์ฃผ๋ฌธ']

>>> realtype_info = KiwoomOpenApiPlusRealType.get_realtype_info_by_name("์ฃผ์‹์‹œ์„ธ")
>>> realtype_info
KiwoomOpenApiPlusRealType('0A', '์ฃผ์‹์‹œ์„ธ', 21, [10, 11, 12, 27, 28, 13, 14, 16, 17, 18, 25, 26, 29, 30, 31, 32, 311, 822, 567, 568, 732])

>>> fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("์ฃผ์‹์‹œ์„ธ")
>>> fid_list
[10, 11, 12, 27, 28, 13, 14, 16, 17, 18, 25, 26, 29, 30, 31, 32, 311, 822, 567, 568, 732]

>>> KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(10)
'ํ˜„์žฌ๊ฐ€'

>>> fid_names = KiwoomOpenApiPlusRealType.get_field_names_by_realtype_name("์ฃผ์‹์‹œ์„ธ")
>>> fid_names
['ํ˜„์žฌ๊ฐ€', '์ „์ผ๋Œ€๋น„', '๋“ฑ๋ฝ์œจ', '๋งค๋„ํ˜ธ๊ฐ€', '๋งค์ˆ˜ํ˜ธ๊ฐ€', '๋ˆ„์ ๊ฑฐ๋ž˜๋Ÿ‰', '๋ˆ„์ ๊ฑฐ๋ž˜๋Œ€๊ธˆ', '์‹œ๊ฐ€', '๊ณ ๊ฐ€', '์ €๊ฐ€', '์ „์ผ๋Œ€๋น„๊ธฐํ˜ธ', '๊ฑฐ๋ž˜๋Ÿ‰์ „์ผ๋Œ€๋น„', '๊ฑฐ๋ž˜๋Œ€๊ธˆ์ฆ๊ฐ', '์ „์ผ๊ฑฐ๋ž˜๋Ÿ‰๋Œ€๋น„์œจ', '๊ฑฐ๋ž˜ํšŒ์ „์œจ', '๊ฑฐ๋ž˜๋น„์šฉ', '์‹œ๊ฐ€์ด์•ก', '822', '567', '568', '732']

์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์š”์ฒญ (์‚ผ์„ฑ์ „์ž ์ฃผ์‹์‹œ์„ธ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์š”์ฒญ)

>>> code_list = ["005930"]
>>> fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("์ฃผ์‹์‹œ์„ธ")
>>> opt_type = "0"  # ๊ธฐ์กด ํ™”๋ฉด์— ์ถ”๊ฐ€๊ฐ€ ์•„๋‹ˆ๋ผ ์‹ ๊ทœ ์ƒ์„ฑ

>>> stream = entrypoint.GetRealDataForCodesAsStream(
...     code_list,
...     fid_list,
...     opt_type,
...     screen_no=None,  # ํ™”๋ฉด๋ฒˆํ˜ธ, 0000 ์„ ์ œ์™ธํ•œ 4์ž๋ฆฌ ์ˆซ์ž ์ž„์˜๋กœ ์ง€์ •, None ์˜ ๊ฒฝ์šฐ ๋‚ด๋ถ€์ ์œผ๋กœ ํ™”๋ฉด๋ฒˆํ˜ธ ์ž๋™ํ• ๋‹น
...     infer_fids=True,  # True ๋กœ ์„ค์ • ์‹œ ์ฃผ์–ด์ง„ fid_list ๋ฅผ ๊ณ ์ง‘ํ•˜์ง€ ๋ง๊ณ  ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ „๋‹ฌ๋ฐ›๋Š” ์‹ค์‹œ๊ฐ„๋ฐ์ดํ„ฐ ์ด๋ฆ„์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ฒŒ fid_list ๋ฅผ ์ถ”๋ก 
...     readable_names=True,  # True ๋กœ ์„ค์ • ์‹œ ๊ฐ fid ๋งˆ๋‹ค ์ˆซ์ž ๋Œ€์‹  ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฐ˜ํ™˜
...     fast_parse=False,  # True ๋กœ ์„ค์ • ์‹œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋‚ด์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ’ ์ฝ๊ธฐ ์‹œ GetCommRealData() ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋Œ€์‹ , ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋„˜์–ด์˜ค๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ํ™œ์šฉ, infer_fids ๊ฐ€ True ๋กœ ์„ค์ •๋œ ๊ฒฝ์šฐ๋งŒ ์œ ์˜๋ฏธํ•จ
... )

>>> for event in cancel_after(stream, 10):
...     if event.name == "OnReceiveRealData":
...         data = dict(zip(event.single_data.names, event.single_data.values))
...         if "ํ˜„์žฌ๊ฐ€" in data:
...             current_price = data["ํ˜„์žฌ๊ฐ€"]

์‚ฌ์šฉ ์ข…๋ฃŒ ํ›„ ์—”ํŠธ๋ฆฌํฌ์ธํŠธ ๊ฐ์ฒด ๋ฆฌ์†Œ์Šค ํ•ด์ œ (์—ฐ๊ฒฐ ํ•ด์ œ ๋ฐ ์„œ๋ฒ„ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ข…๋ฃŒ)

์ง์ ‘ close() ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ:

ํ˜น์€ ์ฒ˜์Œ๋ถ€ํ„ฐ ์ปจํ…์ŠคํŠธ ๋งค๋‹ˆ์ € ํ˜•ํƒœ๋กœ ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ:

Installation

๋Œ€ํ‘œ์ ์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด PyPI ๋ฅผ ํ†ตํ•ด์„œ ์„ค์น˜๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค:

$ pip install koapy

๋งŒ์•ฝ์— ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” poetry_ ๋ฅผ ํ™œ์šฉํ•ด ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

$ # Install poetry (here using pipx)
$ python -m pip install pipx
$ python -m pipx ensurepath
$ pipx install poetry

$ # Clone repository
$ git clone https://github.com/elbakramer/koapy.git
$ cd koapy/

$ # Install dependencies and hooks
$ poetry install
$ poetry run pre-commit install

์ด์™ธ์— ์ž์„ธํ•œ ์„ค์น˜๋ฐฉ๋ฒ•๊ณผ ๊ด€๋ จํ•ด์„œ๋Š” Installation ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

Usage

์„ค์น˜ ์ดํ›„ ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋Š” Usage ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

์ถ”๊ฐ€์ ์œผ๋กœ ์‚ฌ์šฉ๋ฒ•๊ณผ ๊ด€๋ จ๋œ ๋‹ค์–‘ํ•œ ์˜ˆ์‹œ๋“ค์€ examples ํด๋” ๋ฐ notebooks_ipynb ํด๋”์—์„œ๋„ ํ™•์ธ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ํ˜น์‹œ๋‚˜ notebooks_ipynb ํด๋”์˜ .ipynb ํŒŒ์ผ๋“ค์„ Github ์„ ํ†ตํ•ด์„œ ๋ณด๋Š”๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น ๋…ธํŠธ๋ถ ์ฃผ์†Œ๋ฅผ nbviewer ์— ์ž…๋ ฅํ•˜์—ฌ ํ™•์ธํ•ด ๋ณด์„ธ์š”.

ํ˜„์žฌ ์•ŒํŒŒ ๋‹จ๊ณ„์ด๊ธฐ ๋•Œ๋ฌธ์— ๋งŽ์€ ๊ธฐ๋Šฅ๋“ค์ด ์‹ค์ œ๋กœ ๋ฌธ์ œ์—†์ด ๋™์ž‘ํ•˜๋Š”์ง€ ์ถฉ๋ถ„ํžˆ ํ…Œ์ŠคํŠธ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ์— ์‹ค์ „ ํŠธ๋ ˆ์ด๋”ฉ์— ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์ž์ฒด์ ์œผ๋กœ ์ถฉ๋ถ„ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ๊ฑฐ์นœ ํ›„ ์‚ฌ์šฉํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ์œผ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ์†์‹ค์— ๋Œ€ํ•ด ์–ด๋– ํ•œ ์ฑ…์ž„๋„ ์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์•ŒํŒŒ ๋‹จ๊ณ„์—์„œ ๊ฐœ๋ฐœ์ด ์ง„ํ–‰๋˜๋ฉด์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ตฌ์กฐ๊ฐ€ ๊ณ„์† ๊ธ‰๊ฒฉํ•˜๊ฒŒ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฐธ๊ณ  ๋ฐ”๋ž๋‹ˆ๋‹ค.

Features

KOAPY ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉํ–ฅ์„ฑ์„ ๊ฐ€์ง€๊ณ  ๊ฐœ๋ฐœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

GUI ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๋งŒ์œผ๋กœ ์ œํ•œ๋˜์ง€ ์•Š๋Š” ๋‹ค์–‘ํ•œ ์‚ฌ์šฉ์„ฑ

์ผ๋ฐ˜์ ์œผ๋กœ ์ธํ„ฐ๋„ท ๋“ฑ์ง€์—์„œ ์ ‘ํ•˜๊ธฐ ์‰ฌ์šด ๊ด€๋ จ ์˜ˆ์‹œ๋“ค์„ ์ฒ˜์Œ์œผ๋กœ ๋”ฐ๋ผ๊ฐ€๋‹ค ๋ณด๋ฉด, ์ž๊ธฐ๋„ ๋ชจ๋ฅด๋Š” ์‚ฌ์ด์— Qt ๊ธฐ๋ฐ˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ•˜๋‚˜ ๋งŒ๋“ค๊ณ , ๋ฒ„ํŠผ์„ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•˜๊ณ , ์ดํ›„ ๋ชจ๋“  ๊ธฐ๋Šฅ๋“ค์„ ์ฃ„๋‹ค ํ•ด๋‹น ๋ฒ„ํŠผ์„ ํด๋ฆญ ์‹œ ์ž‘๋™ํ•˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ํ•˜๋‚˜์— ์‘ค์…” ๋„ฃ๊ณ  ์žˆ๋Š”.. ์ž์‹ ์„ ๋ฐœ๊ฒฌํ•˜๊ฒŒ ๋˜๋”๊ตฐ์š”.

์‚ฌ์‹ค ๊ธฐ๋ฐ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์• ์ดˆ์— OCX ํ˜•ํƒœ๋กœ์„œ ์ œ๊ณต๋˜๋Š” ๊ฒƒ๋„ ์žˆ๊ณ , ๋‹ค๋ฅธ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ด์œ ๋“ค๋กœ ์ธํ•ด ์ด์ฒ˜๋Ÿผ GUI ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ˜•ํƒœ๋กœ ๊ฐœ๋ฐœ์„ ํ•˜๋Š” ๊ฒƒ์ด ์ž์—ฐ์Šค๋Ÿฌ์šด ํ๋ฆ„์ด๊ณ  ์ ˆ๋Œ€ ์ž˜๋ชป๋˜์—ˆ๋‹ค๊ณ  ์ƒ๊ฐ๋˜์ง„ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹ค๋งŒ ์ด๋Ÿฌํ•œ GUI ํ™˜๊ฒฝ์ด ์ผ๋ฐ˜์ ์œผ๋กœ Python ์—์„œ REPL ํ˜น์€ Jupyter Notebook ๋“ฑ์„ ํ†ตํ•ด์„œ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•˜๊ฒŒ ๊ฒฐ๊ณผ ๊ฐ’๋“ค์„ ํ™•์ธํ•ด๊ฐ€๋ฉด์„œ ์กฐ๊ธˆ์”ฉ ๊ฐœ๋ฐœํ•ด ๋‚˜๊ฐ€๋˜ ๊ฒƒ๊ณผ๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ€์–ด์ง€๋ฉด์„œ ๊ฒฐ๋ก ์ ์œผ๋กœ ์ƒ์‚ฐ์„ฑ์ด ๋–จ์–ด์ง€๊ฒŒ ๋˜๋Š” ๊ฑด ์•„๋‹Œ๊ฐ€ ํ•˜๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๊ณ , ๊ทธ๋กœ ์ธํ•ด KOAPY ์˜ ๊ธฐ๋ณธ์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๊ธฐ๋ฐ˜์ด ๋˜๋Š” Qt ํ™˜๊ฒฝ์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘์ ์œผ๋กœ ๊ณ ๋ คํ•˜์ง„ ์•Š์œผ๋ฉด์„œ๋„ ๊ธฐ๋Šฅ์€ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ๋” ํ•˜๋Š” ๊ฒŒ ์ข‹๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ KOAPY ์˜ ๊ธฐ๋ณธ์ ์ธ ๋””์ž์ธ์€ ์šฐ์„  ์™ธ์ ์œผ๋กœ ๋ดค์„ ๋•Œ ์ด๊ฒŒ ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” Qt ๊ฐ™์€ ํ™˜๊ฒฝํ•˜์—์„œ ๋Œ์•„๊ฐ„๋‹ค๋Š” ๊ฒƒ์„ ๋ฐ”๋กœ ์•Œ์•„์ฑŒ ์ˆœ ์—†๊ฒŒ ๋” ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ๋“ค์„ ์ด์šฉํ•˜๋Š” ๋ฐ์— ์žˆ์–ด์„œ๋„ ๋ฒ„ํŠผ ํด๋ฆญ ๋“ฑ์˜ ์ด๋ฒคํŠธ์— ๊ธฐ๋ฐ˜ํ•œ ํ˜ธ์ถœ๋ณด๋‹จ ์ผ๋ฐ˜์ ์ธ ํ•จ์ˆ˜ ํ˜ธ์ถœ๊ณผ ๊ฐ™์€ ๋ช…๋ นํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ๋””์ž์ธ ํ•˜์˜€์œผ๋ฉฐ, ๋ฌธ์„œ์—์„œ๋„ ํ•ด๋‹น ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค๋“ค์„ ์ค‘์ ์ ์œผ๋กœ ๋จผ์ € ์†Œ๊ฐœํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก ์ ์œผ๋กœ PyQt5 ํ˜น์€ PySide2 ๋ฅผ ๊ธฐ๋ฐ˜ํ•œ GUI ํ™˜๊ฒฝ์— ์–ฝ๋งค์ผ ํ•„์š” ์—†์ด ์ผ๋ฐ˜์ ์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ฒ˜๋Ÿผ ๊ฐ€์ ธ๋‹ค ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์—ฌ์ „ํžˆ GUI ๊ธฐ๋ฐ˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์š”์†Œ๋“ค์„ ํ†ตํ•ด ์ง์ ‘ GUI ๋ฐฉํ–ฅ์œผ๋กœ ๊ฐœ๋ฐœ์„ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜ ํ˜ธ์ถœ๋“ฑ์˜ ๊ณผ์ •์—์„œ ์ผ๋ฐ˜์ ์ธ Python ์˜ ๊ด€์Šต์„ ํฌ๊ฒŒ ํ•ด์น˜์ง€ ์•Š๋Š” ๋งค๋„๋Ÿฌ์šด ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ

Qt ๋ฅผ ํ†ตํ•ด์„œ COM/OLE/OCX ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ ค๋ฉด dynamicCall_ ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๋‹น dynamicCall_ ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฉ”์„œ๋“œ์˜ ํ”„๋กœํ† ํƒ€์ž…์„ ๋ฌธ์ž์—ด ํ˜•ํƒœ ์ธ์ž๋กœ์„œ ์ž…๋ ฅํ•˜๋„๋ก ๋˜์–ด์žˆ๋Š”๋ฐ, ๋‹จ์ˆœํ•˜๊ฒŒ๋Š” ๋งค๋ฒˆ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ ์ž ํ•  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ๋ฉ”์„œ๋“œ์˜ ํ”„๋กœํ† ํƒ€์ž…์ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€๋ฅผ ๋ฌธ์„œ ๋“ฑ์„ ์ฐธ๊ณ ํ•˜๊ณ  ์ผ์ผ์ด ์ ์–ด ๋„ฃ์–ด์ค˜์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ๋‹ค์Œ์œผ๋กœ ๋ณด๋‹ค ๋‚˜์€ ๋ฐฉ์‹์œผ๋กœ๋Š” ์ด๋Ÿฌํ•œ ํ”„๋กœํ† ํƒ€์ž…์„ ๋ชจ๋“  ํ•จ์ˆ˜๋“ค์— ๋Œ€ํ•ด์„œ ํ™•์ธํ•ด์„œ ๊ฐ„๋‹จํ•œ ๋ž˜ํผ ํ•จ์ˆ˜๋“ค์„ ๋งŒ๋“ค์–ด๋‘๊ณ  ํ™œ์šฉํ•˜๋Š” ๊ฒŒ ์žˆ๊ฒ ์ฃ .

์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ์ด๋Ÿฐ ๋ฐฉ์‹๋“ค๋กœ๋„ ์ถฉ๋ถ„ํžˆ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ๋ฌด๋ฆฌ๊ฐ€ ์—†์œผ๋ฆฌ๋ผ ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค๋งŒ ๊ฐœ์ธ์ ์œผ๋กœ๋Š” ์œ„์™€ ๊ฐ™์€ ์ ‘๊ทผ ๋ฐฉ์‹์—์„œ ๋ช‡ ๊ฐ€์ง€ ์šฐ๋ ค๋˜๋Š” ์ ๋“ค์ด ์‹ ๊ฒฝ์ด ์“ฐ์˜€์Šต๋‹ˆ๋‹ค.

  • ํ”„๋กœํ† ํƒ€์ž…์„ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ๋ž˜ํผ ํ•จ์ˆ˜๋“ค์„ ๋งŒ๋“ค์–ด ๋„ฃ๋Š” ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ํœด๋จผ์—๋Ÿฌ
  • ๋ž˜ํผ ํ•จ์ˆ˜๋“ค์„ ๋งŒ๋“ค์–ด ๋†“์•˜๋”๋ผ๋„ ์ถ”ํ›„ ํ•จ์ˆ˜์˜ ๋ชฉ๋ก ํ˜น์€ ํŠน์ • ํ•จ์ˆ˜์˜ ํ”„๋กœํ† ํƒ€์ž…์—์„œ ๋ณ€๊ฒฝ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ ๋งค๋ฒˆ ์ง์ ‘์ ์ธ ๋Œ€์‘์ด ํ•„์š”ํ•จ

๋”ฐ๋ผ์„œ KOAPY ์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์ง€์› ํ•จ์ˆ˜ ๋ชฉ๋ก ๋ฐ ํ•จ์ˆ˜๋ณ„ ํ”„๋กœํ† ํƒ€์ž… ์ •๋ณด ํ™•์ธ, ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ๋“ค์„ ํ™œ์šฉํ•ด ํŠน์ • ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ณผ์ •๊นŒ์ง€๋ฅผ ์–ด๋–ป๊ฒŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ ์œผ๋กœ ๋Œ€์‘ํ•  ์ˆ˜ ์—†์„๊นŒ๋ฅผ ๊ณ ๋ฏผํ–ˆ๊ณ , ํ˜„์žฌ๋Š” OpenAPI+ OCX ์˜ TypeLib ์ •๋ณด๋ฅผ ์ฝ์–ด์™€ ๋ฉ”์„œ๋“œ๋“ค์„ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋„๋ก ๊ตฌํ˜„ํ•ด ์œ„์—์„œ ์šฐ๋ คํ–ˆ๋˜ ์ ๋“ค์„ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

์ตœ์ข…์ ์œผ๋ก  ์ปจํŠธ๋กค ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ ๋งค๋‰ด์–ผ์˜ ๋ช…์„ธ์— ์ ํ˜€์žˆ๋Š” ํ˜•ํƒœ ๊ทธ๋Œ€๋กœ Python ํ•จ์ˆ˜์˜€๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์ดํ›„๋Š” KOAPY ๊ฐ€ ์œ ์—ฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋งค๋ฒˆ ๋ช…์„ธ์— ๋งž๊ฒŒ dynamicCall_ ํ•จ์ˆ˜์˜ ์ธ์ž๋ฅผ ์ ์–ด ๋„ฃ๊ฑฐ๋‚˜, ๋ชจ๋“  ์กด์žฌํ•˜๋Š” ํ•จ์ˆ˜์— ๋Œ€ํ•ด ๋ฏธ๋ฆฌ ๋ž˜ํผ ํ•จ์ˆ˜๋ฅผ ์† ์•„ํ”„๊ฒŒ ๋งŒ๋“ค์–ด๋†“์„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฐ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ด€๋ จ ๋ณต์žกํ•˜์ง€ ์•Š์€ ์ธํ„ฐํŽ˜์ด์Šค ์ œ๊ณต

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ํŠนํžˆ OpenAPI+ ๋ฐ KOAPY ์˜ ๊ฒฝ์šฐ๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ณ ๋ฏผํ•ด ๋ณผ ๋งŒํ•œ ๋ถ€๋ถ„๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์—ฌ๋Ÿฌ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต ๊ฒฐ๊ณผ๋“ค์„ ์ด๋ฒคํŠธ ํƒ€์ž…๋ณ„ ํ•˜๋‚˜์”ฉ์˜ ํ†ต๋กœ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋“ค ๊ฐ„์˜ ๊ตํ†ต์ •๋ฆฌ๋ถ€ํ„ฐ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋‚ด์—์„œ OpenAPI+ ๊ฐ€ ๊ธฐ๋Œ€ํ•˜๋Š” ํ˜น์€ ๊ฐ€์ด๋“œํ•˜๋Š” ๋ฐฉ์‹์— ๋งž์ถฐ์„œ ์ฒ˜๋ฆฌํ•ด ์ฃผ์–ด์•ผ ํ•˜๋Š” ํŠน์ • ๋‹จ๊ณ„ ํ˜น์€ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์กด์žฌํ•˜๋ฉฐ ์ด๋ฅผ ์ ์ ˆํžˆ ๋Œ€์‘ํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ฝœ๋ฐฑ ํ•จ์ˆ˜์—์„œ ๋ฐ›์€ ๊ฒฐ๊ณผ๋ฅผ ์ตœ์ข…์ ์œผ๋กœ ํ•ด๋‹น ๊ฒฐ๊ณผ๊ฐ€ ํ•„์š”ํ•œ ๊ณณ์œผ๋กœ (์ผ๋ฐ˜์ ์œผ๋ก  ์š”์ฒญํ•œ ๋Œ€์ƒ์—๊ฒŒ๋กœ) ์ž˜ ์ „๋‹ฌํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

KOAPY ์—์„œ๋Š” ์œ„์˜ ๋ฌธ์ œ๋“ค์„ ๋‚˜๋ฆ„์˜ ๋ฐฉ์‹๋Œ€๋กœ ๊ณ ๋ฏผํ•˜์˜€๊ณ  ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•˜์—ฌ ๋” ์‰ฝ๊ณ  ๋‚˜์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌ์ฒด์ ์œผ๋กœ ์˜ˆ๋ฅผ ํ•˜๋‚˜ ๋“ค์ž๋ฉด, ์ผ๋ฐ˜์ ์ธ ์š”์ฒญ-์‘๋‹ต ๊ณผ์ •์—์„œ ๋‚ด๋ถ€์ ์œผ๋กœ gRPC ํด๋ผ์ด์–ธํŠธ-์„œ๋ฒ„ ๊ด€๊ณ„๋ฅผ ๋งŒ๋“ค์–ด ์š”์ฒญ์ž๊ฐ€ gRPC ๋ฅผ ํ†ตํ•ด ํŠน์ • ์š”์ฒญ์„ ์ „๋‹ฌํ•˜๋ฉด, ์ดํ›„ gRPC ์„œ๋ฒ„์—์„œ๋Š” ํ•ด๋‹น ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต๋“ค๋งŒ ์ถ”๋ ค์„œ ๊ฒฐ๊ณผ๋ฅผ ์š”์ฒญ์ž์ธก์— ์ŠคํŠธ๋ฆผ ํ˜•ํƒœ๋กœ ์ „๋‹ฌํ•˜๋„๋ก ๋””์ž์ธ๋˜์–ด ์žˆ๋Š”๋ฐ์š”. ์—ฌ๊ธฐ์„œ ๊ตํ†ต์ •๋ฆฌ ๋ฐ ๊ฒฐ๊ณผ ์ „๋‹ฌ ๋ฌธ์ œ๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ•ด๊ฒฐ๋˜๋ฉฐ ๋ถ€์ˆ˜์ ์œผ๋กœ ์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ๋Š” ์ง์ ‘ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ๋‹ค๋ฃจ๊ธฐ๋ณด๋‹ค๋Š” ๊ฐ„์ ‘์ ์œผ๋กœ ์ŠคํŠธ๋ฆผ์„ (for ๋ฌธ์„ ํ™œ์šฉํ•˜์—ฌ) ๋‹ค๋ฃธ์œผ๋กœ์จ ๋” ์‰ฝ๊ฒŒ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

PySide2 ๋ฅผ ํ†ตํ•œ ์ง์ ‘์ ์ธ ๋ฐฉ์‹:

KOAPY ๋ฐฉ์‹:

๊ฒฐ๋ก ์ ์œผ๋กœ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฐ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ์ต์ˆ™ํ•˜์ง€ ์•Š๋”๋ผ๋„ ๊ทธ๋ณด๋‹ค ๋น„๊ต์  ์‰ฌ์šด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ๊ด€๋ จ ๊ธฐ๋Šฅ๋“ค์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋” ๋‚˜์•„๊ฐ€์„œ๋Š” ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ๋ถ€ํ„ฐ TR/์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ, ๊ทธ๋ฆฌ๊ณ  ์ฃผ๋ฌธ์ฒ˜๋ฆฌ๊นŒ์ง€ ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋กœ์ง์„ ๊ตฌํ˜„ํ•ด ์ œ๊ณตํ•ด ์‚ฌ์šฉ์ž๋“ค์ด ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ํ•„์š”ํ•œ ๊ธฐ๋Šฅ ์ค‘ ์ฃผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ๋“ค์— ์‰ฝ๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ์ผ๋ฐ˜์ ์ธ ์‹œ๋‚˜๋ฆฌ์˜ค๋“ค์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ๊ธฐ๋ณธ ๊ตฌํ˜„์ฒด๋“ค์„ ์ œ๊ณต

KOAPY ์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ๋“ค์— ๋Œ€ํ•ด์„œ ์‚ฌ์šฉ์ž๋“ค์ด ์‰ฝ๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก, ์˜ˆ๋ฅผ ๋“ค์–ด ์ฃผ์‹ ๊ธฐ๋ณธ์ •๋ณด ์š”์ฒญ๋ถ€ํ„ฐ ์ผ๋ด‰/๋ถ„๋ด‰ ๋“ฑ ์‹œ์„ธ ๋ฐ์ดํ„ฐ ํ™•์ธ ๊ทธ๋ฆฌ๊ณ  ์˜ˆ์ˆ˜๊ธˆ/์ž”๊ณ  ํ™•์ธ ๋“ฑ๋“ฑ์— ๋Œ€ํ•ด ๋ฏธ๋ฆฌ ๊ตฌํ˜„๋œ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด ์ค‘์— ํ•จ์ˆ˜ ํ˜ธ์ถœ ๊ฒฐ๊ณผ ์ค‘ ํ…Œ์ด๋ธ”์„ฑ ์ •๋ณด๋“ค์€ pandas.DataFrame_ ํƒ€์ž…์œผ๋กœ ์ œ๊ณตํ•ด ์ดํ›„ ๋ถ„์„ ๋ฐ ์ฒ˜๋ฆฌ๊ฐ€ ์œ ์šฉํ•˜๊ฒŒ๋” ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ๊ณผ์ •์—์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐ–์„ ๋“œ๋‚˜๋“ค ํ•„์š”๊ฐ€ ์—†๋„๋ก ์ž์ฃผ ํ™•์ธ์ด ํ•„์š”ํ•œ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฉ”ํƒ€ ์ •๋ณด๋“ค์„ ํ•จ๊ป˜ ์ œ๊ณต

์ผ๋ฐ˜์ ์œผ๋กœ ์ธํ„ฐ๋„ท ๋“ฑ์ง€์—์„œ ์ ‘ํ•˜๊ธฐ ์‰ฌ์šด ๊ด€๋ จ ๋Œ€๋ถ€๋ถ„ ์˜ˆ์‹œ๋“ค์€ ์‚ฌ์šฉ์ž๊ฐ€ OpenAPI+ ์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฉ”ํƒ€์ •๋ณด๋“ค์„ ์ด๋ฏธ ๋‹ค ์•Œ๊ณ  ์žˆ๋‹ค๋Š” ๊ฑธ ๊ฐ€์ •ํ•˜๊ณ , ์•„๋‹ˆ๋ฉด ์ ์–ด๋„ ์™ธ๋ถ€ ์ฐธ๊ณ ์ž๋ฃŒ๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์„ ๊ฐ€์ •ํ•˜๊ณ  ์ž‘์„ฑ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด TR ์˜ ์ž…๋ ฅ๊ณผ ์ถœ๋ ฅ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ, ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ณ„ FID ๋ชฉ๋ก, ์—๋Ÿฌ์ฝ”๋“œ์— ๋Œ€ํ•œ ์„ค๋ช…๋ฌธ ๋“ฑ์ด ์ด๋Ÿฌํ•œ ๋ฉ”ํƒ€์ •๋ณด๋“ค์— ํ•ด๋‹น๋˜๋Š”๋ฐ์š”. ์•ž์„œ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋ฐฉ์‹์—์„œ์˜ ์ด์Šˆ์™€ ๋น„์Šทํ•˜๊ฒŒ, ์ด๋Ÿฌํ•œ ์ •๋ณด๋“ค์„ ๋งค๋ฒˆ ์ฐธ๊ณ  ์ž๋ฃŒ๋ฅผ ํ™•์ธํ•˜๊ณ  ๊ทธ์— ๋งž์ถฐ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐฉ์‹์—๋Š” ์–ด๋Š ์ •๋„ ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ KOAPY ์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์ •๋ณด๋“ค์„ ๊ฐœ๋ฐœํ•˜๋Š” ๊ณผ์ •์—์„œ ์–ธ์–ด ๋‚ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ๋ฐ”๋กœ ์กฐํšŒ ๋ฐ ํ™œ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ํฌํ•จ์‹œ์ผœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์ผ์ฐจ์ ์œผ๋กœ ์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ๋Š” ๋งค๋ฒˆ ๋งค๋‰ด์–ผ ์ด๋‚˜ KOAStudio ๋ฅผ ์—ด์–ด์„œ ์ฐธ๊ณ ํ•˜๊ณ  ์ดํ›„ ์ผ์ผ์ด ํ•˜๋‚˜์”ฉ ํ•˜๋“œ์ฝ”๋”ฉํ•  ํ•„์š”๊ฐ€ ์—†์–ด์กŒ์Šต๋‹ˆ๋‹ค.

๋ง๋ถ™์—ฌ์„œ TR ๊ด€๋ จ ์ •๋ณด๋‚˜ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ๊ด€๋ จ ์ •๋ณด๋“ค์€ OpenAPI+ ๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๊ฒฝ๋กœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐธ๊ณ ํ•ด ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋„๋ก ๋˜์–ด์žˆ๋Š”๋ฐ์š”. ์ด๋กœ ์ธํ•ด ์ง์ ‘ ํ•˜๋“œ์ฝ”๋”ฉ ๋“ฑ์„ ํ–ˆ์„ ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ด์Šˆ ์—†์ด, ๋งค๋ฒˆ ์—…๋ฐ์ดํŠธ ์‹œ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์ด ๋ฐ”๋กœ๋ฐ”๋กœ ์ ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์ด์  ๋˜ํ•œ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ˜ธํ™˜์„ฑ์œผ๋กœ ์ธํ•ด ํŠน์ • ํ™˜๊ฒฝ์ด ๊ฐ•์ œ๋˜๋Š” ๊ฒƒ์„ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋„๋ก ์‹œ์Šคํ…œ ๊ตฌ์„ฑ

ํ‚ค์›€์ฆ๊ถŒ์˜ OpenAPI+ ๋Š” 32bit ํ™˜๊ฒฝ๋งŒ ์ œ๊ณตํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ชฝ๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ 32bit ๊ธฐ๋ฐ˜์ด ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” Python ์„ 32bit ๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์กฐ๊ฑด์ด ๋ถ™๊ฒŒ ๋˜๋Š” ๊ฒƒ์ธ๋ฐ์š”. ๋ช‡๋ช‡ ์™ธ๋ถ€ ์„œ๋“œํŒŒํ‹ฐ๋“ค์—์„œ๋Š” ๋” ์ด์ƒ 32bit ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋„ ๋งŽ์•„ ๋‹ค์–‘ํ•œ ์„œ๋“œํŒŒํ‹ฐ ๊ธฐ๋Šฅ๋“ค๊ณผ ์ ‘๋ชฉ์‹œํ‚ค๊ธฐ์—๋Š” 32bit ์ œ์•ฝ์ด ๋ฒˆ๊ฑฐ๋กœ์šด ์ ์ด ๋งŽ์Šต๋‹ˆ๋‹ค.

KOAPY ์—์„œ๋Š” ์ด๋ฅผ ํ•ด์†Œํ•˜๊ธฐ ์œ„ํ•ด gRPC ์„œ๋ฒ„-ํด๋ผ์ด์–ธํŠธ ํ˜•ํƒœ์˜ ๊ตฌ์„ฑ์„ ์žก์•„ ์„œ๋ฒ„์—์„œ๋Š” 32bit ๊ธฐ๋ฐ˜์œผ๋กœ OpenAPI+ ์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ๋งŒ ์ œ๊ณตํ•˜๋„๋ก ํ•˜๊ณ , ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ์ด๋Ÿฐ 32bit ์ œ์•ฝ ์—†์ด ๊ฒฐ๊ณผ๋“ค์„ ๋ฐ›์•„์„œ ์ดํ›„ ์—ฌ๋Ÿฌ ์„œ๋“œํŒŒํ‹ฐ ๊ธฐ๋Šฅ๋“ค๊ณผ ํ•จ๊ป˜ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

์•ž์—์„œ๋Š” ์ฃผ๋กœ 32bit ์ œ์•ฝ์„ ๊ฐ€์ง€๊ณ  ์ด์•ผ๊ธฐํ–ˆ์ง€๋งŒ ๋” ๋‚˜์•„๊ฐ€์„œ๋Š” gRPC ์˜ ๋งŽ์€ ์–ธ์–ด๋“ค์— ๋Œ€ํ•œ ํ™•์žฅ์„ฑ์„ ํ™œ์šฉํ•˜์—ฌ Python ์ด์™ธ์— gRPC ์—์„œ ์ง€์›ํ•˜๋Š” ๋‹ค๋ฅธ ์–ธ์–ด๋“ค๋กœ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ž‘์„ฑํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ๋„ ํ™•์žฅ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ Python ์—์„œ Qt ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” PyQt5 ํ˜น์€ PySide2 ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”๋ฐ์š”. KOAPY ์—์„œ๋Š” ๋ผ์ด์„ ์Šค ๋“ฑ์„ ๊ณ ๋ คํ•ด์„œ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ PySide2 ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋˜์–ด์žˆ์ง€๋งŒ, ์‚ฌ์šฉ์ž์˜ ํ•„์š”์„ฑ์— ๋”ฐ๋ผ PySide2 ๋Œ€์‹  PyQt5 ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค ํ•  ๋•Œ ์‰ฝ๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋„๋ก qtpy_ ๋ฅผ ํ†ตํ•ด์„œ ์ง€์›ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํ‚ค์›€์ฆ๊ถŒ์˜ OpenAPI+ ๊ธฐ๋Šฅ ์ž์ฒด ์ด์™ธ์— ๋ถ€์ˆ˜์ ์œผ๋กœ ํ•„์š”ํ• ๋งŒํ•œ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์ถ”๊ฐ€๋กœ ์ œ๊ณต

KOAPY ๋Š” ํ‚ค์›€์ฆ๊ถŒ์˜ OpenAPI+ ํ•ต์‹ฌ ๊ธฐ๋Šฅ ์ด์™ธ์— ์ „์ฒด์ ์ธ ๊ฐœ๋ฐœ ๋ฐ ํ™œ์šฉ์— ํ•„์š”ํ•œ ๋‹ค์–‘ํ•œ ๋ถ€๊ฐ€๊ธฐ๋Šฅ๋“ค์„ ์ถ”๊ฐ€๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • TR ํ˜ธ์ถœ ์‹œ ํ˜ธ์ถœ ํšŸ์ˆ˜ ์ œํ•œ ํšŒํ”ผ
  • KRX ๊ฑฐ๋ž˜์†Œ ํœด์žฅ์ผ ํ™•์ธ (exchange_calendars_ API ํ™œ์šฉ)
  • ์•Œ๋žŒ ๋ฐ ๋ฉ”์‹œ์ง€ ๊ธฐ๋Šฅ (discord.py_ API ํ™œ์šฉ)

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ด€๋ จ ๊ธฐ๋Šฅ๋“ค์„ ์ถ”๊ฐ€์ ์ธ ์ฝ”๋“œ ๊ตฌํ˜„์—†์ด ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•ด๋ณผ ์ˆ˜ ์žˆ๋„๋ก (+ ๊ฐœ๋… ์ฆ๋ช… ๋ชฉ์ ์œผ๋กœ์„œ) CLI ์ œ๊ณต

๊ตณ์ด Python ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๋”๋ผ๋„ ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ๋“ค์„ ํ™œ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ์—ฌ๋Ÿฌ ์ปค๋งจ๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” CLI ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

CLI ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋งˆ์ผ“๋ณ„ ์ฝ”๋“œ ๋ชฉ๋ก ํ™•์ธ, ์ฃผ์‹ ๊ธฐ๋ณธ ์ •๋ณด ํ™•์ธ, ์ผ๋ด‰/๋ถ„๋ด‰ ๋ฐ์ดํ„ฐ ํ™•์ธ ๋ฐ ์ €์žฅ, ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ๊ตฌ๋… ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์ฝ”๋“œ ๊ตฌํ˜„ ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

$ koapy get stockcode --market=0
$ koapy get stockinfo --code=005930
$ koapy get daily --code=005930 --output=005930.xlsx
$ koapy watch --code=005930 --realtype="์ฃผ์‹์‹œ์„ธ"

์„œ๋ฒ„๋„ CLI ์ปค๋งจ๋“œ๋กœ ์‰ฝ๊ฒŒ ๋„์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

$ koapy serve

Licensing

KOAPY ๋Š” ๋‹ค์ค‘ ๋ผ์ด์„ ์Šค ๋ฐฉ์‹์œผ๋กœ ๋ฐฐํฌ๋˜๋ฉฐ, ์‚ฌ์šฉ์ž๋Š” ์ž์‹ ์˜ ์˜๋„ ๋ฐ ์‚ฌ์šฉ ๋ฐฉ์‹์— ๋”ฐ๋ผ ์•„๋ž˜ ๋ผ์ด์„ ์Šค ์˜ต์…˜๋“ค ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ผ์ด์„ ์Šค ์„ ํƒ๊ณผ ๊ด€๋ จํ•˜์—ฌ ์ถ”์ฒœํ•˜๋Š” ๊ฐ€์ด๋“œ๋ผ์ธ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

MIT License

  • ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋งž์Šต๋‹ˆ๋‹ค.
  • ์งง๊ณ  ๋‹จ์ˆœํ•œ ๋ผ์ด์„ ์Šค๋ฅผ ์„ ํ˜ธํ•˜์‹œ๋ฉด ํ•ด๋‹น ๋ผ์ด์„ ์Šค๋ฅผ ์„ ํƒํ•˜์„ธ์š”.

Apache License 2.0

  • MIT ๋ผ์ด์„ ์Šค์™€ ํฐ ์ฐจ์ด๋Š” ์—†์ง€๋งŒ, ํŠนํ—ˆ์™€ ๊ด€๋ จํ•ด์„œ ๋ช…์‹œ์ ์ธ ํ—ˆ๊ฐ€์กฐํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ถ”ํ›„ ํŠนํ—ˆ๊ถŒ ์นจํ•ด ์†Œ์†ก์ด ์šฐ๋ ค๋˜๋Š” ๊ฒฝ์šฐ MIT ๋ผ์ด์„ ์Šค ๋Œ€์‹ ์— ์„ ํƒํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

GNU General Public License v3.0 or later

  • FSF/GPL ์ด ์ถ”๊ตฌํ•˜๋Š” Copyleft ์˜ ๊ฐ€์น˜๋ฅผ ๋”ฐ๋ฅด์‹ ๋‹ค๋ฉด ์„ ํƒ ๊ฐ€๋Šฅํ•œ ์˜ต์…˜์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.
  • ์ด์™ธ์— backtrader ๊ด€๋ จ ๊ธฐ๋Šฅ๋“ค์„ ํ™œ์šฉํ•˜์‹œ๋Š” ๊ฒฝ์šฐ, KOAPY ๋Š” ๋ฐ˜๋“œ์‹œ GPLv3+ ๋กœ๋งŒ ๋ฐฐํฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ตฌ์ฒด์ ์œผ๋กœ koapy.backtrader_ ๋ชจ๋“ˆ ํ•˜์œ„์˜ ๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด GPLv3+ ๋ฐฐํฌ ์กฐ๊ฑด์— ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค.
  • ์ด๊ฒƒ์€ backtrader ๊ฐ€ GPLv3+ ๋กœ ๋ฐฐํฌ๋˜๊ณ  ์žˆ์œผ๋ฉฐ, ํ•ด๋‹น ๋ผ์ด์„ ์Šค์˜ ์š”๊ตฌ์‚ฌํ•ญ์— ๋”ฐ๋ผ ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ์†Œํ”„ํŠธ์›จ์–ด ๋˜ํ•œ GPLv3+ ๋กœ ๋ฐฐํฌ๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ฐ ๋ผ์ด์„ ์Šค์˜ ํ—ˆ๊ฐ€ ๋ฐ ์š”๊ตฌ์‚ฌํ•ญ๊ณผ ๊ด€๋ จํ•ด์„œ ์‰ฝ๊ฒŒ ์ •๋ฆฌ๋œ ๋‚ด์šฉ์€ tl;drLegal ์—์„œ ์ฐธ๊ณ ํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋งŒ ์œ„์˜ ๋‚ด์šฉ์ด ๋ฒ•๋ฅ ์  ์กฐ์–ธ์€ ์•„๋‹Œ ์  ์ฐธ๊ณ  ๋ฐ”๋ž๋‹ˆ๋‹ค.

Credits

์ด ํŒจํ‚ค์ง€๋Š” Cookiecutter ์™€ elbakramer/cookiecutter-poetry ํ”„๋กœ์ ํŠธ ํƒฌํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.