Skip to content

블로그

Windows 10에서 아나콘다 32bit 사용시 에러 해결

Anaconda3 x86(32bit) 버전을 아무 문제 없이 잘 쓰고 있었다. 굳이 32bit 버전을 사용한 이유는 HTS API를 사용하기 위해서 였습니다. 증권사 장단점 비교 글에서 그 이유를 설명했습니다. 그런데 윈도우 업데이트가 되었는지 갑자기 Anaconda3 x86의 python.exe를 실행하려 하면 다음과 같은 에러 메시지가 표시되며 실행되지 않았습니다.

error

먼저 이 에러 메시지를 검색해서 이런 저런 방법을 써봤지만 해결되지 않았습니다. 관리자 권한으로 실행해봐도 안되고, “기본 제공 관리자 계정에 대한 관리자 승인 모드” 사용을 해봐도 안됐습니다. Anaconda 버전이 낮아서 그런가 해서 다시 설치해 봤는데도 안되었습니다. 결국 Anaconda3 x64 버전에 x86 환경을 생성하는 것으로 해결는데 그 방법은 다음과 같습니다. 먼저 cmd prompt를 엽니다. 그리고 다음과 같이 환경 설정 후 x86 환경을 설치합니다.

Terminal window
set CONDA_FORCE_32BIT=1
conda create -n py37_32 python=3.7 anaconda
activate py37_32

파이썬 메인 모듈에서 인자(argument) 파싱

