상/하한가 산출 방식과 파이썬으로 구현하기
2018, Jul 19
이 게시글에서는 상/하한가 산출 방식과 그 과정을 파이썬 코드로 옮겨서 정리해 보도록 하겠습니다. 상/하한가는 기준가에 단순히 1.3 또는 0.7을 곱한 가격과 차이가 있습니다. 표지의 그림과 같이 29.XX(%) 이런식으로 결정이 되어집니다. 이는 호가 가격단위가 있기 때문인데, KRX 규정집에 따르면 다음과 같이 계산되어 집니다.
상/하한가 산출방법
- 1차계산 : 기준가격에 가격제한폭(현재는 0.3)을 곱합니다.
- 2차계산 : 기준가격의 호가가격단위에 해당하는 가격 미만을 절사합니다.
- 3차계산 : 기준가격에 2차계산에 의한 수치를 가감하되, 해당가격의 호가가격단위 미만을 절사합니다.
산출예시 : 기준가격이 9,980원인 경우
- 1차계산 : 9,980원X0.3 = 2,994원
- 2차계산 : 2,990원 (9,980원의 호가가격단위인 10원미만 절사 : 1차절사)
- 3차계산
- 상한가
9,980원 + 2,990원 = 12,970원
호가가격단위 적용 : 12,970원의 호가가격단위인 50원미만 절사(2차절사)
상한가 = 12,970 → 12,950원 (호가 단위 50)- 하한가
9,980원 - 2,990원 = 6,990원
하한가 = 6,990 그대로 (만원 이하이기 때문에 호가 단위가 10원임 → 2차 절사가 일어나지 않음)
이를 파이썬 코드를 통해 함수화 해보도록 하겠습니다. 먼저 가격제한폭은 현재 코스피/코스닥 모두 30%(=0.3) 이지만 과거에는 다른 값을 가졌습니다. 코드로 나타내면 다음과 같습니다.
import datetime
def get_limit_rate(date, market):
# 날짜와 시장구분을 입력 받아 가격제한폭을 반환하는 함수
# date : timestamp 또는 datetime
# market : 시장구분 여기서는 KOSPI 또는 KOSDAQ
if market == 'KOSPI': # 코스피 종목의 가격제한폭은 다음과 같이 정해집니다.
if date >= datetime.datetime.strptime('2015-06-15','%Y-%m-%d'):
return 0.3
elif date >= datetime.datetime.strptime('1998-12-07','%Y-%m-%d'):
return 0.15
elif market == 'KOSDAQ': # 코스닥 종목의 가격제한폭은 다음과 같이 정해집니다.
if date >= datetime.datetime.strptime('2015-06-15','%Y-%m-%d'):
return 0.3
elif date >=datetime.datetime.strptime('2005-03-28','%Y-%m-%d'):
return 0.15
elif date >=datetime.datetime.strptime('1998-12-07','%Y-%m-%d'):
return 0.12
그 다음은 호가 가격단위를 계산해 주는 함수를 만들어 줍니다. 호가 가격단위는 다음과 같이 함수화 할 수 있습니다.
def tick_scale(base_price,market):
# base_price : 기준가, market : 시장구분
if market=='KOSPI':
if base_price < 1000 :
return 1
elif base_price < 5000 :
return 5
elif base_price < 10000 :
return 10
elif base_price < 50000 :
return 50
elif base_price < 100000 :
return 100
elif base_price < 500000 :
return 500
else:
return 1000
elif market=='KOSDAQ':
if base_price < 1000 :
return 1
elif base_price < 5000 :
return 5
elif base_price < 10000 :
return 10
elif base_price < 50000 :
return 50
else:
return 100
위의 함수들을 활용하여 상한가와 하한가를 반환해주는 함수를 만들어 보면 다음과 같습니다.
def get_sang_ha(base_price, date, market):
# base_price : 기준가, date : 날짜 ,market : 시장구분
# Output : 당일에 해당하는 상한가와 하한가를 반환
limit_rate = get_limit_rate(date, market) # 가격제한폭을 계산합니다
# 1차 계산
increment = base_price * limit_rate
# 2차 계산
scale = tick_scale(increment, market)
adj_increment = int(increment/scale) * scale # 1차 절사
# 3차 계산
sang = base_price + adj_increment
ha = base_price - adj_increment
# 상한가에 대한 가격 조정
scale = tick_scale(sang, market)
adj_sang = int(sang/scale) * scale # 2차 절사
# 하한가에 대한 가격 조정
scale = tick_scale(ha, market)
adj_ha = int(ha/scale) * scale # 2차 절사
return adj_sang, adj_ha # 상한가와 하한가를 반환
예시의 데이터로 확인을 해보도록 하겠습니다.
# 예제의 데이터로 확인
date = datetime.datetime(2016,1,1) # 임의로 날짜 지정
sang_ha = get_sang_ha(9980,date,'KOSPI')
print ('상한가 : ', sang_ha[0])
print ('하한가 : ', sang_ha[1])
실행 결과는 다음과 같습니다.
상한가 : 12950
하한가 : 6990
날짜를 바꿔서(가격제한폭이 30%가 되기 이전) 실행하여 보도록 하겠습니다.
# 예제의 데이터로 확인
date = datetime.datetime(2013,1,1) # 가격제한폭이 30%가 되기 이전
sang_ha = get_sang_ha(9980,date,'KOSPI')
print ('상한가 : ', sang_ha[0])
print ('하한가 : ', sang_ha[1])
실행 결과는 다음과 같습니다.
상한가 : 11450
하한가 : 8480
다음과 같이 기준가에 대한 데이터를 pandas.Series 형태로 가지고 있다면 이에 대한 상/하한가는 다음 코드로 쉽게 계산 할 수 있습니다.
pd.Series(list(zip(bp,bp.index)),index=bp.index).apply(lambda x : get_sang_ha(x[0],x[1],'KOSPI'))
실행 결과는 다음과 같습니다.