PYTHON/Kiwoom Open API

키움증권 Open API - 차트 데이터 이어서 조회하기 (1)

  • -

이번 게시글에서 다룰 내용은 반드시 데이터베이스가 구축이 되어 있어야만 이어서 조회하는 것이 가능하다. 아직 데이터베이스를 구축하지 않았다면 반드시 이전 게시글을 보면서 차트 데이터 조회를 관리하기 위한 데이터베이스를 구축하고 넘어와야만 이번 게시글을 이해하고 따라갈 수 있다.

 

키움증권 Open API - 차트 데이터 관리 DB 제작 (2)

지난 게시글에서 item_savepoint라는 데이터베이스 안에 item_savepoint라는 테이블을 생성한 채로 마무리했으니 이번 게시글에서는 그 내용에 이어서 item_savepoint라는 테이블 안에 종목 코드들을 입력

trustyou.tistory.com

 

 

item_savepoint 데이터베이스 불러오기

본격적인 내용을 시작하기 전에 앞서, 기본적으로 우리가 차트 데이터를 저장하던 곳에서부터 이어서 저장하기 위해 이 데이터베이스를 만들었기 때문에, 해당 데이터를 불러오는 것은 반드시 Open API 코드가 구축되어 있는 곳에서 제작하는 것이 편하다. 물론 posting_mysql이라는 별도의 파일에 check_db 또는 check_table 등과 같은 함수들을 구축해두긴 했지만, 이번에 사용하고자 하는 것은 조금 다르기 때문에 이 부분은 참고하도록 하자. 아니면 글을 한 번 쭈욱 읽고 나서 어디에 제작할지 결정해도 된다.

