PYTHON/Kiwoom Open API

거래일 기준 최신 일자 조회하기

  • -

기본적으로 키움증권에서 일봉 데이터를 요청할 때 또는 데이터베이스에서 데이터를 조회하고자 할 때, 특정 일자를 대입해야 하는 경우들이 있는데 특히 데이터베이스에서 데이터를 조회하고자 할 경우에는 다음과 같은 상황에서 오류가 발생할 수 있다.

  • 자정 12시가 넘어 오늘 날짜는 1월 1일인데, 저장되어 있는 데이터의 가장 최신 일자는 12월 31일인 경우 
  • 오후 4시 장마감 전이라 오늘 데이터는 굳이 저장하지 않고 싶은데 지 맘대로 오늘 날짜를 집어 넣는 경우 

무엇보다도 주식 시장의 거래일은 평일만 열린다는 특징이 있기 때문에 단순하게 몇 가지 모듈을 통해 오늘 날짜를 얻어와서 그를 바탕으로 정보 조회를 요청한다면 주말에는 서버에서 데이터가 없다는 신호를 보내주는 오류가 발생하게 된다. 그렇기 때문에 당일이 주말인지 아닌지를 구분하고, 주말이 아니라면 현재 시각을 판단해서 4시 이전이라면 어제의 날짜를 기준으로 하고 4시 이후라면 오늘 날짜를 기준으로 데이터를 조회할 수 있도록 하는 것이 목적이다.

 

import datetime, time

시간 관련 함수들을 처리하기 위해서는 datetime과 time 모듈을 import 해야 한다. 

import datetime
import time

 

 

함수 제작하기

함수 이름은 latest_date으로, latest는 '최신의'라는 의미가 있다. 즉, 가장 최신의 거래일자를 반환하는 함수로 이해하면 된다. 

def latest_date():

다음으로 가장 먼저 판단할 것은 일단 현재 시각이 4시 이전인지, 4시 이후인지이다. 즉, 4시 이전이라면 어제의 날짜를 반환하고 4시 이후라면 오늘의 날짜를 반환하도록 하는 것이다. 그렇다면 현재 시각은 어떻게 알 수 있나? 바로 time 모듈을 통해 확인할 수 있다.

nowtime = time.strftime('%H%M', time.localtime(time.time()))

위와같이 제작한 후 print(nowtime)을 실행해보면 현재 시각이 표시되는 것을 확인할 수 있다. 

현재 시간이 1시 39분이라면 1339로 출력된다.

여기서의 시간이 13:39와 같은 식으로 출력되는 게 깔끔하지 않나 싶은 의문이 들 수도 있는데, 상관 없다. 우리는 어차피 지금 시간이 4시 이전인지 4시 이후인지만 판단할 것이기 때문이다. 그러면 이제 현재 시각을 구했으니 함수 아래에 조건문인 if를 사용해서 4시 이전과 4시 이후를 구분해주도록 하자. 

def latest_date():
	if nowtime < "1600":
		pass
	else:
		pass

이제 현재 시각이 4시 이전이라면 전일의 데이터를 조회해야 하는데, 여기서 주의해야 할 몇 가지 사항들이 있다. 만약 오늘이 금요일이라면 목요일의 날짜를 반환하면 되고 오늘이 수요일이라면 화요일의 날짜를 반환하면 되며, 오늘이 화요일이라면 월요일의 날짜를 반환하면 된다. 다만 오늘이 월요일이라면? 일요일도 토요일도 아닌 지난주 금요일의 날짜를 반환해야 한다. 그렇게 하기 위해서는 일단 오늘 날짜에서 하루를 뺀 날짜를 반환해야 하는데, 이렇게 날짜를 계산해주는 모듈이 바로 datetime 모듈의 timedelta 함수이다. 

굳이 오늘 날짜에서 1을 빼면 될 것을 뭐하러 모듈까지 사용하냐는 의견이 있을 수도 있는데, 20200101에서 1을 빼면 20200100이 된다. 그리고 20200100에서 1을 빼면 2020099가 출력된다. 0월 99일이라는 날짜를 본 적이 있는가? 없다. 다만 timedelta를 사용할 경우에는 20200101에서 1을 빼면 자동으로 20191231을 반환해준다. 

# timedelta의 사용 방법
날짜 (- 또는 +) datetime.timedelta(days=일자)

 

위의 내용을 바탕으로 생각해보면, days=일자 부분에 있는 '일자'에 1이 있으면 하루를 빼고, 2가 있으면 이틀을 뺀다. 그렇다면 못해도 3일은 빼야 오늘이 월요일 오후 4시 이전일 때 금요일의 날짜를 반환해줄 것이다. 그러면 하루씩 빼면서 그 날짜가 주말인지 아닌지를 확인하고, 주말이 아니라면 그 값을 반환해주면 된다. 

