반응형
from msilib.schema import RadioButton
import sys
import time
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QProgressBar
from pykiwoom.kiwoom import *
from PyQt5 import QtWidgets, uic, QtCore
import pyautogui as msgbox
from PyQt5.QtGui import QStandardItemModel ## listView 사용
from PyQt5.QtGui import QStandardItem ## listview
import yfinance as yf
import pandas as pd
import datetime as dt
import numpy as np
import mplfinance as mpf
import matplotlib.pyplot as plt
import matplotlib
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from sublib import *
class Stocktrade(QMainWindow,QtWidgets.QDialog):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.load_ui()
self.init_cmb()
self.df_chk = 0
self.fig = plt.figure(figsize=(12,7))
self.canvas = FigureCanvas(self.fig)
self.verticalLayout.addWidget(self.canvas)
self.get_code()
self.radioButton.setChecked(True)
self.radioButton_10.setChecked(True)
self.kospi_btn_click()
self.seek_code_btn.clicked.connect(self.seekcode_btn_click)
self.lineEdit_6.returnPressed.connect(self.seekcode_btn_click)
self.backtest_btn.clicked.connect(self.back_test)
self.db_down_btn.clicked.connect(self.start_db_down)
self.pushButton.clicked.connect(self.disp_db)
self.pushButton_2.clicked.connect(self.save_csv)
self.radioButton.clicked.connect(self.kospi_btn_click)
self.radioButton_2.clicked.connect(self.kosdaq_btn_click)
self.radioButton_3.clicked.connect(self.etf_btn_click)
self.kospi_all_btn.clicked.connect(self.kospi_all)
self.kosdaq_all_btn.clicked.connect(self.kosdaq_all)
self.listView.clicked.connect(self.list_click)
self.listView_2.clicked.connect(self.list_2_click)
def get_code(self):
self.kospi = []
self.kosdaq = []
self.etf = []
self.kospi, self.kosdaq, self.etf = get_market_code(self.kospi, self.kosdaq, self.etf)
self.lineEdit.setText(str(len(self.kospi)))
self.lineEdit_2.setText(str(len(self.kosdaq)))
self.lineEdit_3.setText(str(len(self.etf)))
def start_db_down(self):
x = get_stock_db(self.kospi, self.kosdaq)
print(x)
def disp_db(self):
x = disp_down_db()
print(x)
def back_test(self):
if self.comboBox.currentIndex() == 0:
msgbox.alert("기법 옵션을 선택하세요")
else:
if self.lineEdit_4.text() != "":
self.method()
else:
msgbox.alert("종목 선택하세요")
def kospi_all(self):
self.method_all("kospi")
def kosdaq_all(self):
self.method_all("kosdaq")
def method(self):
self.code = self.lineEdit_4.text()
if self.radioButton_4.isChecked():
term = '1mo'
elif self.radioButton_5.isChecked():
term = '3mo'
elif self.radioButton_6.isChecked():
term = '6mo'
elif self.radioButton_7.isChecked():
term = '1y'
elif self.radioButton_8.isChecked():
term = '2y'
elif self.radioButton_9.isChecked():
term = '5y'
elif self.radioButton_10.isChecked():
term = '10y'
elif self.radioButton_11.isChecked():
term = 'max'
self.code = self.code+'.KS'
ticker = yf.Ticker(self.code)
self.df = ticker.history(interval='1d', period=term, auto_adjust=False)
# 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, max
self.g_masoo_cnt = 0
self.g_mado_cnt = 0
self.g_suik_tot = 0
self.g_suik_rate_tot = 0
self.g_suik_rate_h = 0
self.g_suik_rate_l = 0
print(self.df)
self.df_chk = 0
self.method_exec()
print(self.df)
self.draw_chart()
def save_csv(self):
if self.df_chk == 1:
self.df.to_csv("C://stock//backtesting//csv_file//"+self.lineEdit_4.text().strip()+self.lineEdit_5.text().strip()+".csv")
msgbox.alert(self.lineEdit_4.text().strip()+self.lineEdit_5.text().strip()+".csv 파일 저장")
else:
msgbox.alert("데이터프레임이 없습니다.")
def method_all(self, chk_bit):
print(chk_bit)
if chk_bit == "kospi":
stock_list = self.kospi
else:
stock_list = self.kosdaq
self.g_masoo_cnt = 0
self.g_mado_cnt = 0
self.g_suik_tot = 0
self.g_suik_rate_tot = 0
self.g_suik_rate_h = 0
self.g_suik_rate_l = 0
if self.radioButton_4.isChecked():
term = '1mo'
elif self.radioButton_5.isChecked():
term = '3mo'
elif self.radioButton_6.isChecked():
term = '6mo'
elif self.radioButton_7.isChecked():
term = '1y'
elif self.radioButton_8.isChecked():
term = '2y'
elif self.radioButton_9.isChecked():
term = '5y'
elif self.radioButton_10.isChecked():
term = '10y'
elif self.radioButton_11.isChecked():
term = 'max'
count = 0
for x in stock_list:
self.code = x[0:6]+'.KS'
ticker = yf.Ticker(self.code)
self.df = ticker.history(interval='1d', period=term, auto_adjust=False)
self.method_exec()
count +=1
print("종목수: %s / count : %s 종목코드 %s: 매수건수 : %s 매도건수 : %s 누적수익율 : %s 최고수익률 %s 최저수익률 %s" % \
(len(stock_list),count, self.code, self.g_masoo_cnt, self.g_mado_cnt, round(self.g_suik_rate_tot,2), round(self.g_suik_rate_h,2), round(self.g_suik_rate_l,2)))
self.lineEdit_7.setText(str(self.g_masoo_cnt))
self.lineEdit_8.setText(str(self.g_mado_cnt))
self.lineEdit_9.setText(str(self.g_suik_tot))
self.lineEdit_10.setText(str(round(self.g_suik_rate_tot,2)))
self.lineEdit_11.setText(str(round(self.g_suik_rate_h,2)))
self.lineEdit_12.setText(str(round(self.g_suik_rate_l,2)))
def method_exec(self):
cmb_index = self.comboBox.currentIndex()
self.df['trade'] =0
self.df['masooga'] = 0
self.df['madoga'] = 0
self.df['suik'] = 0
self.df['suik_rate'] = 0
self.df['cut_line'] = 0
self.df['h_close'] = 0
self.df['l_close'] = 0
self.df['macd'] = 0
self.df['signal'] =0
self.df = self.df.reset_index()
self.df['MA5'] = self.df['Close'].ewm(5).mean() # 지수5선
self.df['MA14LOW'] = self.df['Low'].ewm(14).mean() # 지수14저가선
self.df['MA222'] = self.df['Close'].ewm(222).mean() # 지수 222선
# df['ma_next'] = df['close'].rolling(3).mean().shift(1)
# 한칸 밀어서 다음칸에 값을 저장
if cmb_index ==1 or cmb_index == 3:
# Bollinger Band (240,2)
self.df['MA240'] = self.df['Close'].rolling(window=240).mean()
std = self.df['Close'].rolling(240).std(ddof=0)
self.df['BB240UP'] = self.df['MA240'] + 2 * std
self.df['BB240DN'] = self.df['MA240'] - 2 * std
elif cmb_index ==2:
# Bollinger Band (60,2)
self.df['MA60'] = self.df['Close'].rolling(window=60).mean()
std = self.df['Close'].rolling(60).std(ddof=0)
self.df['BB60UP'] = self.df['MA60'] + 2 * std
self.df['BB60DN'] = self.df['MA60'] - 2 * std
elif cmb_index ==4:
self.df['macd'] = self.df['Close'].ewm(span=12, adjust=False).mean() - self.df['Close'].ewm(span=26, adjust=False).mean()
self.df['signal'] = self.df['macd'].ewm(span=9, adjust=False).mean()
self.df=self.df.fillna(0)
## 데이터프레임의 날짜만 빼고 나머지 모두 int형으로 변환
self.df.set_index('Date', inplace=True)
self.df = self.df.astype('int')
self.df['suik_rate'] = self.df['suik_rate'].astype('float')
self.df.reset_index(inplace=True)
masoo_chk = 0
masoo_cnt = 0
mado_cnt = 0
suik_tot = 0
suik_rate_tot = 0
h_close = 0
l_close = 1
cnt = 0
if cmb_index ==1:
## 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
self.df = self.df[['Date','Open','High','Low','Close','Volume','MA5','MA14LOW','MA222','MA240','BB240UP','BB240DN','trade','masooga','madoga','suik','suik_rate','cut_line','h_close','l_close']]
cnt =223
# h_close = df[close].apply(lambda:x 'close' if h< close)
h_close = self.df.iloc[0:222]['Close'].max()
l_close = self.df.iloc[0:222]['Close'].min()
elif cmb_index ==2:
## 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
self.df = self.df[['Date','Open','High','Low','Close','Volume','MA5','MA14LOW','MA222','MA60','BB60UP','BB60DN','trade','masooga','madoga','suik','suik_rate','cut_line','h_close','l_close']]
cnt =61
# h_close = df[close].apply(lambda:x 'close' if h< close)
h_close = self.df.iloc[0:60]['Close'].max()
l_close = self.df.iloc[0:60]['Close'].min()
elif cmb_index ==3:
## 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
self.df = self.df[['Date','Open','High','Low','Close','Volume','MA5','MA14LOW','MA222','MA240','BB240UP','BB240DN','trade','masooga','madoga','suik','suik_rate','cut_line','h_close','l_close']]
cnt =240
# h_close = df[close].apply(lambda:x 'close' if h< close)
h_close = self.df.iloc[0:240]['Close'].max()
l_close = self.df.iloc[0:240]['Close'].min()
elif cmb_index ==4:
## 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
self.df = self.df[['Date','Open','High','Low','Close','Volume','MA5','MA14LOW','MA222','macd', 'macd','signal','trade','masooga','madoga','suik','suik_rate','cut_line','h_close','l_close']]
cnt =26
# h_close = df[close].apply(lambda:x 'close' if h< close)
h_close = self.df.iloc[0:25]['Close'].max()
l_close = self.df.iloc[0:25]['Close'].min()
while True:
if cnt >= self.df.shape[0]:
break
if self.df.iloc[cnt, 4] > h_close:
h_close = self.df.iloc[cnt,4]
elif self.df.iloc[cnt, 4] > 0 and self.df.iloc[cnt, 4] < l_close:
l_close = self.df.iloc[cnt,4]
# print("i = %s h_close = %s l_close = %s" % (i, h_close, l_close))
self.df.iloc[cnt,17] = int((h_close-l_close)/2 + l_close) ## 최고가 - 최저가 /2 아래에서만 매수
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#[['Date', 'Open','High','Low','Close', 'Volume', 'MA5','MA14LOW','MA222','MA240','BB240UP','BB240DN', 'trade', 'masooga', 'madoga', 'suik', 'suik_rate', 'cut_line', h_close', 'l_close']]
if cmb_index ==1:
if masoo_chk == 0 and (self.df.iloc[cnt,4] < self.df.iloc[cnt,17]) and ((self.df.iloc[cnt-1,4] < self.df.iloc[cnt-1,8]) and (self.df.iloc[cnt,4] > self.df.iloc[cnt,8])):
self.df.iloc[cnt,12] = 1
self.df.iloc[cnt,13] = self.df.iloc[cnt,4] # 종가 매수가
masooga = self.df.iloc[cnt,4]
masoo_chk = 1
masoo_cnt += 1
elif masoo_chk == 1 and (self.df.iloc[cnt,4] < self.df.iloc[cnt,10]) and ((self.df.iloc[cnt,4] < self.df.iloc[cnt,7]) or (self.df.iloc[cnt,4] < self.df.iloc[cnt,8])):
# 매수 되었고 & 종가가 볼밴240상단 보다 작고 & (종가가 저가14선 이탈 또는 지수 222 이탈시) 매도
self.df.iloc[cnt,12] = 3
self.df.iloc[cnt,14] = self.df.iloc[cnt,4] # 종가 매도가
madoga = self.df.iloc[cnt,4]
self.df.iloc[cnt,15] = madoga-masooga
self.df.iloc[cnt,16] = self.df.iloc[cnt,15] /masooga * 100
mado_cnt += 1
masoo_chk = 0
suik_tot = suik_tot +(madoga-masooga)
suik_rate_tot = round(suik_rate_tot + self.df.iloc[cnt, 16],2)
elif cmb_index ==2:
if masoo_chk == 0 and (self.df.iloc[cnt,4] < self.df.iloc[cnt,17]) and ((self.df.iloc[cnt-1,3] < self.df.iloc[cnt-1,11]) and (self.df.iloc[cnt,4] > self.df.iloc[cnt,11])):
self.df.iloc[cnt,12] = 1
self.df.iloc[cnt,13] = self.df.iloc[cnt,4] # 종가 매수가
masooga = self.df.iloc[cnt,4]
masoo_low = self.df.iloc[cnt,3]
masoo_chk = 1
masoo_cnt += 1
elif masoo_chk == 1 and (((self.df.iloc[cnt,4] - masooga) /100 > 0.5 and self.df.iloc[cnt,4] < self.df.iloc[cnt,7]) or self.df.iloc[cnt,4] < masoo_low) :
# 매수 되었고 & 5% 이상 수익인데 14저가선 아래 또는 종가가 매수가저가이탈
self.df.iloc[cnt,12] = 3
self.df.iloc[cnt,14] = self.df.iloc[cnt,4] # 종가 매도가
madoga = self.df.iloc[cnt,4]
self.df.iloc[cnt,15] = madoga-masooga
self.df.iloc[cnt,16] = self.df.iloc[cnt,15] /masooga * 100
mado_cnt += 1
masoo_chk = 0
suik_tot = suik_tot +(madoga-masooga)
suik_rate_tot = round(suik_rate_tot + self.df.iloc[cnt, 16],2)
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#[['Date', 'Open','High','Low','Close', 'Volume', 'MA5','MA14LOW','MA222','MA240','BB240UP','BB240DN', 'trade', 'masooga', 'madoga', 'suik', 'suik_rate', 'cut_line', h_close', 'l_close']]
elif cmb_index ==3:
if masoo_chk == 0 and (self.df.iloc[cnt,4] < self.df.iloc[cnt,17]) and ((self.df.iloc[cnt-1,4] < self.df.iloc[cnt-1,11]) and (self.df.iloc[cnt,4] > self.df.iloc[cnt,11])):
self.df.iloc[cnt,12] = 1
self.df.iloc[cnt,13] = self.df.iloc[cnt,4] # 종가 매수가
masooga = self.df.iloc[cnt,4]
masoo_low = self.df.iloc[cnt,3]
masoo_chk = 1
masoo_cnt += 1
elif masoo_chk == 1 and (((self.df.iloc[cnt,4] - masooga) /100 > 0.5 and self.df.iloc[cnt,4] < self.df.iloc[cnt,7]) or self.df.iloc[cnt,4] < masoo_low) :
# 매수 되었고 & 5% 이상 수익인데 14저가선 아래 또는 종가가 매수가저가이탈
self.df.iloc[cnt,12] = 3
self.df.iloc[cnt,14] = self.df.iloc[cnt,4] # 종가 매도가
madoga = self.df.iloc[cnt,4]
self.df.iloc[cnt,15] = madoga-masooga
self.df.iloc[cnt,16] = self.df.iloc[cnt,15] /masooga * 100
mado_cnt += 1
masoo_chk = 0
suik_tot = suik_tot +(madoga-masooga)
suik_rate_tot = round(suik_rate_tot + self.df.iloc[cnt, 16],2)
elif cmb_index == 4: ## macd 매매
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# [['Date','Open','High','Low','Close','Volume','MA5','MA14LOW','MA222','macd', 'macd','signal','trade','masooga','madoga','suik','suik_rate','cut_line','h_close','l_close']]
if masoo_chk == 0 and (self.df.iloc[cnt,4] < self.df.iloc[cnt,17]) and ((self.df.iloc[cnt-1,10] < self.df.iloc[cnt-1,11]) and (self.df.iloc[cnt,10] > self.df.iloc[cnt,11])):
self.df.iloc[cnt,12] = 1
self.df.iloc[cnt,13] = self.df.iloc[cnt,4] # 종가 매수가
masooga = self.df.iloc[cnt,4]
masoo_low = self.df.iloc[cnt,3]
masoo_chk = 1
masoo_cnt += 1
elif masoo_chk == 1 and (((self.df.iloc[cnt,4] - masooga) /100 > 0.5 and self.df.iloc[cnt,4] < self.df.iloc[cnt,7]) or self.df.iloc[cnt,4] < masoo_low) :
# 매수 되었고 & 5% 이상 수익인데 14저가선 아래 또는 종가가 매수가저가이탈
self.df.iloc[cnt,12] = 3
self.df.iloc[cnt,14] = self.df.iloc[cnt,4] # 종가 매도가
madoga = self.df.iloc[cnt,4]
self.df.iloc[cnt,15] = madoga-masooga
self.df.iloc[cnt,16] = self.df.iloc[cnt,15] /masooga * 100
mado_cnt += 1
masoo_chk = 0
suik_tot = suik_tot +(madoga-masooga)
suik_rate_tot = round(suik_rate_tot + self.df.iloc[cnt, 16],2)
cnt +=1
self.lineEdit_7.setText(str(masoo_cnt))
self.lineEdit_8.setText(str(mado_cnt))
self.lineEdit_9.setText(str(suik_tot))
self.lineEdit_10.setText(str(suik_rate_tot))
self.lineEdit_11.setText(str(round(self.df['suik_rate'].max(),2)))
self.lineEdit_12.setText(str(round(self.df['suik_rate'].min(),2)))
self.g_masoo_cnt =self.g_masoo_cnt+ masoo_cnt
self.g_mado_cnt =self.g_mado_cnt+ mado_cnt
self.g_suik_tot =self.g_suik_tot+ suik_tot
self.g_suik_rate_tot =self.g_suik_rate_tot+ suik_rate_tot
if self.g_suik_rate_h < self.df['suik_rate'].max():
self.g_suik_rate_h = self.df['suik_rate'].max()
elif self.g_suik_rate_l > self.df['suik_rate'].min():
self.g_suik_rate_l = self.df['suik_rate'].min()
self.df_chk = 1
def draw_chart(self):
### matplot 좋은영상 : https://www.youtube.com/watch?v=5DfACSYgP0U&t=176s
matplotlib.rcParams['font.family'] ='Malgun Gothic' # 폰트설정
matplotlib.rcParams['font.size'] = 10 # 글자크기
matplotlib.rcParams['axes.unicode_minus'] = False # 마이너스기호(-)가 깨지는 현상 방지
self.ax = self.fig.add_subplot(111)
self.ax.plot(self.df['Date'],self.df['Close'], color='gray', label="종가", linewidth=2)
self.ax.plot(self.df['Date'],self.df['MA222'], color='pink', label="지수222", linewidth=2)
self.ax.plot(self.df['Date'],self.df['MA14LOW'], label="지수 저가14일선")
if self.comboBox.currentIndex() == 1 or self.comboBox.currentIndex() == 3:
self.ax.plot(self.df['Date'],self.df['BB240UP'], label="BB 240 UP")
self.ax.plot(self.df['Date'],self.df['BB240DN'], label="BB 240 DN")
elif self.comboBox.currentIndex() == 2:
self.ax.plot(self.df['Date'],self.df['BB60UP'], label="BB 60 UP")
self.ax.plot(self.df['Date'],self.df['BB60DN'], label="BB 60 DN")
self.ax.plot(self.df['Date'],self.df['cut_line'], label="매수기준선")
cnt = 0
while True:
if cnt >= self.df.shape[0]:
break
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
# self.df = self.df[['Date', 'Open','High','Low','Close', 'Volume', 'MA5','MA14LOW','MA222','MA240','BB240UP','BB240DN', 'trade', 'masoo', 'mado']]
# https://wikidocs.net/92083 (마커 표시)
if self.df.iloc[cnt,12] == 1:
self.ax.plot(self.df.iloc[cnt,0], self.df.iloc[cnt,4], color = 'red', marker='^')
elif self.df.iloc[cnt,12] == 3:
self.ax.plot(self.df.iloc[cnt,0], self.df.iloc[cnt,4], color = 'blue', marker='v')
cnt +=1
self.ax.legend(loc='upper left', frameon=False, shadow=True)
self.ax.grid()
# self.ax.axes.xaxis.set_visible(False)
self.ax.axes.yaxis.set_visible(False)
self.canvas.draw()
def load_ui(self):
self.ui = uic.loadUi("C://stock//backtesting//main.ui",self)
self.ui.show()
def kospi_btn_click(self):
self.label.setText("K O S P I")
model = QStandardItemModel()
for codename in self.kospi:
model.appendRow(QStandardItem(codename))
self.listView.setModel(model)
def kosdaq_btn_click(self):
self.label.setText("K O S D A Q")
model = QStandardItemModel()
for codename in self.kosdaq:
model.appendRow(QStandardItem(codename))
self.listView.setModel(model)
def etf_btn_click(self):
self.label.setText("E T F")
model = QStandardItemModel()
for codename in self.etf:
model.appendRow(QStandardItem(codename))
self.listView.setModel(model)
def cls_mem(self):
self.lineEdit_4.clear()
self.lineEdit_5.clear()
self.lineEdit_7.clear()
self.lineEdit_8.clear()
self.lineEdit_9.clear()
self.lineEdit_10.clear()
self.lineEdit_11.clear()
self.lineEdit_12.clear()
def list_click(self):
self.cls_mem()
current_index = self.listView.currentIndex()
item = current_index.data(QtCore.Qt.DisplayRole)
self.lineEdit_4.setText(item[0:6])
self.lineEdit_5.setText(item[7:])
def list_2_click(self):
self.cls_mem()
current_index = self.listView_2.currentIndex()
item = current_index.data(QtCore.Qt.DisplayRole)
self.lineEdit_4.setText(item[0:6])
self.lineEdit_5.setText(item[7:])
def seekcode_btn_click(self):
kospi = self.kiwoom.GetCodeListByMarket('0')
kosdaq = self.kiwoom.GetCodeListByMarket('10')
etf = self.kiwoom.GetCodeListByMarket('8')
stock_code = kospi + kosdaq + etf
model = QStandardItemModel()
for code in stock_code:
name = self.kiwoom.GetMasterCodeName(code)
if self.lineEdit_6.text() in name:
model.appendRow(QStandardItem(code+" "+name))
self.listView_2.setModel(model)
def init_cmb(self):
self.comboBox.addItem("--백테스팅 기법 선택--")
self.comboBox.addItem("지수 222선 돌파")
self.comboBox.addItem("BBnand(60,2) 하단선 상향돌파")
self.comboBox.addItem("BBnand(240,2) 하단선 상향돌파")
self.comboBox.addItem("MACD 골든크로스")
if __name__ == "__main__":
app = QApplication(sys.argv)
stocktrade = Stocktrade()
sys.exit(app.exec_())
반응형
'파이썬 & 키움API > 파이썬 키움API 설정 팁' 카테고리의 다른 글
키움api 계좌정보 가져오기 (0) | 2025.01.25 |
---|---|
키움api 연결 (0) | 2025.01.25 |
파이썬 & 키움API 연결 중요팁 (0) | 2025.01.25 |