상/하한가 산출 방식과 파이썬으로 구현하기

상/하한가 산출 방식과 파이썬으로 구현하기

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'))

실행 결과는 다음과 같습니다.