그렇다면 계산하기 전에 앞서서, 오늘 날짜는 무엇인지를 얻어야 할텐데, 오늘 날짜는 아래의 방법으로 구할 수 있다.

today = datetime.datetime.now()
datee = str(today.strftime("%Y %m %d").replace(" ", ""))
current_day = datetime.date(int(datee[:4]), int(datee[4:6]), int(datee[6:]))

첫 번째 줄 코드 실행 결과
두 번째 줄 코드 실행 결과
세 번째 줄 코드 실행 결과

첫 번째 사진은 오늘 날짜와 시각을 모두 구하는 모습이고, 두 번째 사진에 있는 코드는 오늘 날짜와 시각이 저장되어 있는 변수인 today를 가공해서 20210101과 같은 형태로, 연월일 데이터만 불러온다. 그 후 세 번째 줄의 코드를 통해서 20210101과 같은 형태를 연-월-일의 형태로, 즉 2021-01-01과 같은 형태로 다시 바꾸어준다. 이렇게 바꾸는 이유는 timedelta를 사용하기 위해서는 계산하고자 하는 일자가 연-월-일의 형태로 구분되어 있어야 하기 때문이다. 물론 이 데이터를 보고는 today[:9]와 같은 형식으로 인덱싱 함으로써 오늘 날짜를 구해올 순 없나 싶은 의문이 들 수도 있는데,  직접 해보면 알겠지만 today는 인덱싱을 통해 접근할 수 있는 형태가 아니다. 그래서 위와 같은 데이터 가공 절차를 거치는 것이다. 이제 current_day를 프린트해보면 2021-01-01과 같이 오늘 날짜를 잘 나타내주는 것을 확인할 수 있다.

# today 변수 인덱싱 접근 시 발생 오류
Traceback (most recent call last):
	File "<pyshell#14>", line 1, in <module>
		today[0]
TypeError: 'datetime.datetime' object is not subscriptable

 


728x90

 

 

timedelta를 이용해서 날짜 계산하기

def latest_date():
	if nowtime < "1600":
		current_date = current_day - datetime.timedelta(days=1)
	
	else:
		pass

가장 먼저, 현재 시간이 4시 이전이라면 일단 오늘 일자를 조회할 것이 아니라 어제 일자를 기준으로 조회해야 한다. 왜냐하면 오늘이 2020년 1월 1일인데 아직 4시 이전이라면, 지금 현재 기준으로 가장 최신의 거래일은 2019년 12월 31일이 될 것이기 때문이다. 따라서 위에서 오늘의 일자를 불러왔던 current_day 변수에서 timedelta(days=1)을 이용해서 하루를 빼주면 어제 일자가 입력된 current_date 변수를 얻게 된다. 이제 for문을 통해 하루 하루씩 빼면서, 그 날짜가 주말인지 아닌지 확인해보도록 하자.

def latest_date():
	if nowtime < "1600":
		current_date = current_day - datetime.timedelta(days=1)
        
		for i in range(7):
			variable = current_date - datetime.timedelta(days=i)
	
	else:
		pass

이처럼 for문 뒤에 range(7)라는 코드를 추가함으로써, 0에서 부터 1씩 증가하되 최대 7까지만 늘리라는 범위를 입력해주었다. 물론 5을 넣나 3을 넣나 값은 같긴 할텐데, 본인은 안전하게 계산하자는 차원에서 7을 입력했다. 이제 variable이라는 변수 안에는 어제 날짜를 기준으로 하루씩 뺀 날짜가 입력되어 있을 테고, 우리는 그 값을 바탕으로 주말인지 아닌지 그 여부를 판단해주면 된다. 주말을 판단하는 것은 datetime 모듈의 weekday() 함수이다. 아래와 같이 제작해주면 된다.

def latest_date():
	if nowtime < "1600":
		current_date = current_day - datetime.timedelta(days=1)
        
		for i in range(7):
			variable = current_date - datetime.timedelta(days=i)
			split = str(variable).split("-")
			aggregate_split = split[0] + split[1] + split[2]
			justify_week = datetime.date(int(split[0]), int(split[1]), int(split[2])).weekday()
	
	else:
		pass