파이썬 main을 실행할 때 인자(argument)를 주고싶은 경우 다음과 같이 할 수 있습니다. 인자는 positional argument와 optional argument로 구성할 수 있습니다. (자세한 정보는 https://docs.python.org/3.7/library/argparse.html 참고하세요.)

if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('parg1') # positional argument
parser.add_argument('parg2') # positional argument
parser.add_argument('--oarg1') # optional argument
parser.add_argument('--oarg2') # optional argument
args = parser.parse_args()
print(args)

다음은 실행 커맨드에 따라 달라지는 args를 보여줍니다.

  • python main.py 1 2
    • Namespace(oarg1=None, oarg2=None, parg1='1', parg2='2')
  • python invalidanc.py 1 2 --oarg1=3
    • Namespace(oarg1='3', oarg2=None, parg1='1', parg2='2')
  • python invalidanc.py 1 2 --oarg1=3 --oarg2=4
    • Namespace(oarg1='3', oarg2='4', parg1='1', parg2='2')

증권사 API 장단점 비교

이 포스트에서는 다음 세 가지 증권사 API의 활용성에 대해 정리하고자 합니다.

  • 키움증권 Open API
  • 대신증권 크레온 API
  • 이베스트투자증권 Xing API

증권사 API들은 제가 아는 바로는 모두 윈도우 환경에서만 제공됩니다. 공인인증서 등의 보안 장치 때문으로 보이는데, 개발 환경이 주로 리눅스나 맥인 경우 이는 상당한 단점이 됩니다.

주요 개발환경을 리눅스나 맥으로 유지하면서 증권사 API를 활용하려면 어떻게 해야 할까요? 윈도우 환경으로 증권사 API를 호출하고 결과를 그대로 전달해주는 간단한 Bridge 서버를 구성하는 것이 유일한 방법으로 보입니다.

arch

리눅스, 맥 환경의 클라이언트가 윈도우 환경의 Brige 서버에 요청을 보내고, 이 Bridge 서버는 요청에 맞게 HTS API를 호출하여 결과를 다시 클라이언트에게 전송하는 구조입니다.

Bridge 서버는 HTTP, Socket 등의 통신 방식으로 구성할 수 있습니다. Request-Response 방식의 요청만 필요하면 HTTP 서버로, 실시간 데이터 수신이 필요하면 Socket 서버를 사용하는 것이 효과적일 것입니다.

증권사들이 윈도우 환경에서 OCX, COM, DLL 방식으로 API를 제공합니다.

  • 키움증권 Open API: OCX 방식
  • 대신증권 크레온 API: COM 방식
  • 이베스트투자증권 Xing API: COM 방식, DLL 방식

개인적으로 API 제공 방식은 OCX 보다는 COM 방식을 선호합니다. 파이썬에서 OCX 방식의 API를 사용하기 위해서 PyQt를 이용해야 하지만 COM 방식은 win32com을 사용하여 보다 간편합니다. (DLL 방식으로는 개발해보지 않았습니다.)

API가 잘 설계되어 있으면 그만큼 사용하기 편합니다. 세 증권사 API를 모두 사용해본 소감을 다음과 같이 정리합니다.

  • 키움증권 Open API: 문서화가 잘 되어 있고 API의 Signature는 설계가 잘 되어 있으나, 요청 결과를 비동기 방식으로 제공하여 불편함이 있습니다.
  • 대신증권 크레온 API: 문서화가 잘 되어 있고 API의 Signature도 잘 설계되어 있으며 요청 결과를 동기적으로 받을 수 있습니다.
  • 이베스트투자증권 Xing API: 문서화가 잘 되어 있지만 API Signature가 직관적이지가 않습니다. 요청 결과는 동기적으로 받을 수 있습니다.

즉 제가 느낀 사용성은 크레온 >> 키움 = 씽 입니다.

증권사 API들은 원활한 서비스 제공을 위해 API를 통한 과도한 요청을 막고 있습니다.

  • 키움증권 Open API: 1초에 5회로 제한하며, 제 경험상 1시간에 1000회로 제한하고 있습니다.
  • 대신증권 크레온 API: 시세 조회의 경우 15초에 60건, 실시간 조회의 경우 최대 400건으로 제한되어 있고, 주문 관련 조희의 경우 15초에 최대 20건으로 제한됨.
  • 이베스트투자증권 Xing API: 모의서버의 경우 1초에 10건으로 제한되어 있습니다.

이로 봤을 때 요청 제한은 Xing API가 가장 제한이 약하고 나머지 두 증권사는 비슷한 수준으로 보입니다.

세 증권사 API 모두 자동로그인이 가능합니다. 다만 사용성과 보안성 측면에서 차이점이 있습니다.

  • 키움증권 Open API: 코드 상에서 아이디, 비밀번호, 공인인증서 비밀번호가 노출되지 않으므로 보안이 강합니다.
  • 대신증권 크레온 API: 코드 상에서 크레온 프로그램을 실행하여 자동로그인 기능을 구현하면 아이디, 비밀번호, 공인인증서 비밀번호가 노출될 수 있습니다. 스크립트 등으로 로그인하고 프로그램을 실행하는 것이 보안상 좋습니다.
  • 이베스트투자증권 Xing API: 코드 상에서 아이디, 비밀번호, 공인인증서 비밀번호가 노출될 수 있습니다.

즉 보안성은 키움증권이 제일 좋아 보이며 크레온, Xing을 사용할 경우 코드가 유출되지 않도록 각별히 유의해야 할 것입니다.

키움증권크레온Xing
환경윈도우윈도우윈도우
API 연결 방식OCXCOMCOM, DLL
API 사용성보통좋음보통
요청 제한5/s4/s10/s
자동로그인 보안성좋음보통보통

Matplotlib으로 봉차트(Candlestick Chart) 그리기

봉차트(Candlestick Chart)는 한국 금융권에서 아주 친숙하게 사용되고 있는 차트 입니다. 하나의 봉(Candle)은 특정 기간 동안에서의 시가, 고가, 저가, 종가 (Open, High, Low, Close; OHLC)를 한번에 표현해 줍니다. 보통 일봉, 즉 하루 동안의 OHLC를 표현한 봉으로 차트를 그립니다.

파이썬에서 봉차트를 그릴 수 있는 도구는 다양하겠지만 대표적인 파이썬 차트 라이브러리인 (Matplotlib)[https://matplotlib.org/index.html]을 활용하여 봉차트를 그리는 법을 이 포스트에서 다루겠습니다.

Matplotlib 1.X 버전에서는 matplotlib.finance 모듈에서 candlestick_ohlc() 함수를 제공하고 있었으나 이 모듈은 2.0 버전부터 Deprecated 되었고, 이 모듈은 따로 (Gihub Repository)[https://github.com/matplotlib/mpl_finance]로 유지되고 있습니다. 설치는 다음 명령으로 할 수 있습니다.

pip install https://github.com/matplotlib/mpl_finance/archive/master.zip

이제 가시화할 데이터를 준비합니다. 다음과 같은 20일치 OHLC와 거래량 데이터를 봉차트로 그려보겠습니다.

dateopenhighlowclosevolume
02018080714250014550014200014500063103
12018080814400014500014150014350049191
22018080914350014400014200014200063800
32018081014200014650014200014600057283
42018081314500014600014100014200051095
52018081414150014600014150014250042579
62018081614150014200013850014100066262
720180817140500141000137000138500100717
82018082013850014000013750013750053507
92018082113750014000013750014000040399
102018082213850014000013850013900034023
112018082313950014000013500013600095824
1220180824135500137000132000134500118459
132018082713500013650013400013500067489
142018082813550013600013300013500066626
152018082913500013600013400013550064548
1620180830135500136000131500132500141496
1720180831132500133500131000132000100410
182018090313250013350013200013200037159
192018090413250013350013150013350035215

이렇게 데이터가 준비되었으니, 차트 레이아웃을 구성하겠습니다.

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=(8, 5))
fig.set_facecolor('w')
gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1])
axes = []
axes.append(plt.subplot(gs[0]))
axes.append(plt.subplot(gs[1], sharex=axes[0]))
axes[0].get_xaxis().set_visible(False)

결과는 다음과 두 개의 차트 영역이 위아래에 구성됩니다. 위에는 봉차트를 아래에는 거래량 바차트(Bar Chart)를 그리겠습니다. 위 아래 차트 모두 x 축은 같기 때문에 아래쪽 차트에만 x 축의 틱 레이블(Tick Label)을 표시합니다.

layout

이제 여기에 봉차트와 거래량 차트를 그리면 됩니다. mpl_finance 모듈에서 candlestick_ohlc() 함수를 임포트하고 x 축 데이터를 준비한 다음 봉차트와 거래량 차트를 그립니다.

