-
Notifications
You must be signed in to change notification settings - Fork 55
Home
ํ๊ตญํฌ์์ฆ๊ถ์ ํธ๋ ์ด๋ฉ OPEN API ์๋น์ค๋ฅผ ํ์ด์ฌ ํ๊ฒฝ์์ ์ฌ์ฉํ ์ ์๋๋ก ๋ง๋ ๊ฐ๋ ฅํ ์ปค๋ฎค๋ํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
2.0.0 ๋ฒ์ ์ด์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ฌ๊ธฐ, ๋ฌธ์๋ 1, 2, 3์์ ํ์ธํ ์ ์์ต๋๋ค.
๐ ๋ชจ๋ ๊ฐ์ฒด์ ๋ํ Type hint
- ๋ชจ๋ ํจ์์ ํด๋์ค์ ๋ํด ์ถ์ํ ๋ฐ Typing์ ์ ์ฉํ์ฌ, ํ์ด์ฌ์ ๋์ ํ์ดํ์ ๋ณด์ํฉ๋๋ค.
- IDE์ ์๋์์ฑ์ 100% ํ์ฉํ ์ ์์ผ๋ฉฐ, ๊ณต์ ๋ฌธ์ ์์ด ์ ํํ๊ณ ๋ฒ๊ทธ ์๋ ๊ฐ๋ฐ์ด ๊ฐ๋ฅํฉ๋๋ค.
๐ ๋ณต๊ตฌ ๊ฐ๋ฅํ ์น์์ผ ํด๋ผ์ด์ธํธ
- ์ค์๊ฐ ์์ธ, ํธ๊ฐ, ์ฒด๊ฒฐ ๋ฑ์ ์ค์๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ ๊ณผ์ ์์ ๋คํธ์ํฌ ๋ฌธ์ ๋ฑ์ผ๋ก ์ธํด ์ฐ๊ฒฐ์ด ๋๊ฒผ์ ๋, ์๋ฒฝํ ๋ณต๊ตฌํ ์ ์๋๋ก ๋ง๋ค์ด์ก์ต๋๋ค.
- ์ฌ์ฐ๊ฒฐ ์ด์ ์ ๋ฑ๋ก๋ ์กฐํ๋ ์๋์ผ๋ก ๋ค์ ๋ฑ๋กํ์ฌ ์ ์ค์ ๋ฐฉ์งํฉ๋๋ค.
- ํ๊ตญํฌ์์ฆ๊ถ์ ์น์์ผ ์กฐํ ์์คํ ์ ํ์ด์ฌ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ์์คํ ๊ณผ ์๋ฒฝํ ํตํฉํ์ฌ, GC์ ์ํด ์ด๋ฒคํธ ๊ตฌ๋ ์ด ๊ด๋ฆฌ๋ฉ๋๋ค.
๐๏ธ ํ์ค ์์ด ๋ค์ด๋ฐ
- ํ๊ตญํฌ์์ฆ๊ถ์ API์ ๊ฒฝ์ฐ, ํ๊ธ ๋ฐ์์ด๋ ๋นํ์ค ์ฝ์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
- ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ชจ๋ ๊ฐ์ฒด์ ๋ํด ํ์ค ์์ด ๋ค์ด๋ฐ์ ์ ์ฉํ์ฌ, ์ดํดํ๊ธฐ ์ฝ๋๋ก ๋ง๋ค์์ต๋๋ค.
OpenAPI ์๋น์ค ์ ์ฒญ ๋ฐฉ๋ฒ
- ํ๊ตญํฌ์์ฆ๊ถ ๊ณ์ข์ ์์ด๋๊ฐ ํ์ํฉ๋๋ค. KIS ํธ๋ ์ด๋ฉ ์๋น์ค๋ KIS Developers ์๋น์ค๋ฅผ ํตํด ์ ์ฒญ ํ ์ ์์ต๋๋ค.
- ์๋น์ค๋ฅผ ์ ์ฒญ์ด ์๋ฃ๋๋ฉด, ์๋์ ๊ฐ์ด ์ฑ ํค๋ฅผ ๋ฐ๊ธ ๋ฐ์ ์ ์์ต๋๋ค.
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ์ด์ฌ 3.11์ ๊ธฐ์ค์ผ๋ก ์์ฑ๋์์ต๋๋ค.
pip install python-kis
์ฌ์ฉ๋ ๋ชจ๋ ๋ณด๊ธฐ
requests>=2.32.3
websocket-client>=1.8.0
cryptography>=43.0.0
colorlog>=6.8.2
-
์ํฌ๋ฆฟ ํค๋ฅผ ํ์ผ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ (๊ถ์ฅ)
๋จผ์ ์ํฌ๋ฆฟ ํค๋ฅผ ํ์ผ๋ก ์ ์ฅํฉ๋๋ค.
from pykis import KisAuth auth = KisAuth( # HTS ๋ก๊ทธ์ธ ID ์) soju06 id="YOUR_HTS_ID", # ์ฑ ํค ์) Pa0knAM6JLAjIa93Miajz7ykJIXXXXXXXXXX appkey="YOUR_APP_KEY", # ์ฑ ์ํฌ๋ฆฟ ํค ์) V9J3YGPE5q2ZRG5EgqnLHn7XqbJjzwXcNpvY . . . secretkey="YOUR_APP_SECRET", # ์ฑ ํค์ ์ฐ๊ฒฐ๋ ๊ณ์ข๋ฒํธ ์) 00000000-01 account="00000000-01", # ๋ชจ์ํฌ์ ์ฌ๋ถ virtual=False, ) # ์์ ํ ๊ฒฝ๋ก์ ์ํฌ๋ฆฟ ํค๋ฅผ ํ์ผ๋ก ์ ์ฅํฉ๋๋ค. auth.save("secret.json")
๊ทธ ํ, ์ ์ฅ๋ ์ํฌ๋ฆฟ ํค๋ฅผ ์ฌ์ฉํ์ฌ PyKis ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.
from pykis import PyKis, KisAuth # ์ค์ ํฌ์์ฉ PyKis ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค. kis = PyKis("secret.json", keep_token=True) kis = PyKis(KisAuth.load("secret.json"), keep_token=True) # ๋ชจ์ํฌ์์ฉ PyKis ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค. kis = PyKis("secret.json", "virtual_secret.json", keep_token=True) kis = PyKis(KisAuth.load("secret.json"), KisAuth.load("virtual_secret.json"), keep_token=True)
-
์ํฌ๋ฆฟ ํค๋ฅผ ์ง์ ์ ๋ ฅํ๋ ๋ฐฉ๋ฒ
from pykis import PyKis # ์ค์ ํฌ์์ฉ ํ๊ตญํฌ์์ฆ๊ถ API๋ฅผ ์์ฑํฉ๋๋ค. kis = PyKis( id="soju06", # HTS ๋ก๊ทธ์ธ ID account="00000000-01", # ๊ณ์ข๋ฒํธ appkey="PSED321z...", # AppKey 36์๋ฆฌ secretkey="RR0sFMVB...", # SecretKey 180์๋ฆฌ keep_token=True, # API ์ ์ ํ ํฐ ์๋ ์ ์ฅ ) # ๋ชจ์ํฌ์์ฉ ํ๊ตญํฌ์์ฆ๊ถ API๋ฅผ ์์ฑํฉ๋๋ค. kis = PyKis( id="soju06", # HTS ๋ก๊ทธ์ธ ID account="00000000-01", # ๋ชจ์ํฌ์ ๊ณ์ข๋ฒํธ appkey="PSED321z...", # ์ค์ ํฌ์ AppKey 36์๋ฆฌ secretkey="RR0sFMVB...", # ์ค์ ํฌ์ SecretKey 180์๋ฆฌ virtual_id="soju06", # ๋ชจ์ํฌ์ HTS ๋ก๊ทธ์ธ ID virtual_appkey="PSED321z...", # ๋ชจ์ํฌ์ AppKey 36์๋ฆฌ virtual_secretkey="RR0sFMVB...", # ๋ชจ์ํฌ์ SecretKey 180์๋ฆฌ keep_token=True, # API ์ ์ ํ ํฐ ์๋ ์ ์ฅ )
stock.quote()
ํจ์๋ฅผ ์ด์ฉํ์ฌ ๊ตญ๋ด์ฃผ์ ๋ฐ ํด์ธ์ฃผ์์ ์์ธ๋ฅผ ์กฐํํ ์ ์์ต๋๋ค.
from pykis import KisQuote
# ์๋น๋์์ ์ํ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
stock = kis.stock("NVDA")
quote: KisQuote = stock.quote()
quote: KisQuote = stock.quote(extended=True) # ์ฃผ๊ฐ๊ฑฐ๋ ์์ธ
# PyKis์ ๋ชจ๋ ๊ฐ์ฒด๋ repr์ ํตํด ์ฃผ์ ๋ด์ฉ์ ํ์ธํ ์ ์์ต๋๋ค.
# ๋ฐ์ดํฐ๋ฅผ ํ์ธํ๋ ์ฉ๋์ด๋ฏ๋ก ์ค์ ํ๋กํผํฐ ํ์
๊ณผ ๋ค๋ฅผ ์ ์์ต๋๋ค.
print(quote)
KisForeignQuote(
symbol='NVDA',
market='NASDAQ',
name='์๋น๋์',
sector_name='๋ฐ๋์ฒด ๋ฐ ๋ฐ๋์ฒด์ฅ๋น',
volume=1506310,
amount=160791125,
market_cap=2593332000000,
indicator=KisForeignIndicator(
eps=1.71,
bps=2,
per=63.88,
pbr=54.65,
week52_high=140.76,
week52_low=39.2215,
week52_high_date='2024-06-20',
week52_low_date='2023-10-31'
),
open=109.21,
high=109.38,
low=104.37,
close=105.42,
change=-3.79,
unit=1,
tick=0.01,
risk='none',
halt=False,
overbought=False
)
account.balance()
ํจ์๋ฅผ ์ด์ฉํ์ฌ ์์๊ธ ๋ฐ ๋ณด์ ์ข
๋ชฉ์ ์กฐํํ ์ ์์ต๋๋ค.
from pykis import KisBalance
# ์ฃผ ๊ณ์ข ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
account = kis.account()
balance: KisBalance = account.balance()
print(repr(balance)) # repr์ ํตํด ๊ฐ์ฒด์ ์ฃผ์ ๋ด์ฉ์ ํ์ธํ ์ ์์ต๋๋ค.
KisIntegrationBalance(
account_number=KisAccountNumber('50113500-01'),
deposits={
'KRW': KisDomesticDeposit(account_number=KisAccountNumber('50113500-01'), currency='KRW', amount=2447692, exchange_rate=1),
'USD': KisForeignPresentDeposit(account_number=KisAccountNumber('50113500-01'), currency='USD', amount=0, exchange_rate=1384.6),
},
stocks=[
KisDomesticBalanceStock(account_number=KisAccountNumber('50113500-01'), market='KRX', symbol='000660', qty=14, price=192600, amount=2696400, profit=22900, profit_rate=0.856555077613615111277351786),
KisDomesticBalanceStock(account_number=KisAccountNumber('50113500-01'), market='KRX', symbol='039200', qty=118, price=39600, amount=4672800, profit=-199500, profit_rate=-4.094575457176282248630010467)
],
purchase_amount=7545800,
current_amount=7369200,
profit=-176600,
profit_rate=-2.340374778022211031302181346
)
stock.order()
, stock.buy()
, stock.sell()
, stock.modify()
, stock.cancel()
ํจ์๋ฅผ ์ด์ฉํ์ฌ ๋งค์/๋งค๋ ์ฃผ๋ฌธ ๋ฐ ์ ์ /์ทจ์๋ฅผ ํ ์ ์์ต๋๋ค.
from pykis import KisOrder
# SKํ์ด๋์ค 1์ฃผ ์์ฅ๊ฐ ๋งค์ ์ฃผ๋ฌธ
order: KisOrder = hynix.buy(qty=1)
# SKํ์ด๋์ค 1์ฃผ ์ง์ ๊ฐ ๋งค์ ์ฃผ๋ฌธ
order: KisOrder = hynix.buy(price=194700, qty=1)
# SKํ์ด๋์ค ์ ๋ ์์ฅ๊ฐ ๋งค๋ ์ฃผ๋ฌธ
order: KisOrder = hynix.sell()
# SKํ์ด๋์ค ์ ๋ ์ง์ ๊ฐ ๋งค๋ ์ฃผ๋ฌธ
order: KisOrder = hynix.sell(price=194700)
print(order.pending) # ๋ฏธ์ฒด๊ฒฐ ์ฃผ๋ฌธ์ธ์ง ์ฌ๋ถ
print(order.pending_order.pending_qty) # ๋ฏธ์ฒด๊ฒฐ ์๋
order: KisOrder = order.modify(price=195000) # ๋จ๊ฐ ์ ์
order: KisOrder = order.modify(qty=10) # ์๋ ์ ์
order.cancel() # ์ฃผ๋ฌธ ์ทจ์
# ๋ฏธ์ฒด๊ฒฐ ์ฃผ๋ฌธ ์ ์ฒด ์ทจ์
for order in account.pending_orders():
order.cancel()
๊ตญ๋ด์ฃผ์ ๋ฐ ํด์ธ์ฃผ์์ ์ค์๊ฐ ์ฒด๊ฒฐ๊ฐ ์กฐํ๋ stock.on("price", callback)
ํจ์๋ฅผ ์ด์ฉํ์ฌ ์์ ํ ์ ์์ต๋๋ค.
from pykis import KisRealtimePrice, KisSubscriptionEventArgs, KisWebsocketClient, PyKis
def on_price(sender: KisWebsocketClient, e: KisSubscriptionEventArgs[KisRealtimePrice]):
print(e.response)
ticket = hynix.on("price", on_price)
print(kis.websocket.subscriptions) # ํ์ฌ ๊ตฌ๋
์ค์ธ ์ด๋ฒคํธ ๋ชฉ๋ก
input("Press Enter to exit...")
ticket.unsubscribe()
{KisWebsocketTR(id='H0STCNT0', key='000660')}
Press Enter to exit...
[08/02 13:50:42] INFO: RTC Connected to real server
[08/02 13:50:42] INFO: RTC Restoring subscriptions... H0STCNT0.000660
[08/02 13:50:42] INFO: RTC Subscribed to H0STCNT0.000660
KisDomesticRealtimePrice(market='KRX', symbol='000660', time='2024-08-02T13:50:44+09:00', price=174900, change=-18400, volume=8919304, amount=1587870362300)
KisDomesticRealtimePrice(market='KRX', symbol='000660', time='2024-08-02T13:50:44+09:00', price=174800, change=-18500, volume=8919354, amount=1587879102300)
KisDomesticRealtimePrice(market='KRX', symbol='000660', time='2024-08-02T13:50:45+09:00', price=174800, change=-18500, volume=8919358, amount=1587879801500)
KisDomesticRealtimePrice(market='KRX', symbol='000660', time='2024-08-02T13:50:45+09:00', price=174900, change=-18400, volume=8920313, amount=1588046831000)
KisDomesticRealtimePrice(market='KRX', symbol='000660', time='2024-08-02T13:50:45+09:00', price=174800, change=-18500, volume=8920319, amount=1588047879800)
[08/02 13:50:48] INFO: RTC Unsubscribed from H0STCNT0.000660