대신증권 크레온(Creon) HTS 브리지 서버 만들기 (Django 편)
2020-05-31 • quant • 대신증권, creon, 크레온, hts, 서버, 장고, django • 4 min read
일전에 Flask로 크레온 HTS Bridge 서버 만드는 방법을 이 포스트에서 다뤘었습니다. 이번 포스트에서는 같은 HTS Bridge 서버를 Django로 만드는 방법을 다룹니다.
크레온에 요청을 보내는 creon.py는 재사용합니다.
먼저 Django를 설치합니다.
$ pip install django
설치 결과로 다음처럼 "Successfully installed" 메시지를 확인합니다.
Installing collected packages: asgiref, sqlparse, django
Successfully installed asgiref-3.2.7 django-3.0.6 sqlparse-0.3.1
그리고 한번 더 python 프롬프트에서 django를 임포트해봅니다.
Python 3.7.6 (default, Jan 8 2020, 19:59:22)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> print(django.get_version())
3.0.6
이렇게 버전을 확인하여 설치 및 임포트가 정상적으로 되는지 최종 확인합니다.
이제 프로젝트를 생성할 차례입니다. Flask에 비해서 Django는 초기 설정이 조금 더 복잡합니다. 문서에 따르면 Flask의 기본 내장 웹서버는 개발용으로만 사용하도록 권장하고 있습니다. Django는 Production 서버로 사용하기 적합합니다. (Django 튜토리얼)[https://docs.djangoproject.com/en/3.0/intro/tutorial01/]을 따라서 Django 초기 설정을 해보실길 추천드립니다.
다음과 같이 프로젝트를 생성할 수 있습니다.
$ django-admin startproject <project_name>
$ django-admin startproject systrader
여기서는 project_name
을 systrader
로 정하여 프로젝트를 생성했습니다. 그럼 프로젝트 이름의 폴더가 생성되고 그 아래에 manage.py
와 같은 프로젝트 이름의 폴더가 있습니다.
./systrader/systrader
에는 다음과 같은 파일들이 생성되어 있을 것입니다.
__init__.py
asgi.py
settings.py
urls.py
wsgi.py
여기서 주로 수정해야 할 파일은 urls.py
입니다. 그리고 일반적으로 요청을 처리할 views.py
파일을 추가로 생성해야 합니다.
urls.py
에서 웹서버가 처리할 요청 URL들을 정의합니다. 크레온 API와의 연결을 관리하기 위한 인터페이스 connection
을 시작으로 종목코드, 종목상태, 종목차트, 시장차트, 종목 자질, 공매도, 투자자매매현황 데이터를 받기 위한 인터페이스들이 있습니다.
urlpatterns = [
path('admin/', admin.site.urls),
path('connection', bridge.handle_connection),
path('stockcodes', bridge.handle_stockcodes),
path('stockstatus', bridge.handle_stockstatus),
path('stockcandles', bridge.handle_stockcandles),
path('marketcandles', bridge.handle_marketcandles),
path('stockfeatures', bridge.handle_stockfeatures),
path('short', bridge.handle_short),
path('investorbuysell', bridge.handle_investorbuysell),
]
views.py
는 이름과는 달리 MVC(Model-View-Controller) 모델에서 Controller 역할을 하는 파일입니다. Django의 views.py
는 MVC에서의 View를 렌더링한다는 관점에서 이름을 정한 것으로 추측됩니다.
여기서는 views.py
대신 bridge.py
로 이름을 정했습니다.
먼저 크레온 API를 호출하는 클래스인 Creon
인스턴스를 생성합니다.
import json
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from creon import Creon
import constants
c = Creon()
크레온 HTS API와의 연결 관련 기능을 처리하는 인터페이스를 생성합니다. RESTful 형식으로 GET
방식으로 요청하면 연결 상태를 반환하고 POST
방식은 ID, 비밀번호, 공인인증서 비밀번호를 id
, pwd
, pwdcert
로 각각 받아서 크레온 API와의 연결을 시도합니다. DELETE
방식으로 요청하면 크레온 API와의 연결을 해제합니다.
@csrf_exempt
def handle_connection(request):
if request.method == 'GET':
# check connection status
return JsonResponse(c.connected(), safe=False)
elif request.method == 'POST':
# make connection
data = json.loads(request.body)
_id = data['id']
_pwd = data['pwd']
_pwdcert = data['pwdcert']
return JsonResponse(c.connect(_id, _pwd, _pwdcert), safe=False)
elif request.method == 'DELETE':
# disconnect
return JsonResponse(c.disconnect(), safe=False)
크레온 API와 연결되면 다양한 데이터를 획득할 수 있습니다. 다음은 주식시장 별 종목코드를 획득하기 위한 함수입니다. market
인자로 kospi
또는 kosdaq
를 받아서 해당 시장에 소속된 종목코드를 반환합니다.
def handle_stockcodes(request):
c.wait()
market = request.GET.get('market')
if market == 'kospi':
return JsonResponse(c.get_stockcodes(constants.MARKET_CODE_KOSPI), safe=False)
elif market == 'kosdaq':
return JsonResponse(c.get_stockcodes(constants.MARKET_CODE_KOSDAQ), safe=False)
else:
return HttpResponse('"market" should be one of "kospi" and "kosdaq".', status_code=400)
다음은 종목 상태를 반환하는 함수입니다. 인자 code
로 종목코드를 입력받아서 해당 종목의 상태를 반환받습니다. 상태에는 관리 종목 여부, 거래정지 여부 등이 포함됩니다.
def handle_stockstatus(request):
c.wait()
stockcode = request.GET.get('code')
if not stockcode:
return HttpResponse('"code" should be provided.', status_code=400)
res = c.get_stockstatus(stockcode)
return JsonResponse(res)
다음은 종목의 일봉차트를 획득하기 위한 함수입니다. 획득할 차트의 기간을 date_from
, date_to
인자로 지정할 수 있고 획득할 봉 개수를 n
인자로 지정할 수도 있습니다. 날짜는 yyyyMMdd
형태여야 합니다.
def handle_stockcandles(request):
c.wait()
stockcode = request.GET.get('code')
n = request.GET.get('n')
if n:
n = int(n)
date_from = request.GET.get('date_from')
date_to = request.GET.get('date_to')
if not (n or date_from):
return HttpResponse('Need to provide "n" or "date_from" argument.', status_code=400)
res = c.get_chart(stockcode, target='A', unit='D', n=n, date_from=date_from, date_to=date_to)
return JsonResponse(res, safe=False)
다음은 시장의 일봉차트를 획득하기 위한 함수입니다. 위 종목차트 함수와 거의 같습니다. code
에 kospi
, kosdaq
, kospi200
을 입력할 수 있습니다.
def handle_marketcandles(request):
c.wait()
marketcode = request.GET.get('code')
n = request.GET.get('n')
if n:
n = int(n)
date_from = request.GET.get('date_from')
date_to = request.GET.get('date_to')
if marketcode == 'kospi':
marketcode = '001'
elif marketcode == 'kosdaq':
marketcode = '201'
elif marketcode == 'kospi200':
marketcode = '180'
else:
return HttpResponse('"code" should be one of "kospi", "kosdaq", and "kospi200".', status_code=400)
if not (n or date_from):
return HttpResponse('Need to provide "n" or "date_from" argument.', status_code=400)
res = c.get_chart(marketcode, target='U', unit='D', n=n, date_from=date_from, date_to=date_to)
return JsonResponse(res, safe=False)
다음은 종목의 다양한 자질값들을 획득하는 함수입니다. 데이터에는 PER
, 배당률
, 공매도수량
등의 매우 다양한 자질들이 포함됩니다.
def handle_stockfeatures(request):
c.wait()
stockcode = request.GET.get('code')
if not stockcode:
return HttpResponse('"code" should be provided.', status_code=400)
res = c.get_stockfeatures(stockcode)
return JsonResponse(res)
다음은 종목의 일단위 공매도 데이터를 획득하는 함수입니다. 종목코드와 데이터 일수를 입력으로 받습니다.
def handle_short(request):
c.wait()
stockcode = request.GET.get('code')
n = request.GET.get('n')
if n:
n = int(n)
if not stockcode:
return HttpResponse('"code" should be provided.', status_code=400)
res = c.get_shortstockselling(stockcode, n=n)
return JsonResponse(res, safe=False)
다음은 종목의 투자자별 매매현황을 획득하는 함수입니다.
def handle_investorbuysell(request):
c.wait()
stockcode = request.GET.get('code')
n = request.GET.get('n')
if n:
n = int(n)
if not stockcode:
return HttpResponse('"code" should be provided.', status_code=400)
res = c.get_investorbuysell(stockcode, n=n)
return JsonResponse(res, safe=False)
이렇게 크레온 API 브리지 서버를 구축하고 다음과 같이 실행하여 사용할 수 있습니다.
$ python manage.py runserver 0.0.0.0:8000 --noreload
manage.py
의 runserver
명령으로 웹서버를 실행할 수 있으며 인자로 웹서버의 listen IP, 포트를 입력할 수 있고 --noreload
옵션을 추가하여 웹서버 코드를 수정했을때 자동으로 리로드 되는 것을 막을 수 있습니다.
위에서 소개한 브리지 서버는 간단한 기능 몇개만 구현해 놓은 것이며 다양한 기능들을 추가해 나갈 예정입니다.