from mpl_finance import candlestick_ohlc
x = np.arange(len(df.index))
ohlc = df[['open', 'high', 'low', 'close']].astype(int).values
dohlc = np.hstack((np.reshape(x, (-1, 1)), ohlc))
# 봉차트
candlestick_ohlc(axes[0], dohlc, width=0.5, colorup='r', colordown='b')
# 거래량 차트
axes[1].bar(x, df.volume, color='k', width=0.6, align='center')
plt.tight_layout()
plt.show()

이 파이썬 코드의 결과는 다음과 같습니다.

layout

여기서 x 축의 틱 레이블이 0에서 59까지 index 값으로 표시되는데, 일자로 표시되도록 해보겠습니다. 아래와 같이 plt.show() 전에 틱 레이블을 추가합니다. 여기서는 월요일에 해당하는 날짜만 표시하도록 했습니다.

# xlabels에 요일 추가
import datetime
_xticks = []
_xlabels = []
_wd_prev = 0
for _x, d in zip(x, df.date.values):
weekday = datetime.datetime.strptime(str(d), '%Y%m%d').weekday()
if weekday <= _wd_prev:
_xticks.append(_x)
_xlabels.append(datetime.datetime.strptime(str(d), '%Y%m%d').strftime('%m/%d'))
_wd_prev = weekday
axes[1].set_xticks(_xticks)
axes[1].set_xticklabels(_xlabels, rotation=45, minor=False)

이렇게 해주면 아래와 같이 index 값 대신 날짜가 x축 틱의 레이블로 표시됩니다.

layout

코스피, 코스닥, 코스피200 5일 평균 대비 현재가

주식 투자를 함에 있어 시장 상황을 파악하는 것은 매우 중요한 일입니다. 코스피, 코스닥, 코스피200 등의 지수가 안좋을 때는 매도의 관점에서 리스크를 관리해야 할 것입니다.

이 포스트에서는 지수의 5일 평균선에서의 현재 지수의 위치를 확인하는 간단한 파이썬 코드를 공유합니다. 데이터는 키움증권 Open API를 통해 수집했습니다. 물론 어떠한 소스에서 데이터를 획득해도 상관 없습니다.

5일 간의 코스피 데이터가 다음과 같을 때, 최근 5일 종가(현재가)의 평균 대비 당일 현재가의 위치를 확인해 보겠습니다.

[{'code': '001',
'date': '20181102',
'open': 2046.61,
'high': 2096.63,
'low': 2044.94,
'close': 2096.0,
'volume': 371978.0},
{'code': '001',
'date': '20181101',
'open': 2035.11,
'high': 2054.22,
'low': 2023.43,
'close': 2024.46,
'volume': 343813.0},
{'code': '001',
'date': '20181031',
'open': 2022.84,
'high': 2030.5,
'low': 2006.63,
'close': 2029.69,
'volume': 373027.0},
{'code': '001',
'date': '20181030',
'open': 1985.95,
'high': 2028.84,
'low': 1985.95,
'close': 2014.69,
'volume': 441585.0},
{'code': '001',
'date': '20181029',
'open': 2026.68,
'high': 2045.76,
'low': 1993.77,
'close': 1996.05,
'volume': 427304.0}]

우선 20181029에서 20181102까지 5일 동안의 코스피 평균은 약 2032.18 입니다. 그리고 20181102의 종가는 2096.0 입니다. 5일 평균과의 비율로 보면 약 1.03으로 1보다는 커서 매수를 해볼만한 상황이라 볼 수 있습니다.

이런 단순한 지표로 투자를 결정할 수는 없지만 돌다리도 두들겨보고 건넌다는 생각으로, 시장 지수의 5일 평균 대비 현재가가 1 미만인 경우에는 관망하는 것이 좋습니다.

아래는 이 값을 구하는 매우 간단한 파이썬 코드 입니다.

import numpy as np
data = [{'code': '001', 'date': '20181102', 'open': 204661.0, 'high': 209663.0, 'low': 204494.0, 'close': 209600.0, 'volume': 371978.0}, {'code': '001', 'date': '20181101', 'open': 203511.0, 'high': 205422.0, 'low': 202343.0, 'close': 202446.0, 'volume': 343813.0}, {'code': '001', 'date': '20181031', 'open': 202284.0, 'high': 203050.0, 'low': 200663.0, 'close': 202969.0, 'volume': 373027.0}, {'code': '001', 'date': '20181030', 'open': 198595.0, 'high': 202884.0, 'low': 198595.0, 'close': 201469.0, 'volume': 441585.0}, {'code': '001', 'date': '20181029', 'open': 202668.0, 'high': 204576.0, 'low': 199377.0, 'close': 199605.0, 'volume': 427304.0}]
for d in data:
d['open'] = d.get('open') / 100
d['high'] = d.get('high') / 100
d['low'] = d.get('low') / 100
d['close'] = d.get('close') / 100
m = np.mean(list(map(lambda d: d.get('close'), data)))
print(m)