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 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 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 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 stockname(codes, port): from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout) as context: context.EnsureConnected() def get_codes(): if codes: if '-' in codes: with click.open_file('-', 'r') as f: for code in f: yield code.strip() else: for code in codes: yield code else: while True: try: code = click.prompt('code', prompt_suffix=' >>> ') code = code.strip() if code == 'exit': break if code: yield code except EOFError: break for code in get_codes(): name = context.GetMasterCodeName(code) click.echo(name)
def stockcode(markets, name, port): """ \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 (markets, name) == (tuple(), None): fail_with_usage() from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext( port=port, client_check_timeout=client_check_timeout) as context: context.EnsureConnected() if name is not None and not markets: markets = ['0'] if 'all' in markets: markets = market_codes codes = set() for market in markets: codes = codes.union(set(context.GetCodeListByMarketAsList(market))) codes = sorted(list(codes)) if not name: for code in codes: click.echo(code) else: names = [context.GetMasterCodeName(code) for code in codes] codes_by_name = dict(zip(names, codes)) code = codes_by_name.get(name, None) if code: click.echo(code) else: click.echo('Cannot find code for given name.')
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 get_or_create_context(self): with contextlib.ExitStack() as stack: if self._context is None: default_context = config.get( 'koapy.data.updater.default_context') if default_context == 'koapy.backend.cybos.CybosPlusComObject.CybosPlusComObject': logging.debug('Using CybosPlus backend') default_context = CybosPlusComObject() else: if default_context != 'koapy.context.KiwoomOpenApiContext.KiwoomOpenApiContext': logging.warning( 'Unexpected default context %s, defaults to KiwoomOpenApiContext.', default_context) logging.debug('Using Kiwoom OpenAPI backend') default_context = KiwoomOpenApiContext() self._context = stack.enter_context(default_context) def unset_context(): self._context = None stack.callback(unset_context) else: logging.debug('Using existing given context of type %s', type(self._context)) if isinstance(self._context, KiwoomOpenApiContext): if self._chart_type == ChartType.DAY: self._date_column_name = '일자' self._date_format = '%Y%m%d' elif self._chart_type == ChartType.MINUTE: self._date_column_name = '체결시간' self._date_format = '%Y%m%d%H%M%S' else: raise ValueError elif isinstance(self._context, CybosPlusComObject): if self._chart_type == ChartType.DAY: self._date_column_name = '날짜' self._date_format = '%Y%m%d' elif self._chart_type == ChartType.MINUTE: self._date_column_name = '날짜' self._date_format = '%Y%m%d' self._time_column_name = '시간' self._time_format = '%H%M' else: raise ValueError else: raise TypeError self._context.EnsureConnected() yield self._context
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 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 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 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 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 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)
from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext() as context: context.EnsureConnected() account_nos = context.GetAccountList() print('전체 계좌 목록: %s' % account_nos) account_no = account_nos[0] print('사용할 계좌번호: %s' % account_no) print() series = context.GetDepositInfo(account_no) print('예수금상세현황요청 : 예수금상세현황') print(series.to_markdown()) print() df = context.GetAccountRateOfReturnAsDataFrame(account_no) print('계좌수익률요청 : 계좌수익률') # TR 이름에서 그대로 따왔긴 한데, 정작 수익률은 그 어디에도 없음.. print(df.to_markdown()) print() summary, foreach = context.GetAccountEvaluationStatusAsSeriesAndDataFrame( account_no) print('계좌평가현황요청 : 계좌평가현황') print(summary.to_markdown()) print('계좌평가현황요청 : 종목별계좌평가현황') print(foreach.to_markdown()) print() # 위와 아래의 차이는 수수료/세금 영향을 고려하냐 안하냐의 차이인듯, 위는 고려하지 않고 아래는 모두 고려하는것으로 보임
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 stockcode(names, markets, port): """ \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. """ markets_option = markets if (markets, names) == (tuple(), tuple()): # fail_with_usage() pass from koapy import KiwoomOpenApiContext with KiwoomOpenApiContext(port=port, client_check_timeout=client_check_timeout) as context: context.EnsureConnected() if not names and not markets: markets = ['0'] if 'all' in markets: markets = market_codes codes = set() for market in markets: codes = codes.union(set(context.GetCodeListByMarketAsList(market))) codes = sorted(list(codes)) if markets_option: for code in codes: click.echo(code) else: def get_names(): if names: if '-' in names: with click.open_file('-', 'r') as f: for name in f: yield name.strip() else: for name in names: yield name else: while True: try: name = click.prompt('name', prompt_suffix=' >>> ') name = name.strip() if name == 'exit': break if name: yield name except EOFError: break all_names = [context.GetMasterCodeName(code) for code in codes] codes_by_name = dict(zip(all_names, codes)) for name in get_names(): code = codes_by_name.get(name, None) if code: click.echo(code) else: click.echo('Cannot find code for given name: %s.' % name)
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)
import pandas as pd from koapy import KiwoomOpenApiContext from koapy.backend.cybos.CybosPlusComObject import CybosPlusComObject kiwoom = KiwoomOpenApiContext() cybos = CybosPlusComObject() kiwoom.EnsureConnected() cybos.EnsureConnected() kiwoom_codes = kiwoom.GetCommonCodeList() cybos_codes = cybos.GetCommonCodeList() cybos_codes = [code[1:] for code in cybos_codes] kiwoom_codes = pd.DataFrame(kiwoom_codes, columns=['code']) kiwoom_codes['kiwoom'] = 'TRUE' cybos_codes = pd.DataFrame(cybos_codes, columns=['code']) cybos_codes['cybos'] = 'TRUE' df = pd.merge(kiwoom_codes, cybos_codes, how='outer', on='code') df.to_excel('output.xlsx')