목 차
1. 들어가며
2. 사전 준비
1) Slow %K 및 %D 산출식
2) Slow %K 및 %D 값
3) Slow %K 및 %D 계산하기(엑셀)
3. 코드 설명
4. 전체코드
5. 마치며
1. 들어가며
지난 글에서는 스토캐스틱 패스트 %K, %D 구하는 방법을 알아보았다. 지수이동평균을 구하는 부분이 약간 어렵게 느껴지겠지만, 몇 번 연습하다보면 그 개념과 코드를 이해할 수 있으리라 생각된다.
이번 글에서는 스토캐스틱 슬로우 %K, %D 구하는 방법을 알아보자. 지난 글에서 for문, list 항목 추가 등 충분한 설명을 했으므로, 이번 글에서는 중복되는 내용 등은 생략한다.
※ 코드의 연속성을 위해 스토캐스틱 패스트 %K, %D 코드에 스토캐스틱 슬로우 %K, %D 코드를 추가할 것이다. 지난 글과 중복되는 내용(패스트 %K, %D 구하기)은 설명을 생략한다.
2. 사전 준비
1) Slow %K 및 %D 산출식
스토캐스틱 보조지표에 대해 처음 설명할 때 한번 언급한 적이 있지만, 키움증권에서의 슬로우 %K는 타 증권사와 그 결과값이 다르다. 이유는? Slow %K를 구할 때 "Fast %D의 이동평균값"을 취하지 않고, "키움증권에서 자체 계산한 값"을 취하기 때문이다. (https://springcoming.tistory.com/210)
- 스토캐스틱 패스트 %K : (현재가격 - n분(일) 중 최저가) / ( n분(일) 중 최고가 - n분(일) 중 최저가) * 100
- 스토캐스틱 패스트 %D : 패스트 %K를 m분(일) 로 지수이동평균한 값
- 스토캐스틱 슬로우 %K : 패스트 %D를 m분(일)로 이동평균한값 → 키움증권식 계산한 값
- 스토캐스틱 슬로우 %D : 슬로우 %K를 m분(일)로 지수이동평균한 값
- 스토캐스틱 오실레이터 : 패스트 %D - 슬로우 %D
키움증권을 이용하고 있는 필자로서는 울며겨자먹기 식으로 Slow %K는 "키움 자체 계산 값"을 구해야 할 것 같다. 여기서는 슬로우 %K와 %D를 구할 것이다.
- 키움자체 Slow %K = sum(현재가 - n분중 최저가) / sum( n분중 최고가 - n분중 최저가) * 100
키움증권 1분봉 데이터의 스토캐스틱 슬로우 설정기간은 12분, 5분, 5분이다.
2) Slow %K 및 %D 값
우리가 파이썬 코딩을 통해 구하고자 하는 값은 2023년 9월 30일(토)의 05:59분에 해당하는 Slow %K인 20.29와 Slow %D인 27.16이다.
3) Slow %K 및 %D 계산하기(엑셀)
슬로우 %K 및 %D를 구하는 방법을 생각해 보았다. 슬로우 %K의 기간은 < 그림1-2 >에서 확인하였듯이 12분, 5분이다.
이 말은 12분 내 최고값 및 최저값을 구한다는 말이다.
- 키움자체 Slow %K = sum(현재가 - n분중 최저가) / sum( n분중 최고가 - n분중 최저가) * 100
- 스토캐스틱 슬로우 %D : 슬로우 %K를 m분(일)로 지수이동평균한 값
키움증권에서는 역순으로 자료를 제공하므로 12분 동안의 최고/최저가이며, 5분 간격으로 분자/분모를 구한다.
- 05:59분 종가 14891.5(F열601줄)에 따른 최고가는 D590~601(12개), 최저가는 E590~601(12개)에서 산출된다.
- 05:58분 종가 14894.25(F열600줄)에 따른 최고가는 D589~600(12개), 최저가는 E589~600(12개)에서 산출된다.
- ...
- 05:55분 종가 14899(F열597줄)에 따른 최고가는 D586~597(12개), 최저가는 E586~597(12개)에서 산출된다.
5분 동안(05:59~05:55) 각각 종가, 최고가, 최저가 등이 결정되면 그 값들을 더하고 나서 100을 곱해주면 Slow %K가 된다.
즉, Slow %K의 분자는 SUM[(05:59분종가 - 05:59분최저가) + (05:58분종가 - 05:58분최저가) + ... + (05:55분종가 - 05:55분최저가)]이고, Slow %K의 분모는 SUM[(05:59분최고가 - 05:59분최저가) + (05:58분최고가 - 05:58분최저가) + ... + (05:55분최고가 - 05:55분최저가)]이다.
정리하면 Slow %K = (분자의 합) / (분모의 합) *100 = 20.29가 나온다.
3. 코드 설명
전체본 캡쳐를 해놓고보니, 중복된 내용이 너무 많다. ㅠㅠ. 해당 내용만 발췌해서 설명하면 코드 흐름이 끊길거 같고... 이래저래 고민이다. 일단 풀 버전으로 설명한다.
※ 라이브러리, 로그인, opc10002(1분봉 받기), Stochastic Fast %K, %D에 관한 내용은 중복이므로 여기서는 설명하지 않을 예정이다.
1줄~18줄 : 활용할 라이브러리 및 로그인에 관련 내용으로 설명을 생략한다.
20줄~31줄 : %K, %D를 구하기 위해 미리 리스트형 변수를 선언한다.
33줄~41줄 : 스토캐스틱 패스트/슬로우/오실레이터를 산출을 위해 지수이동평균시 활용되는 가중치 및 리스트형 변수를 미리 선언한다.
50줄~64줄 : 1분봉 데이터 입력/요청/조회하는 함수이다.
68줄~107줄 : 스토캐스틱 패스트 %K 및 %D를 구하는 내용이다. (설명 생략)
여기서부터 자세히 설명한다. 짤린 부분은 4번(전체코드)에서 확인가능하다. Slow %K의 기간은 12분, 5분이다.
- 키움자체 Slow %K = sum(현재가 - n분중 최저가) / sum( n분중 최고가 - n분중 최저가) * 100로 계산%K
- 스토캐스틱 슬로우 %D : 슬로우 %K를 m분(일)로 지수이동평균한 값
110줄~112줄 : 3중 for문을 활용하였다. 이유는? 2중 for문으로 1개의 %K는 구할 수 있다. 하지만 %D까지 구하려면, 2중 for문으로 구한 %K를 지수이동평균하여야 하기 때문에 for문을 한번 더 돌려서, 3중 for문이 되는 것이다.
110줄 : 슬로우 %D를 구하기 위해 30회 for문을 돌려준다. 아래에서 설명할 것이다.
111줄~112줄 : 이 글의 핵심이다. %K의 기간이 12분, 5분인 것을 반드시 기억하자. k=0일 때 (현재가-최저가) 및 (최고가-최저가)가 나올 것이다. 이것을 2번째 for문을 통해 5번 돌린다(j)는 뜻이다. 5번 돌려야 하는 이유? %K의 기간이 12분, 5분인 것을 기억하자! 즉 k=0일 때 분자0와 분모0, k=1일 때 분자1와 분모1, ... , k=4일 때 분자4와 분모4로 나올 것이다.
키움측 자체 Slow %K = (분자0+분자1+...+분자4) / (분모0+분모1+...+분모4) * 100을 하라는 뜻이다.
* 여기서 분자는 (현재가-5분중 최저가)의 각각의 합계이고, 분모는 (5분중 최고가-5분중 최저가)의 각각의 합계이다.
113줄~115줄 : 현재가, 최고/최저값을 구한다.
116줄~117줄 : 12줄 이내 최고값과 최저값을 20줄에서 선언한 self.nq_max_prcie_list 리스트에 넣는다.
121줄~122줄 : 리스트 내 최고값/최저값을 찾는다.
124줄~125줄 : 이미 사용한 리스트를 각각 초기화 한다.
127줄~128줄 : 키움자체 Slow %K의 분자와 분모를 각각 구하기 위해 (현재가-최저가) 및 (최고가-최저가)를 계산한다.
130줄~131줄 : 각각의 분자 및 분모를 리스트에 넣는다.
133줄~134줄 : 리스트 내에 있는 (현재가-최저가)모음 및 (최고가-최저가)모음을 각각 합산한다.
136줄~137줄 : 이미 사용한 리스트를 초기화한다.
139줄~146줄 : Stochastic %K 값을 구한다.
148줄 : 이 글의 두번째 핵심이다. 슬로우 %D를 구하기 위해 리스트(최근→과거)를 역산(과거→최근)한다. 이유는? 지수이동평균은 시계열 순서(과거→최근)으로 되어 있어야, 앞에서 계산한 값을 뒤에서 "가중치"를 둘 수 있기 때문이다.
151줄~156줄 : %F가 모여있는 리스트(148줄, self.stc_slow_d_list)에서 %F 값을 하나씩 가지고 와서, 지수이동평균 계산을 한다.
158줄 : 슬로우 %D를 소수 셋째자리에서 반올림한다.
159줄 : 이미 사용한 self.stc_slow_d_list를 초기화한다.
위의 값을 계산하면, 아래와 같이 나온다.
- 패스트 %K는 3.12(엑셀에는 3.13), 패스트 %D는 14.26(엑셀에는 14.27)
- 슬로우 %K는 20.29(엑셀에는 20.29), 슬로우 %D는 27.16(엑셀에는 27.16)
3.12
14.26
20.29
27.16
4. 전체코드
전체코드는 아래와 같다. 아래의 코드를 실행하려면, 키움증권에 시세 이용료(월 $185)를 지불하여야 한다.
import sys
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class btl_system():
def __init__(self):
self.kiwoom = QAxWidget("KFOPENAPI.KFOpenAPICtrl.1")
print("로그인 시작!")
self.kiwoom.dynamicCall("CommConnect(1)") # CommConnect() : 괄호 안에 자동(1)을 넣는다.
self.kiwoom.OnEventConnect.connect(self.login_Connect)
self.kiwoom.OnReceiveTrData.connect(self.trdata_get)
self.login_event_loop = QEventLoop()
self.login_event_loop.exec_()
self.kiwoom.dynamicCall("GetCommonFunc(QString, QString)", "ShowAccountWindow", "") # 계좌번호 입력창을 띄우는 내부함수
self.nq_max_price_list = []
self.nq_min_price_list = []
self.stc_fast_d_list = []
self.stc_slow_k_list_close_min = []
self.stc_slow_k_list_max_min = []
self.stc_slow_d_list_row = []
self.stc_slow_d_list = []
self.stc_slow_k_forth_list = []
self.stc_fast_k_weighting = 2 / (3 + 1)
self.stc_slow_d_weighting = 2 / (5 + 1)
self.stc_oscillator_d_weighting = 2 / (26+1)
self.stc_oscillator_d_9_weighting = 2 / (9+1)
self.stc_slow_oscillator_k_26_close_min_list = []
self.stc_slow_oscillator_k_26_max_min_list = []
self.stc_slow_oscillator_final = []
def login_Connect(self, err_code):
if err_code == 0:
print('로그인 성공했습니다!')
else:
print('로그인 실패했습니다!')
self.login_event_loop.exit()
########## 키움서버에 TR 요청하는 함수 모음 ##########
def rq_data_opc10002(self, stock_code_num, time_unit): # 1분봉 데이터 조회
self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "종목코드", stock_code_num)
self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "시간단위", time_unit)
self.kiwoom.dynamicCall("CommRqData(QString, QString, QString, QString)", "opc_10002", "opc10002", "", "1002")
self.tr_event_loop = QEventLoop()
self.tr_event_loop.exec_()
########## OnReceiveTrData을 통해 수신받은 데이터 함수 ##########
def trdata_get(self, scrno, rqname, trcode, recordname, prenext):
if rqname == "opc_10002":
self.tr_event_loop.exit()
btl.stochastic_searching()
def stochastic_searching(self):
########## 스토캐스틱 패스트 %K, %D ##########
for i in range(0, 30): # 현재 분의 STC_패스트 K, D 구하기
for j in range(i, i + 5):
self.close_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "현재가").strip()))
max_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", j, "고가").strip()))
min_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", j, "저가").strip()))
self.nq_max_price_list.append(max_price_row_data)
self.nq_min_price_list.append(min_price_row_data)
self.close_price_first = self.close_price_row_data
self.max_price_first = max(self.nq_max_price_list)
self.min_price_first = min(self.nq_min_price_list)
self.nq_max_price_list = []
self.nq_min_price_list = []
self.stc_fast_k_first = (self.close_price_first - self.min_price_first) / (self.max_price_first - self.min_price_first) * 100
self.stc_fast_k_first = round(self.stc_fast_k_first, 2) # 소수 셋째자리에서 반올림
self.stc_fast_d_list.append(self.stc_fast_k_first)
self.stc_fast_d_list_final = self.stc_fast_d_list[::-1]
self.stc_fast_k = self.stc_fast_d_list_final[29]
self.stc_fast_d_list = []
for i in range(len(self.stc_fast_d_list_final)):
if i == 0:
self.stc_fast_d_first = self.stc_fast_d_list_final[i]
elif i >= 1:
self.stc_fast_d_second = (self.stc_fast_d_list_final[i] * self.stc_fast_k_weighting) + (self.stc_fast_d_first * (1 - self.stc_fast_k_weighting))
self.stc_fast_d_first = self.stc_fast_d_second
self.stc_fast_d_list_final = []
self.stc_fast_k = round(self.stc_fast_k, 2)
self.stc_fast_d = round(self.stc_fast_d_second, 2)
print(self.stc_fast_k)
print(self.stc_fast_d)
########## 스토캐스틱 슬로우 %K, %D ##########
for i in range(0, 30):
for j in range(i, i+5): # 현재 분의 STC_슬로우 K, D 구하기 /// stc_slow_k = ∑(현재가 - 최대값) / ∑(최대값 - 최소값)
for k in range(j, j + 12):
self.close_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", j, "현재가").strip()))
max_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", k, "고가").strip()))
min_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", k, "저가").strip()))
self.nq_max_price_list.append(max_price_row_data)
self.nq_min_price_list.append(min_price_row_data)
self.close_price_first = self.close_price_row_data
self.max_price_first = max(self.nq_max_price_list)
self.min_price_first = min(self.nq_min_price_list)
self.nq_max_price_list = []
self.nq_min_price_list = []
self.price_first_close_min = self.close_price_first - self.min_price_first
self.price_first_max_min = self.max_price_first - self.min_price_first
self.stc_slow_k_list_close_min.append(self.price_first_close_min)
self.stc_slow_k_list_max_min.append(self.price_first_max_min)
self.stc_slow_k_first = sum(self.stc_slow_k_list_close_min)
self.stc_slow_k_second = sum(self.stc_slow_k_list_max_min)
self.stc_slow_k_list_close_min = []
self.stc_slow_k_list_max_min = []
self.stc_slow_k_third = self.stc_slow_k_first / self.stc_slow_k_second * 100
self.stc_slow_k_third = round(self.stc_slow_k_third, 2)
self.stc_slow_k_forth_list.append(self.stc_slow_k_third)
if i == 0:
self.stc_slow_k = self.stc_slow_k_forth_list[0]
elif i == 1:
self.stc_slow_k_1_ago = self.stc_slow_k_forth_list[1]
self.stc_slow_d_list = self.stc_slow_k_forth_list[::-1]
self.stc_slow_k_forth_list = []
for i in range(0, 30):
if i == 0:
self.stc_slow_d_first = self.stc_slow_d_list[i]
elif i >= 1:
self.stc_slow_d_second = (self.stc_slow_d_list[i] * self.stc_slow_d_weighting) + (self.stc_slow_d_first * (1 - self.stc_slow_d_weighting))
self.stc_slow_d_first = self.stc_slow_d_second
self.stc_slow_d = round(self.stc_slow_d_first, 2)
self.stc_slow_d_list = []
print(self.stc_slow_k)
print(self.stc_slow_d)
if __name__ == "__main__":
app = QApplication(sys.argv)
btl = btl_system()
btl.rq_data_opc10002("NQZ23", "1")
app.exec_()
5. 마치며
지금까지 Stochastic Slow %K 및 %D 구하는 방법을 알아보았다. 사실 Slow %K 때문에 3시간 정도 헤맸던 것 같다. 이유는? 인터넷 검색을 해보니 "Slow %K = Fast %D 이동평균"이라고 해서 엑셀로 구해보니, 값이 다른 것이었다. 어떻게 된거지??? 한창을 검색 및 고민하다가 "키움자체 Slow %K 값으로 계산한다"는 검색 결과에 약간 허무했다. 그래도 이번 기회에 증권사별로 다를 수 있다는 내용을 이렇게 알게 되어서 다행이다.! ^^
다음 글에서는 Stochastic 관련 마지막 내용으로 Stochastic Oscillator에 대해 알아보도록 하자.
'2. 해외선물 > 2-4. 해외선물 API (사용)' 카테고리의 다른 글
(키움증권 해외선물 OpenAPI-W) 일목균형표 구하기 (2) 일목균형표 값 구하기(전환선, 기준선, 후행스팬, 선행스팬1, 선행스팬2) (0) | 2023.12.15 |
---|---|
(키움증권 해외선물 OpenAPI-W) 일목균형표 구하기 (1) 일목균형표 개념 및 산출식 (0) | 2023.12.14 |
(키움증권 해외선물 OpenAPI-W) 스토캐스틱(Stochastic) 값 구하기 (4) 스토캐스틱 오실레이터(Stochastic Oscilla (1) | 2023.10.04 |
(키움증권 해외선물 OpenAPI-W) 스토캐스틱(Stochastic) 값 구하기 (2) 스토캐스틱 패스트 %K, %D 구하기 (6) | 2023.10.02 |
(키움증권 해외선물 OpenAPI-W) 스토캐스틱(Stochastic) 값 구하기 (1) 스토캐스틱 개념 및 계산하는 방법 (4) | 2023.10.01 |
(키움증권 해외선물 OpenAPI-W) MACD 값 구하기 (3) 파이썬에서 작성하기 (0) | 2023.08.08 |
(키움증권 해외선물 OpenAPI-W) MACD 값 구하기 (2) MACD 엑셀에서 계산하기 (0) | 2023.08.07 |
(키움증권 해외선물 OpenAPI-W) MACD 값 구하기 (1) MACD 개념 및 지수이동평균 (0) | 2023.08.06 |