위에서 split이니 aggregate니 뭐니 다양한 값들이 포함되어 있는데, 바로 자료의 형태를 약간 약간씩 수정해주는 것이다. 예를 들어 현재 current_date가 어떤 형태인지 기억하는가? timedelta는 2021-01-01과 같은 형태일 경우에 동작한다고 설명했었다. 그렇기 때문에 현재의 current_date 역시 2021-01-01과 같이 중간에 하이픈(-)이 포함되어 있는 형태일 것이다. 하지만 weekday()함수는 연, 월, 일 모두 제각각 하나의 변수로 전달해주어야 한다. 그렇기 때문에 split이라는 변수 내에서 split("-")을 통해 current_date에 포함되어 있는 값들을 2021, 01, 01의 세 개의 값으로 나누어주었고 justify_week 변수에서는 각각 split[0], split[1], split[2]를 통해 2021, 01, 01이라는 값을 바탕으로 weekday()를 사용했다. 이제 weekday()가 적용된 justify_week 변수에는 0, 1, 2, 3, 4, 5, 6이라는 값이 입력되어 있다. 0, 1, 2, 3, 4는 각각 월, 화, 수, 목, 금요일이고 5, 6은 각각 토요일, 일요일이다. 그렇다면 우리는 이제 justify_week 값이 4보다 크다면 주말이고, 4 이하라면 평일이라는 점을 확인할 수 있는 것이다. 또한 중간에 aggregate_split이라는 변수가 있는데, 이는 우리가 2021, 01, 01로 나누었던 값을 다시 20210101과 같은 형태로 합친 것이다. 왜 합치는가 하면, 우리가 일봉 차트를 조회할 때 기준일자라는 변수에 값을 입력해야 하는데, 그 때 입력하는 날짜의 형태가 하이픈(-) 없이 단순하게 연원일로 이루어진, 20210101과 같은 형태이기 때문이다. 

def latest_date():
	latest_date = []
	if nowtime < "1600":
		current_date = current_day - datetime.timedelta(days=1)
        
		for i in range(7):
			variable = current_date - datetime.timedelta(days=i)
			split = str(variable).split("-")
			aggregate_split = split[0] + split[1] + split[2]
			justify_week = datetime.date(int(split[0]), int(split[1]), int(split[2])).weekday()

			if justify_week > 4:
				pass
			else:
				latest_date.append(aggregate_split)
                
		return latest_date[:1]
	
	else:
		pass

이제 justify_week이 4보다 크다면, 즉 주말이라면 어떠한 처리를 진행하지 않고 4보다 작다면 앞서 20210101과 같은 형태로 바꾸어주었던 aggregate_split이라는 변수를 latest_date라는 변수에 입력(append)해준다. 그 후 마지막에는 하루씩 빼면서 해당 날짜를 입력했던 latest_date 변수에 있는 값을 return 해주는 것이다. 

[참고] latest_date라는 변수는 def latest_date() 바로 아래 줄에 latest_date=[]와 같이 정의해주었는데, 이와 같은 형태로 정의하는 것은 latest_date 변수가 리스트(list)형태임을 의미한다. 리스트 형태로 사용하는 이유는, 하루씩 빼면서 그 값을 입력했으니 나중에는 latest_date[-1]과 같은 방식으로 인덱싱함으로써 최신 일자를 구해올 수 있기 때문이다.

 

 

else: 아래도 제작해주기

else: 하단에는 사실 if nowtime < "1600": 부분과 딱 한 줄만 차이가 있다. 그건 바로 오늘 날짜로부터 하루를 뺀 값인 current_date를 계산하는가 하지 않는가 이다. 위의 if문 안에서는 어제를 기준으로 조회해야 하기 때문에 하루를 뺀 값을 기준으로 계산했지만, else문 아래에서는 4시 이후이기 때문에 오늘 날짜를 기준으로 하루씩 빼면서 어제의 날짜를 반환해주면 된다. 즉, current_date를 계산하는 부분만 빼고 그대로 제작해주면 된다.

else:        
	for i in range(7):
		variable = current_day - datetime.timedelta(days=i)
		split = str(variable).split("-")
		aggregate_split = split[0] + split[1] + split[2]
		justify_week = datetime.date(int(split[0]), int(split[1]), int(split[2])).weekday()

		if justify_week > 4:
			pass
		else:
			latest_date.append(aggregate_split)
                
	return latest_date[:1]

 

 

테스트해보기

위에서 제작한 코드들을 실행해보면 아래와 같은 결과물을 얻을 수 있다. 해당 포스팅을 작성하는 2021년 6월 7일은 월요일이고, 오후 4시 이전에 해당 코드를 실행했기 때문에 일요일인 6월 6일과 토요일인 6월 5일을 건너뛰고 금요일인 2021년 6월 4일이라는 결과값을 반환해주는 것이다. 

 

이제 다음 포스팅에서는 앞서 제작했던 필터링 처리가 된 종목 코드를 대상으로 모든 종목의 일봉 차트 데이터를 조회하되, 이번 포스팅에서 작성했던 거래일 기준 최신일자를 일봉 조회 함수에 전달하여 차트 데이터를 조회하는 방법에 대해 작성할 예정이다.

 

  


728x90
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.