def autologin(port, verbose): set_verbosity(verbose) from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext( port=port, client_check_timeout=client_check_timeout) as context: context.EnsureConnected() context.ShowAccountWindow()
def version(verbose): set_verbosity(verbose) from koapy import KiwoomOpenApiPlusVersionUpdater from koapy.config import config credential = config.get('koapy.backend.kiwoom_open_api_plus.credential') updater = KiwoomOpenApiPlusVersionUpdater(credential) updater.update_version_if_necessary()
def userinfo(port, verbose): set_verbosity(verbose) import pandas as pd from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout, verbosity=verbose) as context: context.EnsureConnected() result = {} result['보유계좌수'] = context.GetLoginInfo('ACCOUNT_CNT') account_numbers = context.GetLoginInfo('ACCLIST').rstrip(';').split(';') for i, accno in enumerate(account_numbers): result['계좌번호 (%d/%s)' % (i + 1, result['보유계좌수'])] = accno result['사용자 ID'] = context.GetLoginInfo('USER_ID') result['사용자 명'] = context.GetLoginInfo('USER_NAME') result['키보드보안 해지 여부'] = { '0': '정상', '1': '해지', }.get(context.GetLoginInfo('KEY_BSECGB'), '알수없음') result['방화벽 설정 여부'] = { '0': '미설정', '1': '설정', '2': '해지', }.get(context.GetLoginInfo('FIREW_SECGB'), '알수없음') result['접속서버 구분'] = { '1': '모의투자', }.get(context.GetServerGubun(), '실서버') click.echo(pd.Series(result).to_markdown())
def modulepath(port, verbose): set_verbosity(verbose) from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout, verbosity=verbose) as context: click.echo(context.GetAPIModulePath())
def order(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no, format, port, verbose): """ \b [주문유형] 1 : 신규매수 2 : 신규매도 3 : 매수취소 4 : 매도취소 5 : 매수정정 6 : 매도정정 \b [거래구분] 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. 00 : 지정가 03 : 시장가 05 : 조건부지정가 06 : 최유리지정가 07 : 최우선지정가 10 : 지정가IOC 13 : 시장가IOC 16 : 최유리IOC 20 : 지정가FOK 23 : 시장가FOK 26 : 최유리FOK 61 : 장전시간외종가 62 : 시간외단일가매매 81 : 장후시간외종가 """ if (request_name, screen_no, account_no, order_type, code, quantity) == (None, None, None, None, None, None): fail_with_usage() set_verbosity(verbose) from koapy import KiwoomOpenApiContext from google.protobuf.json_format import MessageToDict if format == 'json': import json def print_message(message): click.echo(json.dumps(MessageToDict(message))) else: import pprint pp = pprint.PrettyPrinter() def print_message(message): click.echo(pp.pformat(MessageToDict(message))) with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout, verbosity=verbose) as context: context.EnsureConnected() for response in context.OrderCall(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no): print_message(response)
def holidays(output, offline, update, no_update, verbose): set_verbosity(verbose) if output is None: import pandas as pd if not offline: from koapy.utils.krx.marketdata.holiday import download_holidays_as_dict response = download_holidays_as_dict() else: def get_holidays(): import datetime from koapy.utils.krx.calendar.KrxHolidayCalendar import KrxHolidayCalendar today = datetime.datetime.today() calendar = KrxHolidayCalendar() start = datetime.datetime(today.year, 1, 1) end = datetime.datetime(today.year, 12, 31) holidays = calendar.holidays(start, end, return_name=True) return holidays def get_holidays_as_dict(): holidays = get_holidays() response = { 'block1': [{ 'calnd_dd_dy': dt.strftime('%Y-%m-%d'), 'kr_dy_tp': dt.strftime('%a'), 'dy_tp_cd': dt.strftime('%a'), 'holdy_nm': name, } for dt, name in holidays.items() if dt.weekday() < 5] } return response response = get_holidays_as_dict() lang = locale.getdefaultlocale()[0] if lang == 'ko_KR': day_key = 'kr_dy_tp' columns = ['일자 및 요일', '요일구분', '비고'] else: day_key = 'dy_tp_cd' columns = ['date', 'day of week', 'comment'] data = [] for holiday in response['block1']: date = holiday['calnd_dd_dy'] day = holiday[day_key].strip() name = holiday['holdy_nm'] data.append([date, day, name]) df = pd.DataFrame.from_records(data, columns=columns) click.echo(df.to_markdown()) else: if not offline: from koapy.utils.krx.marketdata.holiday import download_holidays_as_excel if output and not output.endswith('.xls'): output += '.xls' download_holidays_as_excel(output) if update: logging.warning('Cannot update on file output.') else: fail_with_usage( 'Saving to file should come with offline option disabled.')
def login(port, verbose): set_verbosity(verbose) from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout) as context: state = context.GetConnectState() if state == 0: click.echo('Logging in...') else: click.echo('Already logged in.') context.EnsureConnected() gubun = context.GetServerGubun() if gubun == '1': click.echo('Logged into Simulation server.') else: click.echo('Logged into Real server.')
def deposit(account, port, verbose): set_verbosity(verbose) if account is None: logging.info('Account not given. Using first account available.') from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout, verbosity=verbose) as context: context.EnsureConnected() if account is None: account = context.GetAccountList()[0] result = context.GetDepositInfo(account) click.echo(result.to_markdown(floatfmt='.2f'))
def stockinfo(code, output, format, port, verbose): # pylint: disable=redefined-builtin if (code, output) == (None, None): fail_with_usage() set_verbosity(verbose) if output is None: if format is None: format = 'md' else: if format is None: format = 'xlsx' if format == 'xlsx': if not output.endswith('.xlsx'): output += '.xlsx' elif format == 'md': if not output.endswith('.md'): output += '.md' elif format == 'json': if not output.endswith('.json'): output += '.json' import pandas as pd from koapy import KiwoomOpenApiPlusEntrypoint with KiwoomOpenApiPlusEntrypoint(port=port, client_check_timeout=client_check_timeout, verbosity=verbose) as context: context.EnsureConnected() dic = context.GetStockBasicInfoAsDict(code) series = pd.Series(dic) if not output: if format == 'md': click.echo(series.to_markdown()) elif format == 'json': click.echo(series.to_json()) else: if format == 'xlsx': series.to_excel(output, header=False) elif format == 'json': with open(output, 'w') as f: click.echo(series.to_json(), file=f)
def evaluation(account, include_delisted, exclude_delisted, for_each, as_summary, port, verbose): set_verbosity(verbose) if account is None: logging.info('Account not given. Using first account available.') if exclude_delisted: include_delisted = False if as_summary: for_each = False lookup_type = '1' elif for_each: lookup_type = '2' from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout, verbosity=verbose) as context: context.EnsureConnected() if account is None: account = context.GetAccountList()[0] single, multi = context.GetAccountEvaluationStatusAsSeriesAndDataFrame( account, include_delisted) click.echo('[계좌평가현황요청] : [계좌평가현황]') click.echo(single.to_markdown()) click.echo() click.echo('[계좌평가현황요청] : [종목별계좌평가현황]') click.echo(multi.to_markdown()) click.echo() single, multi = context.GetAccountEvaluationBalanceAsSeriesAndDataFrame( account, lookup_type) click.echo('[계좌평가잔고내역요청] : [계좌평가결과]') click.echo(single.to_markdown()) click.echo() click.echo('[계좌평가잔고내역요청] : [계좌평가잔고개별합산]') click.echo(multi.to_markdown())
def daily(code, output, format, start_date, end_date, port, verbose): # pylint: disable=redefined-builtin if (code, output, start_date, end_date) == (None, None, None, None): fail_with_usage() set_verbosity(verbose) if output is None: output = '%s.%s' % (code, format) from koapy import KiwoomOpenApiPlusEntrypoint with KiwoomOpenApiPlusEntrypoint(port=port, client_check_timeout=client_check_timeout, verbosity=verbose) as context: context.EnsureConnected() df = context.GetDailyStockDataAsDataFrame(code, start_date, end_date) if format == 'xlsx': df.to_excel(output) elif format == 'sqlite3': from sqlalchemy import create_engine engine = create_engine('sqlite:///' + output) df.to_sql('A' + code, engine)
def orders(account, date, reverse, executed_only, not_executed_only, stock_only, bond_only, sell_only, buy_only, code, starting_order_no, port, verbose): set_verbosity(verbose) if account is None: logging.info('Account not given. Using first account available.') sort_type = '1' if reverse: sort_type = '2' if executed_only: sort_type = '3' if not_executed_only: sort_type = '4' asset_type = '0' if stock_only: asset_type = '1' if bond_only: asset_type = '2' order_type = '0' if sell_only: order_type = '1' if buy_only: order_type = '2' from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout, verbosity=verbose) as context: context.EnsureConnected() if account is None: account = context.GetFirstAvailableAccount() df = context.GetOrderLogAsDataFrame1(account) click.echo('[실시간미체결요청]') click.echo(df.to_markdown()) click.echo() df = context.GetOrderLogAsDataFrame2(account) click.echo('[실시간체결요청]') click.echo(df.to_markdown()) click.echo() df = context.GetOrderLogAsDataFrame3(account, date, sort_type, asset_type, order_type, code, starting_order_no) click.echo('[계좌별주문체결내역상세요청]') click.echo(df.to_markdown())
def errmsg(err_code, verbose): set_verbosity(verbose) from koapy.openapi.KiwoomOpenApiError import KiwoomOpenApiError err_msg = KiwoomOpenApiError.get_error_message_by_code(err_code) click.echo('[%d] %s' % (err_code, err_msg))
def trdata(port, verbose): set_verbosity(verbose) from koapy import KiwoomOpenApiContext from koapy.openapi.TrInfo import TrInfo with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout) as context: TrInfo.dump_trinfo_by_code(context=context)
def realdata(verbose): set_verbosity(verbose) from koapy import KiwoomOpenApiPlusRealType KiwoomOpenApiPlusRealType.dump_realtype_by_desc()
def trdata(verbose): set_verbosity(verbose) from koapy.openapi.TrInfo import TrInfo TrInfo.dump_trinfo_by_code()
def __init__(self, args=()): super().__init__() self._parser = argparse.ArgumentParser() self._parser.add_argument('-p', '--port') self._parser.add_argument('--verbose', '-v', action='count', default=0) self._parsed_args, remaining_args = self._parser.parse_known_args(args) self._port = self._parsed_args.port self._verbose = self._parsed_args.verbose set_verbosity(self._verbose) self._app = QApplication(remaining_args) self._control = KiwoomOpenApiQAxWidget() self._server = KiwoomOpenApiServiceServer(self._control, port=self._port) self._should_restart.connect(self._exit) self._startRestartNotifier() self._startEventLoopProcessor() self._tray = QSystemTrayIcon() self._tray.activated.connect(self._activate) icon = self._app.style().standardIcon(QStyle.SP_TitleBarMenuButton) menu = QMenu() menu.addSection('Connection') connectAction = menu.addAction('Login and Connect') connectAction.triggered.connect(self._connect) autoLoginAction = menu.addAction('Congifure Auto Login') autoLoginAction.triggered.connect(self._configureAutoLogin) menu.addSection('Status') self._connectionStatusAction = menu.addAction('Status: Disconnected') self._connectionStatusAction.setEnabled(False) self._serverStatusAction = menu.addAction('Server: Unknown') self._serverStatusAction.setEnabled(False) menu.addSection('Links') documentationAction = menu.addAction('Documentation') documentationAction.triggered.connect(self._openReadTheDocs) githubAction = menu.addAction('Github') githubAction.triggered.connect(self._openGithub) openApiAction = menu.addAction('Kiwoom OpenAPI+ Home') openApiAction.triggered.connect(self._openOpenApiHome) openApiAction = menu.addAction('Kiwoom OpenAPI+ Document') openApiAction.triggered.connect(self._openOpenApiDocument) qnaAction = menu.addAction('Kiwoom OpenAPI+ Qna') qnaAction.triggered.connect(self._openOpenApiQna) menu.addSection('Exit') exitAction = menu.addAction('Exit') exitAction.triggered.connect(self._exit) tooltip = 'KOAPY Tray Application' self._tray.setIcon(icon) self._tray.setContextMenu(menu) self._tray.setToolTip(tooltip) self._tray.show() self._control.OnEventConnect.connect(self._onEventConnect)
def minute(codes, interval, input, output, format, clean, start_date, end_date, port, verbose): # pylint: disable=redefined-builtin if (codes, interval, input, output, start_date, end_date) == (tuple(), None, None, None, None, None): fail_with_usage() set_verbosity(verbose) if interval is None: fail_with_usage('Interval is not set.') codes_len = len(codes) extension = '.' + format if codes_len == 0: if input is None: fail_with_usage('Either code or input should be given.') if not os.path.exists(input): fail_with_usage('Given input does not exist.') if os.path.isfile(input): if input.endswith('.xlsx'): import pandas as pd df = pd.read_excel(input, dtype=str) code_column = '종목코드' if code_column in df: codes = df[code_column] else: codes = df.iloc[0] codes_len = len(codes) elif input.endswith('.txt'): with open(input) as f: codes = [line.strip() for line in f] codes_len = len(codes) else: fail_with_usage('Unrecognized input file type.') elif os.path.isdir(input): import re codes = [os.path.splitext(name)[0] for name in os.listdir(input) if name.endswith(extension)] codes = [code for code in codes if re.match(r'[0-9A-Z]+', code)] codes_len = len(codes) else: fail_with_usage('Unrecognized input type.') if output is None: output = '.' if os.path.exists(output): if os.path.isdir(output): output_is_folder = True else: output_is_folder = False else: if output.endswith('/') or output.endswith(os.path.sep) or codes_len > 1: output_is_folder = True else: output_is_folder = False if not output_is_folder: assert codes_len == 1 code = codes[0] base_output = os.path.basename(output) output = os.path.dirname(output) extension = '.' + format if not base_output.endswith(extension): base_output += extension final_output = os.path.join(output, base_output) def post_process(updater, codes, output, context): # pylint: disable=unused-argument os.replace(updater.get_filepath_for_code(code), final_output) else: def post_process(updater, codes, output, context): # pylint: disable=unused-argument pass import contextlib with contextlib.ExitStack() as stack: context = None if port is not None: from koapy import KiwoomOpenApiContext context = stack.enter_context(KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout, verbosity=verbose)) context.EnsureConnected() from koapy.data.HistoricalStockPriceDataUpdater import HistoricalStockPriceDataUpdater updater = HistoricalStockPriceDataUpdater(codes, output, 'minute', interval, format, delete_remainings=clean, context=context) updater.update() post_process(updater, codes, output, context)
def stockinfo(codes, markets, input, output, format, port, verbose): # pylint: disable=redefined-builtin """ \b Possible market codes are: 0 : 장내 10 : 코스닥 3 : ELW 8 : ETF 50 : KONEX 4 : 뮤추얼펀드 5 : 신주인수권 6 : 리츠 9 : 하이얼펀드 30 : K-OTC \b Possible market code aliases are: all: All possible market codes. """ if (codes, markets, input, output) == (tuple(), tuple(), None, None): fail_with_usage() set_verbosity(verbose) codes_from_input = False codes_len = len(codes) if codes_len == 0 and len(markets) == 0: if input is None: fail_with_usage('Cannot specify codes.') if not os.path.exists(input): fail_with_usage('Given input does not exist.') codes_from_input = True if os.path.isfile(input): if input.endswith('.xlsx'): import pandas as pd df = pd.read_excel(input, dtype=str) code_column = '종목코드' if code_column in df: codes = df[code_column] else: codes = df.iloc[0] codes_len = len(codes) elif input.endswith('.txt'): with open(input) as f: codes = [line.strip() for line in f] codes_len = len(codes) else: fail_with_usage('Unrecognized input type.') else: fail_with_usage('Unrecognized input type.') if output is None: if codes_len > 1 or codes_from_input: fail_with_usage('Output path is not specified.') if format is None: format = 'md' else: if format is None: format = 'xlsx' if format == 'xlsx': if not output.endswith('.xlsx'): output += '.xlsx' elif format == 'md': if not output.endswith('.md'): output += '.md' elif format == 'json': if not output.endswith('.json'): output += '.json' import pandas as pd from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout, verbosity=verbose) as context: context.EnsureConnected() if not codes_from_input and codes_len == 1: df = context.GetStockInfoAsDataFrame(codes) if not output: if format == 'md': click.echo(df.iloc[0].to_markdown()) elif format == 'json': click.echo(df.iloc[0].to_json()) else: if format == 'xlsx': df.to_excel(output, index=False) elif format == 'json': with open(output, 'w') as f: click.echo(df.iloc[0].to_json(), file=f) elif codes_len > 0: df = context.GetStockInfoAsDataFrame(codes) df.to_excel(output, index=False) elif len(markets) > 0: if 'all' in markets: markets = market_codes if format == 'xlsx': with pd.ExcelWriter(output) as writer: # pylint: disable=abstract-class-instantiated for market in markets: codes = context.GetCodeListByMarketAsList(market) df = context.GetStockInfoAsDataFrame(codes) df.to_excel(writer, index=False, sheet_name=market) elif format == 'json': codes = set() for market in markets: codes = codes.union(set(context.GetCodeListByMarketAsList(market))) codes = sorted(list(codes)) with open(output, 'w', encoding='utf-8') as f: for code in codes: df = context.GetStockInfoAsDataFrame(code) click.echo(df.iloc[0].to_json(), file=f) else: fail_with_usage('Cannot specify codes.')
def trdata(verbose): set_verbosity(verbose) from koapy import KiwoomOpenApiPlusTrInfo KiwoomOpenApiPlusTrInfo.dump_trinfo_by_code()
def watch(codes, input, fids, realtype, output, format, port, verbose): if (codes, fids, realtype) == (tuple(), tuple(), None): fail_with_usage() set_verbosity(verbose) codes_len = len(codes) if codes_len == 0: if input is None: fail_with_usage('Either code or input should be given.') if not os.path.exists(input): fail_with_usage('Given input does not exist.') if os.path.isfile(input): if input.endswith('.xlsx'): import pandas as pd df = pd.read_excel(input, dtype=str) code_column = '종목코드' if code_column in df: codes = df[code_column] else: codes = df.iloc[0] codes_len = len(codes) elif input.endswith('.txt'): with open(input) as f: codes = [line.strip() for line in f] codes_len = len(codes) else: fail_with_usage('Unrecognized input type.') else: fail_with_usage('Unrecognized input type.') if realtype is not None: from koapy.openapi.RealType import RealType fids_from_realtype = RealType.get_fids_by_realtype(realtype) fids = list(set(fids).union(set(fids_from_realtype))) if not codes: fail_with_usage('No codes to watch. Set --code or --input.') if not fids: fail_with_usage('Cannot infer fids to watch. Set either --fid or --realtype.') import datetime import pandas as pd from koapy import KiwoomOpenApiContext from koapy.openapi.RealType import RealType def parse_message(message): fids = event.single_data.names names = [RealType.Fid.get_name_by_fid(fid, str(fid)) for fid in fids] values = event.single_data.values dic = dict((name, value) for fid, name, value in zip(fids, names, values) if name != fid) series = pd.Series(dic) return series if format == 'json': def print_message(message): click.echo(parse_message(message).to_json(), file=output) else: def print_message(message): code = event.arguments[0].string_value name = event.arguments[1].string_value click.echo('[%s] [%s]' % (code, name), file=output) click.echo('[%s]' % datetime.datetime.now(), file=output) click.echo(parse_message(message).to_markdown(), file=output) with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout, verbosity=verbose) as context: context.EnsureConnected() for event in context.GetRealDataForCodesAsStream(codes, fids, infer_fids=True): print_message(event)
def realdata(verbose): set_verbosity(verbose) from koapy.openapi.RealType import RealType RealType.dump_realtype_by_desc()
def realdata(port, verbose): set_verbosity(verbose) from koapy import KiwoomOpenApiContext from koapy.openapi.RealType import RealType with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout) as context: RealType.dump_realtype_by_desc(context=context)
def order(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no, format, port, verbose): # TODO: 주문 취소시 기존 주문에 대한 이벤트 스트림 종료되도록 """ \b [주문유형] 1 : 신규매수 2 : 신규매도 3 : 매수취소 4 : 매도취소 5 : 매수정정 6 : 매도정정 \b [거래구분] 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. 00 : 지정가 03 : 시장가 05 : 조건부지정가 06 : 최유리지정가 07 : 최우선지정가 10 : 지정가IOC 13 : 시장가IOC 16 : 최유리IOC 20 : 지정가FOK 23 : 시장가FOK 26 : 최유리FOK 61 : 장전시간외종가 62 : 시간외단일가매매 81 : 장후시간외종가 """ if (request_name, screen_no, account_no, order_type, code, quantity) == (None, None, None, None, None, None): fail_with_usage() if order_type is None: fail_with_usage() set_verbosity(verbose) from koapy import KiwoomOpenApiContext from google.protobuf.json_format import MessageToDict if format == 'json': import json def print_message(message): click.echo(json.dumps(MessageToDict(message))) else: import pprint pp = pprint.PrettyPrinter() def print_message(message): click.echo(pp.pformat(MessageToDict(message))) with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout, verbosity=verbose) as context: context.EnsureConnected() if order_type in ['3', '4'] and (account_no is None or code is None): for account_no_candidate in context.GetAccountList(): df = context.GetOrderLogAsDataFrame1(account_no_candidate) if '주문번호' in df.columns: rows = df.loc[df['주문번호'] == original_order_no,:] if rows.shape[0] > 0: row = rows.iloc[0,:] if account_no is None: account_no = row['계좌번호'] if code is None: code = row['종목코드'] break if account_no is None: logging.info('Account not given. Using first account available.') account_no = context.GetFirstAvailableAccount() responses = context.OrderCall( request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no) for response in responses: print_message(response)