6. 주식 단타 전략 모니터링 시스템 - 파이썬 자동 감지 프로그램(2)
파이썬 자동 감지 프로그램
2022.10.25 - [개발기록] - 주식 단타 전략 모니터링 시스템 개발 일지 - 5. 자동 감지 프로그램(1)
앞서 말한 고려사항 중
1. 날짜가 바뀔 때 마다 전날 데이터를 새로 수집해야 하는지
2. 주식 시장이 열릴 때 일일이 실행시켜주어야 하는지
3. 실행시켰을 때 반복적으로 같은 종목이 출력되는 부분
4. 실행 내역과 모니터링 내역의 로그 기록
5. 카카오톡 API로 나에게 메세지 보내기
6. 카카오톡 API 토큰 자동 갱신
밑줄 친 4개 항목에서 수정을 하겠다.
그럼 필요한 패키지 두 개가 있다.
import datetime as dt
import time
현재 시간을 불러주는 datetime과 시간과 관련된 time 패키지를 import 한다.
while True:
for t_i in kospi_data["Symbol"]:
t_n = kospi_data[kospi_data["Symbol"]==t_i]["Name"].values[0]
price_data = fdr.DataReader(t_i, t_date).tail(1)
price_data.insert(0,"Symbol",t_i)
price_data.insert(0,"Name",t_n)
target_band = before_price[before_price["Symbol"]==t_i]["range"].values[0]
price_data["Price_stand"] = price_data["Open"] + int(target_range*1.5)
base_price = price_data["Price_stand"].values[0]
current_price = price_data["Close"].values[0]
if current_price >= base_price:
print(t_n, current_price, base_price,target_band)
전 글에서 사용한 코드인데, 이 기준으로 추가된 부분을 설명하겠다.
먼저 전체 코드.
while True:
x = dt.datetime.now()
file_name = "./monitoring_log/"+str(x.month) + str(x.day) +"_kospi_log"
time_log = str(x.month)+"월"+str(x.day)+"일 "+str(x.hour%24+9)+":"+str(x.minute)
if x.hour+9 >=9 and x.hour+9 <16:
with open(file_name+'.txt', 'a') as f:
f.write(time_log + " --- Monitoring 종목 개수 : "+ str(kospi_data.shape[0])+"\n")
set_before = True
print(x.hour+9,x.minute)
for t_i in kospi_data["Symbol"]:
t_n = kospi_data[kospi_data["Symbol"]==t_i]["Name"].values[0]
price_data = fdr.DataReader(t_i, t_date).tail(1)
date = price_data.index
if t_date != date : t_date = str(price_data.index)[16:26]
price_data.insert(0,"Symbol",t_i)
price_data.insert(0,"Name",t_n)
target_band = before_price[before_price["Symbol"]==t_i]["range"].values[0]
price_data["Price_stand"] = price_data["Open"] + int(target_band*1.5)
base_price = price_data["Price_stand"].values[0]
current_price = price_data["Close"].values[0]
bot_log = (time_log + " ### 프로그램 log test ### 종목명 : " + t_n + " / 종목코드 : " + t_i +
" / 현재가격 : " + str(current_price) + " / 기준가격 : " + str(base_price) +
" / Range : " +str(target_band) +"\n")
#log test
with open(file_name+'_kospi_test.txt', 'a') as f:
f.write(bot_log)
if current_price >= base_price:
kospi_data = kospi_data[kospi_data["Symbol"]!=t_i]
print(t_n, current_price, base_price,target_band)
with open(file_name+'.txt', 'a') as f:
f.write(bot_log)
elif x.hour+9 == 16 and x.minute >= 10 and set_before == True:
print(x.month, x.day,x.hour+9,x.minute)
price_data = fdr.DataReader(t_i, t_date)
t_date = str(price_data.tail(1).index)[16:26]
kospi_data = df_krx[df_krx["Market"].str.contains("KOSPI")]
kospi_data = kospi_data[kospi_data["Name"].isin(kospi_200_list[kospi_200_list["Symbol"]==102110].STK_NM_KOR)]
before_price = None
for t_i2 in kospi_data["Symbol"]:
t_n = kospi_data[kospi_data["Symbol"]==t_i2]["Name"].values[0]
price_data = fdr.DataReader(t_i2, t_date)
price_data.insert(0,"Symbol",t_i2)
price_data.insert(0,"Name",t_n)
before_price = pd.concat([before_price,price_data.tail(1)],axis = 0)
before_price["range"] = before_price["High"] - before_price["Low"]
set_before = False
print(x.month,x.day,"completed")
before_price.to_csv("./before_data/before_data_kospi"+str(x.month)+str(x.day)+".csv")
with open(file_name+'.txt', 'a') as f:
f.write(time_log + ' --- Before_data_kospi를 갱신했습니다.' +"\n")
else:
with open(file_name+'.txt', 'a') as f:
f.write(time_log + ' --- 거래시간이 아닙니다. 프로그램 대기중' +"\n")
time.sleep(60)
수정한 부분씩 차례로 설명해보겠다.
2. 주식 시장이 열릴 때 일일이 실행시켜주어야 하는지
우선 dt.datatime.now() 함수는 현재 시간을 알 수 있다.
표준시로 출력이 됨으로 한국 시간에 맞춰서 사용해야 한다.
datetime으로 알 수 있는 건 년, 월, 일, 시간, 분, 초 정보이다.
이중에 필요한 건 hour, minute이다.
while True:
x = dt.datetime.now()
time_log = str(x.month)+"월"+str(x.day)+"일 "+str(x.hour%24+9)+":"+str(x.minute)
if x.hour+9 >=9 and x.hour+9 <16:
print(x.hour+9,x.minute)
elif x.hour+9 == 16 and x.minute >= 10 and set_before == True:
print(x.hour+9,x.minute)
set_before = False
else:
print(x.hour+9,x.minute)
time.sleep(60)
datetime과 관련된 부분을 뽑아서 보면 if 문에서 사용하고 있다.
hour에 9를 더해준 것은 한국시간에 맞추기 위해서이다.
첫 번째 if 문을 보면 한국시간 기준으로 9시~16시 사이에 해당될 때, 해당 조건문이 실행이 된다.
즉, 주식 개장 시간과 동일하다.(3시반까지지만 4시까지 거래가 가능하기에)
그다음 elif 조건은 16시 10분이 넘어가는 시점에 실행되는 조건문이다.
여기서는 당일 주식시장이 끝난 후 주가 데이터를 수집하기 위함이다.
따라서 한 번 실행된 후 set_before 값이 False로 바뀌며 실행되지 않는다.
세 번째 else는 그 외 시간에서 실행되며 아무 작업도 하지 않는다.
주식시장이 폐장했기 때문에 프로그램도 대기 상태로 만들기 위함이다.
여기서 time 패키지의 sleep을 60초씩 걸어둔다.
무의미한 루프를 계속 돌릴 필요가 없기 때문에 1분에 한 번씩만 상태 점검차 실행한다.
조건문을 위와 같이 구현하면 주식 시장 시간에 맞춰 봇이 감지를 시작하고 폐장하면 봇도 대기 상태로 바뀌는 프로그램을 구현할 수 있다.
비록 휴일에도 실행된다는 단점이 있지만, 휴일을 지정해주어야 하는 문제가 있기 때문에 큰 문제가 없는 한 이대로 실행해도 될 것 같다.
1. 날짜가 바뀔 때마다 전날 데이터를 새로 수집해야 하는지
이제 전날 데이터를 주식시장이 폐장 시 실행시켜 준비를 해놓아야 한다.
방금의 조건문에서 elif 조건을 보면 16시 10분이 넘어가면 한 번 실행한다 했다.
이때 다음날 사용하기 위한 데이터를 수집하는 것이다.
elif x.hour+9 == 16 and x.minute >= 10 and set_before == True:
print(x.month, x.day,x.hour+9,x.minute)
price_data = fdr.DataReader(t_i, t_date)
t_date = str(price_data.tail(1).index)[16:26]
kospi_data = df_krx[df_krx["Market"].str.contains("KOSPI")]
kospi_data = kospi_data[kospi_data["Name"].isin(kospi_200_list[kospi_200_list["Symbol"]==102110].STK_NM_KOR)]
before_price = None
for t_i2 in kospi_data["Symbol"]:
t_n = kospi_data[kospi_data["Symbol"]==t_i2]["Name"].values[0]
price_data = fdr.DataReader(t_i2, t_date)
price_data.insert(0,"Symbol",t_i2)
price_data.insert(0,"Name",t_n)
before_price = pd.concat([before_price,price_data.tail(1)],axis = 0)
before_price["range"] = before_price["High"] - before_price["Low"]
set_before = False
print(x.month,x.day,"completed")
해당 조건문만 따로 빼내 와서 보자.
현재 일 기준으로 데이터를 수집해야 하기 때문에 아무 종목이나 데이터를 한번 수집하고, 가장 최근 날짜로 업데이트해준다.
price_data = fdr.DataReader(t_i, t_date)
t_date = str(price_data.tail(1).index)[16:26]
.tail(1)을 사용한 이유가 가장 최신 데이터가 맨 아래에 있기 때문이다. 여기서 문자열의 위치를 지정해 날짜만 추출한다.
그다음 대상 종목을 재지정해주고, 전날 가격으로 사용할 데이터를 수집한다.
해당 코드는 이전 글에 설명했던 코드와 동일하다.
2022.10.25 - [개발기록] - 주식 단타 전략 모니터링 시스템 개발 일지 - 5. 자동 감지 프로그램(1)
혹시 모를 에러에 대비해 해당 데이터를 저장한다.
그리고 set_before값을 False로 바꿔 elif문이 다시 실행되지 않도록 바꾼다.
set_before값은 다음날이 되어 주식 시장이 개장하면 다시 True로 바뀌게 설정해놓았다.
이렇게 전날 가격 데이터도 자동으로 수집할 수 있게 구현했다.
3. 실행시켰을 때 반복적으로 같은 종목이 출력되는 부분
같은 종목이 반복적으로 출력되지 않게 하는 방법은 간단하다.
if current_price >= buy_price :
kospi_data = kospi_data[kospi_data["Symbol"]!=t_i]
print(t_n, current_price, buy_price,target_band)
현재 가격이 기준이 매수 기준 가격보다 높아지면 print문으로 출력하도록 조건을 걸어놓았는데, 여기서 출력되는 종목을 감지 대상 종목 리스트에서 제외하면 된다.
4. 실행 내역과 모니터링 내역의 로그 기록
프로그램이 잘 돌아가는지 로그를 남기는 것도 중요하다.
출력되는 결과물을 일 별로 저장하면서 오류 여부를 찾아야 하기 때문이다.
해당 부분 코드만 뽑아서 보면
while True:
x = dt.datetime.now()
file_name = "./monitoring_log/"+str(x.month) + str(x.day) +"_kospi_log"
time_log = str(x.month)+"월"+str(x.day)+"일 "+str(x.hour%24+9)+":"+str(x.minute)
if x.hour+9 >=9 and x.hour+9 <16:
with open(file_name+'.txt', 'a') as f:
f.write(time_log + " --- Monitoring 종목 개수 : "+ str(kospi_data.shape[0])+"\n")
for t_i in kospi_data["Symbol"]:
bot_log = (time_log + " ### 프로그램 log test ### 종목명 : " + t_n + " / 종목코드 : " + t_i +
" / 현재가격 : " + str(current_price) + " / 기준가격 : " + str(base_price) +
" / Range : " +str(target_band) +"\n")
with open(file_name+'_test.txt', 'a') as f:
f.write(bot_log)
if current_price >= base_price:
kospi_data = kospi_data[kospi_data["Symbol"]!=t_i]
print(t_n, current_price, base_price,target_band)
with open(file_name+'.txt', 'a') as f:
f.write(bot_log)
elif x.hour+9 == 16 and x.minute >= 10 and set_before == True:
with open(file_name+'.txt', 'a') as f:
f.write(time_log + ' --- Before_data_kospi를 갱신했습니다.' +"\n")
else:
with open(file_name+'.txt', 'a') as f:
f.write(time_log + ' --- 거래시간이 아닙니다. 프로그램 대기중' +"\n")
time.sleep(60)
file_name의 경우 날짜 별로 저장하기 위해 datetime에서 month와 day를 사용해 양식을 만들었다.
time_log의 경우 저장하는 시간을 체크하기 위해 월, 일, 시간, 분을 조합해 만들었다.
생성되는 파일은 두 개다.
프로그램이 잘 실행되고 감지되는 종목을 기록하는 "filename".txt 파일과
모니터링이 잘 되고 있는지 모든 종목을 기록하는 "filename_test".txt파일이다.
전체 감지 대상 종목이 200개라 할 때, 200개를 한 번 볼 때마다 몇 개가 감지되는지 종목 개수를 출력하다.
개수를 출력하는 이유는 매수 사인이 난 종목을 출력 후 해당 종목을 감지 대상에서 제외하는데 그럼 199개가 감지되고 있는지 확인하기 위함이다.
bot_log에 모니터링하는 종목, 가격 등을 기록한 후
with open (file_name.... 부터 시작하는 코드에서 각각 해당 파일에 기록한다.
전날 가격 데이터를 생성하거나, 거래시간이 아닐 때도 기록해 프로그램이 잘 실행되고 있는지 체크하도록 하였다.
이렇게 실행되고 있는 목록이다.
프로그램을 실행시켜 놓으면 날짜가 바뀌며 자동으로 저장되도록 구현되어 있다.
한 가지, 표준시간 +9로 사용하고 있기 때문에 날짜도 9시간 후에 바뀐다.
즉, 주식 시장이 개장하면 표준 날짜가 바뀌기 때문에 9시부터 해당 거래일을 로그가 저장된다.
나는 이게 보기 편해서 그대로 사용하고 있다.
작업했던 결과를 보면
2개 종목이 감지되어 추천한 후 폐장시간까지 기준가를 넘는 종목이 없어 모니터링만 지속한다.
16시가 넘는 시점부터 잠시 대기하다가 16시 10분 시점에 전날 가격으로 사용할 데이터를 갱신한다.
그 후 다음 거래 시작시간까지 대기상태에 돌입한다.
여기까지 주요 내용에 대해선 구현이 되었다.
이제 남은 것은
5. 카카오톡 API로 나에게 메세지 보내기
6. 카카오톡 API 토큰 자동 갱신
두 항목인데..
글이 너무 길어져 다음 글에서 다루겠다.
카카오톡 API까지 구현하고 나면 생각했던 대부분 기능을 구현하는 것 같다.
해당 내용을 소개한 후 앞으로 모니터링 시스템을 어떻게 발전시킬지 정리해보겠다.