이제 데이터베이스를 불러올 것인데, 데이터베이스를 불러오는 것은 SELECT 문이다. 이전 게시글에서도 여러 번 사용했기 때문에 사용하는 방식에 대해서는 어렵지 않게 유추할 수 있다. 바로 cur.execute("SELECT")와 같은 형태로 사용한다. 다만 SELECT를 통해서 가져오고자 하는 데이터를 정해서 가져올 수도 있고 모두 가져올 수도 있다. SELECT문의 기본적인 형태는 아래를 참고하도록 하자. 물론 SELECT문의 경우에도 UPDATE문과 같이 WHERE 명령어를 함께 사용할 수도 있다.

  • cur.execute("SELECT columns_name FROM 'db_name'.'table_name')
  • cur.execute("SELECT * FROM 'db_name'.'table_name')
  • cur.execute("SELECT * FROM 'db_name'.'table_name' WHERE 'columns_name'='data'

이 경우에는 여러 가지 형태로 사용할 수 있긴 하지만, 가장 기본적인 형태는 SELECT ~ FROM과 같은 형태이기 때문에, WHERE은 제외하고 별도의 함수를 제작해서 사용할 수 있다. 물론 WHERE = True 또는 False와 같은 bool 형태로 해당 함수에 변수를 전달하고 if WHERE = True인 경우와 if WHERE = False인 경우를 나누어서 코드를 구축할 수도 있긴 하지만, 일단은 가장 기본적인 데이터베이스 불러오기만 구축하도록 하자.

def select_data(columns_name, db_name, table_name):
	connect = mysql.connector.connect(user='root', password=PASSWORD, host='127.0.0.1', charset='utf8mb4')
	cur = connect.cursor()

	select_data = "SELECT " + columns_name + " FROM `" + db_name + "`.`" + table_name + "`"
	cur.execute(select_data)
	result = cur.fetchall()
	return result

 

이제 Open API가 제작된 파일의 코드 중 맨 하단에 있는 if문 아래로 가서, 별도의 파일(본인의 파일명은 posting_sql)에 제작한 select_data 함수에 관련 변수들을 전달해주고 그 결과값을 받도록 하자. 

파이참의 경우, 함수를 사용할 땐 전달해야 할 변수를 알려준다.

아래의 코드를 실행한 후, print(result)를 통해 그 결과값을 출력하도록 하면 다음과 같은 결과물을 얻을 수 있다. 

result = posting_mysql.select_data("*", 'item_savepoint', 'item_savepoint')
print(result)

 

[('000020', '20210608'), ('000040', '20210608'), ('000050', '20210608'), ····

결과값을 보니 전체적으로는 []와 같은 리스트 형식으로 되어 있고, 그 안에는 두 개의 값이 짝을 지어서 들어가 있다는 것을 확인할 수 있다. 이러한 자료형에서 특정 값을 이용하는 방법이 있는데, 아래의 사진을 참고해보자.

result[0]을 쓰면 (000020, 20210608)이라는 두 개의 값을 얻어오지만 result[0][0]을 쓰면 000020을, result[0][1]을 쓰면 20210608을 얻어온다는 것이다. 여기서 우리는 특정 종목코드의 일봉 차트 데이터가 저장된 최신 일자를 얻어올 수 있는 것이다. 

그렇다면 select_data 함수로 전달하는 변수 중 첫 번째 자리에 *이 아닌 code를 넣어주면 어떤 결과가 출력될까?

result = posting_mysql.select_data("code", 'item_savepoint', 'item_savepoint')
print(result)

 

[('000020',), ('000040',), ('000050',), ('000060',), ('000070',), ('000080',), ('000100',),

맨 처음에 '*'을 입력했던 때와는 달리, 날짜는 출력되지 않고 칼럼명이 'code'인 칼럼 아래에 있는 데이터(종목 코드)만 출력되는 모습을 확인할 수 있다. 그런데 이상하게도, 종목 코드는 000020을 입력헀는데 '000020'이 출력되는 모습을 확인할 수 있다. 하지만 위에서 살펴봤듯이, result[0][0]를 사용하면 000020이 출력된다.

 


728x90

 

 

차트 데이터 이어받기 코드 구축

일단 정말 아주 예전에 작성했던 filtered_code() 함수를 통해 종목코드를 불러온 후에, 우리가 SELECT문을 통해 불러온 종목 코드들이 filtered_code()를 통해 얻은 종목코드 리스트 안에 있는지를 확인해야 한다. 왜냐하면, 새로운 상장 종목이 있는 경우에는 별도로 item_savepoint 내에 종목 코드를 집어넣어주어야 하기 때문이다.

물론 이와 관련하여, 차트 데이터를 조회하기 전에 앞서 filtered_code() 함수의 결과값을 조회한 후에 그 결과값 안에 포함된 종목 코드를 item_savepoint 데이터베이스에 입력하도록 하는 절차를 거친 후에 차트 데이터를 조회하겠다면 문제가 없겠지만 만약 그렇지 않은 경우에는 우리의 item_savepoint 내에 있는 종목코드가 filtered_code에 있는지 없는지를 확인한 후에 차트 데이터를 조회해야 한다. 말이 조금 어려운데, 아래의 그림을 통해 이해해보도록 하자.

위의 상황은 filtered_code() 함수 내에서 종목 코드들을 조회한 후에, item_savepoint 데이터베이스에 개별 종목 코드들을 저장한 후 rq_chart_data를 사용하는 경우이기 때문에 문제가 발생하지 않는 상황이다. 하지만 우리는 지금 위에서 보았듯이 filtered_code()를 먼저 실행한 것이 아니라, item_savepoint()에 저장되어 있는 데이터를 먼저 불러온 것이기 때문에 그 여부를 확인해주어야 한다는 것이다. 즉, 아래의 그림과 같은 상황이 발생하게 된다.

즉 item_savepoint 안에 있는 종목 코드들을 대상으로 차트 저장 일자를 확인한 후에 곧바로 rq_chart_data를 실행하는 것이기 때문에, 위의 사진처럼 item_savepoint 데이터베이스에는 없는 '000050'이라는 종목이 filtered_code() 함수에서는 갖고 있는 종목이라면, 우리는 '000050'이라는 종목을 빠뜨린 채로 데이터를 업데이트하는 것이 되기 때문이다. 그렇기 때문에 item_savepoint 안에 있는 종목들을 하나 하나 차트 데이터를 요청할 때, filtered_code()에 있는 종목이라면 차트 데이터만 요청하면 되지만 만약 item_savepoint 안에는 없는데 filtered_code() 안에는 있는 종목이라면 item_savepoint 데이터베이스 안에 해당 종목 코드를 입력해주어야 그 종목의 차트 데이터를 조회하고 저장한 후에 날짜를 입력할 수 있는 것이다.

그렇다면 우리는 일단 filtered_code()를 대상으로 for문을 돌리되, 그 for문을 돌 때마다의 종목코드가 item_savepoint 안에 있는 종목 코드인지를 확인한 후, 그 코드가 없다면 새롭게 데이터를 입력한 후에 차트 데이터를 조회하면 된다. 따라서 맨 처음에는 가볍게, filtered_code() 함수를 대상으로 for문을 돌리는 것부터 시작하도록 하자.

code_list = trade.filtered_code()
result = posting_mysql.select_data('code', 'item_savepoint', 'item_savepoint')

for code in code_list:

이제 filtered_code()가 뿜어낸 code가 result라는 결과값 안에 있는 것인지 없는 것인지 그 여부를 판단하면 된다. 이제 아래의 코드를 실행해보자.

for code in code_list:
	print(code)

	if code in result:
		print("안에 있음")
	else:
		print("안에 없음")

 

000020
안에 없음
000040
안에 없음
000050
안에 없음
000060
안에 없음
000070
안에 없음
000080
안에 없음
000100
안에 없음

뭔가 이상하다. 우리는 분명히 item_savepoint 안에 모든 종목에 대한 데이터를 입력했는데도 불구하고 000020도 없고, 000040도 없고, 000100도 없고 아무 것도 없다고 나온다. 왜 이럴까? 그 이유는 위에서 이미 확인했었다. 즉, 지금 우리의 result 안에 있는 값들은 모두 '000020' 형태이지만 filtered_code() 안에 있는 종목 코드들은 모두 000020 형태이다. 즉, 괄호가 있냐 없냐가 달라서 인식을 못하는 것이다. 그렇다면 우리는 item_savepoint 안에 있는 종목 코드들을 모두 000020 형태로 바꾸어서 반환해줄 필요가 있는데, 이 역시 여기 저기서 자주 사용하게 되는 함수이니 따로 또 제작해주도록 하자.

def codelist_inDB():
	result = select_data("code", 'item_savepoint', 'item_savepoint')
	code_list = []

	for data in result:
		code = data[0]
		code_list.append(code)
	return code_list

함수 이름은 codelit_inDB로 설정했고, 같은 파일 안에 있는 select_data 함수를 이용해서 결과값(result)을 얻어온 후에, result 값을 대상으로 for문을 돌면서 앞에 있는 값을 code에 넣고, code_list에 그 code 값을 입력한 후에 code_list를 반환하는 함수이다. 말로 하니 진짜 드럽게 이해 안 되는데, 한 군데에 break point를 찍어놓고 디버그로 돌려보면 손 쉽게 이해할 수 있다.

그렇다면 이제 다시 원래의 파일로 돌아와서 기존에 제작했던 result = posting_mysql.select_data("code", 'item_savepoint', 'item_savepoint') 부분을 삭제하고 아래의 코드로 대체해주도록 하자.

result = posting_mysql.codelist_inDB()

 

이제 다시 바뀐 코드를 실행해보면 아래와 같이 출력이 잘 되는 모습을 확인할 수 있다!

code_list = trade.filtered_code()
result = posting_mysql.codelist_inDB()

for code in code_list:
	print(code)

	if code in result:
		print("안에 있음")
	else:
		print("안에 없음")

 

000020
안에 있음
000040
안에 있음
000050
안에 있음
000060
안에 있음
000070
안에 있음
000080
안에 있음
000100
안에 있음

 

이번 포스팅도 예기치 않게 그림까지 만들어가며 설명하는 바람에 길이가 너무 길어지게 되어 여기까지만 제작하는 것으로 하고, 다음 포스팅에서는 본격적으로 if문과 else문을 제작할 예정이다.

 

 


728x90
반응형
Contents

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

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