commit bee0f632a6ace58af21248e0bef7c8e7575e94b8 Author: hyeonji0409 Date: Thu Jul 1 17:01:58 2021 +0900 moneydare diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..27a018c --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +predict.py \ No newline at end of file diff --git a/.idea/Auto_stock.iml b/.idea/Auto_stock.iml new file mode 100644 index 0000000..14d8c8d --- /dev/null +++ b/.idea/Auto_stock.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..be93871 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..fe7c492 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Kiwoom.py b/Kiwoom.py new file mode 100644 index 0000000..dc710a4 --- /dev/null +++ b/Kiwoom.py @@ -0,0 +1,220 @@ +import sys +from PyQt5.QtWidgets import * +from PyQt5.QAxContainer import * +from PyQt5.QtCore import * +import time +import pandas as pd +import sqlite3 + +TR_REQ_TIME_INTERVAL = 0.05 + + +class Kiwoom(QAxWidget): + def __init__(self): + super().__init__() + self._create_kiwoom_instance() + self._set_signal_slots() + + def _create_kiwoom_instance(self): + self.setControl("KHOPENAPI.KHOpenAPICtrl.1") + + def _set_signal_slots(self): + self.OnEventConnect.connect(self._event_connect) + self.OnReceiveTrData.connect(self._receive_tr_data) + self.OnReceiveChejanData.connect(self._receive_chejan_data) + + def comm_connect(self): + self.dynamicCall("CommConnect()") + self.login_event_loop = QEventLoop() + self.login_event_loop.exec_() + + def _event_connect(self, err_code): + if err_code == 0: + print("connected") + else: + print("disconnected") + + self.login_event_loop.exit() + + def get_code_list_by_market(self, market): + code_list = self.dynamicCall("GetCodeListByMarket(QString)", market) + code_list = code_list.split(';') + return code_list[:-1] + + def get_master_code_name(self, code): + code_name = self.dynamicCall("GetMasterCodeName(QString)", code) + return code_name + + def get_connect_state(self): + ret = self.dynamicCall("GetConnectState()") + return ret + + def get_login_info(self, tag): + ret = self.dynamicCall("GetLoginInfo(QString)", tag) + return ret + + def set_input_value(self, id, value): + self.dynamicCall("SetInputValue(QString, QString)", id, value) + + def comm_rq_data(self, rqname, trcode, next, screen_no): + self.dynamicCall("CommRqData(QString, QString, int, QString)", rqname, trcode, next, screen_no) + self.tr_event_loop = QEventLoop() + self.tr_event_loop.exec_() + + def _comm_get_data(self, code, real_type, field_name, index, item_name): + ret = self.dynamicCall("CommGetData(QString, QString, QString, int, QString)", code, + real_type, field_name, index, item_name) + return ret.strip() + + def _get_repeat_cnt(self, trcode, rqname): + ret = self.dynamicCall("GetRepeatCnt(QString, QString)", trcode, rqname) + return ret + + def send_order(self, rqname, screen_no, acc_no, order_type, code, quantity, price, hoga, order_no): + self.dynamicCall("SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)", + [rqname, screen_no, acc_no, order_type, code, quantity, price, hoga, order_no]) + + def get_chejan_data(self, fid): + ret = self.dynamicCall("GetChejanData(int)", fid) + return ret + + def get_server_gubun(self): + ret = self.dynamicCall("KOA_Functions(QString, QString)", "GetServerGubun", "") + return ret + + def _receive_chejan_data(self, gubun, item_cnt, fid_list): + print(gubun) + print(self.get_chejan_data(9203)) + print(self.get_chejan_data(302)) + print(self.get_chejan_data(900)) + print(self.get_chejan_data(901)) + + def _receive_tr_data(self, screen_no, rqname, trcode, record_name, next, unused1, unused2, unused3, unused4): + if next == '2': + self.remained_data = True + else: + self.remained_data = False + + if rqname == "opt10081_req": + self._opt10081(rqname, trcode) + elif rqname == "opw00001_req": + self._opw00001(rqname, trcode) + elif rqname == "opw00018_req": + self._opw00018(rqname, trcode) + + try: + self.tr_event_loop.exit() + except AttributeError: + pass + + @staticmethod + def change_format(data): + strip_data = data.lstrip('-0') + if strip_data == '' or strip_data == '.00': + strip_data = '0' + + try: + format_data = format(int(strip_data), ',d') + except: + format_data = format(float(strip_data)) + + if data.startswith('-'): + format_data = '-' + format_data + + return format_data + + @staticmethod + def change_format2(data): + strip_data = data.lstrip('-0') + + if strip_data == '': + strip_data = '0' + + if strip_data.startswith('.'): + strip_data = '0' + strip_data + + if data.startswith('-'): + strip_data = '-' + strip_data + + return strip_data + + def _opw00001(self, rqname, trcode): + d2_deposit = self._comm_get_data(trcode, "", rqname, 0, "d+2추정예수금") + self.d2_deposit = Kiwoom.change_format(d2_deposit) + + def _opt10081(self, rqname, trcode): + data_cnt = self._get_repeat_cnt(trcode, rqname) + + for i in range(data_cnt): + date = self._comm_get_data(trcode, "", rqname, i, "일자") + open = self._comm_get_data(trcode, "", rqname, i, "시가") + high = self._comm_get_data(trcode, "", rqname, i, "고가") + low = self._comm_get_data(trcode, "", rqname, i, "저가") + close = self._comm_get_data(trcode, "", rqname, i, "현재가") + volume = self._comm_get_data(trcode, "", rqname, i, "거래량") + + self.ohlcv['date'].append(date) + self.ohlcv['open'].append(int(open)) + self.ohlcv['high'].append(int(high)) + self.ohlcv['low'].append(int(low)) + self.ohlcv['close'].append(int(close)) + self.ohlcv['volume'].append(int(volume)) + + def reset_opw00018_output(self): + self.opw00018_output = {'single': [], 'multi': []} + + def _opw00018(self, rqname, trcode): + # single data + total_purchase_price = self._comm_get_data(trcode, "", rqname, 0, "총매입금액") + total_eval_price = self._comm_get_data(trcode, "", rqname, 0, "총평가금액") + total_eval_profit_loss_price = self._comm_get_data(trcode, "", rqname, 0, "총평가손익금액") + total_earning_rate = self._comm_get_data(trcode, "", rqname, 0, "총수익률(%)") + estimated_deposit = self._comm_get_data(trcode, "", rqname, 0, "추정예탁자산") + + self.opw00018_output['single'].append(Kiwoom.change_format(total_purchase_price)) + self.opw00018_output['single'].append(Kiwoom.change_format(total_eval_price)) + self.opw00018_output['single'].append(Kiwoom.change_format(total_eval_profit_loss_price)) + + total_earning_rate = Kiwoom.change_format(total_earning_rate) + + if self.get_server_gubun(): + total_earning_rate = float(total_earning_rate) / 100 + total_earning_rate = str(total_earning_rate) + + self.opw00018_output['single'].append(total_earning_rate) + + self.opw00018_output['single'].append(Kiwoom.change_format(estimated_deposit)) + + # multi data + rows = self._get_repeat_cnt(trcode, rqname) + for i in range(rows): + name = self._comm_get_data(trcode, "", rqname, i, "종목명") + quantity = self._comm_get_data(trcode, "", rqname, i, "보유수량") + purchase_price = self._comm_get_data(trcode, "", rqname, i, "매입가") + current_price = self._comm_get_data(trcode, "", rqname, i, "현재가") + eval_profit_loss_price = self._comm_get_data(trcode, "", rqname, i, "평가손익") + earning_rate = self._comm_get_data(trcode, "", rqname, i, "수익률(%)") + + quantity = Kiwoom.change_format(quantity) + purchase_price = Kiwoom.change_format(purchase_price) + current_price = Kiwoom.change_format(current_price) + eval_profit_loss_price = Kiwoom.change_format(eval_profit_loss_price) + earning_rate = Kiwoom.change_format2(earning_rate) + + self.opw00018_output['multi'].append([name, quantity, purchase_price, current_price, eval_profit_loss_price, + earning_rate]) + + +if __name__ == "__main__": + app = QApplication(sys.argv) + kiwoom = Kiwoom() + kiwoom.comm_connect() + + kiwoom.reset_opw00018_output() + account_number = kiwoom.get_login_info("ACCNO") + account_number = account_number.split(';')[0] + + kiwoom.set_input_value("계좌번호", account_number) + kiwoom.comm_rq_data("opw00018_req", "opw00018", 0, "2000") + print(kiwoom.opw00018_output['single']) + print(kiwoom.opw00018_output['multi']) \ No newline at end of file diff --git a/__pycache__/Kiwoom.cpython-37.pyc b/__pycache__/Kiwoom.cpython-37.pyc new file mode 100644 index 0000000..6b40038 Binary files /dev/null and b/__pycache__/Kiwoom.cpython-37.pyc differ diff --git a/__pycache__/Kiwoom.cpython-38.pyc b/__pycache__/Kiwoom.cpython-38.pyc new file mode 100644 index 0000000..bad6799 Binary files /dev/null and b/__pycache__/Kiwoom.cpython-38.pyc differ diff --git a/__pycache__/Kiwoom.cpython-39.pyc b/__pycache__/Kiwoom.cpython-39.pyc new file mode 100644 index 0000000..5e71442 Binary files /dev/null and b/__pycache__/Kiwoom.cpython-39.pyc differ diff --git a/__pycache__/webreader.cpython-37.pyc b/__pycache__/webreader.cpython-37.pyc new file mode 100644 index 0000000..7ac78cf Binary files /dev/null and b/__pycache__/webreader.cpython-37.pyc differ diff --git a/__pycache__/webreader.cpython-38.pyc b/__pycache__/webreader.cpython-38.pyc new file mode 100644 index 0000000..29b7ff8 Binary files /dev/null and b/__pycache__/webreader.cpython-38.pyc differ diff --git a/__pycache__/widgetfile.cpython-37.pyc b/__pycache__/widgetfile.cpython-37.pyc new file mode 100644 index 0000000..1c9cc4a Binary files /dev/null and b/__pycache__/widgetfile.cpython-37.pyc differ diff --git a/__pycache__/widgetfile.cpython-38.pyc b/__pycache__/widgetfile.cpython-38.pyc new file mode 100644 index 0000000..d90bfa6 Binary files /dev/null and b/__pycache__/widgetfile.cpython-38.pyc differ diff --git a/buy_list.txt b/buy_list.txt new file mode 100644 index 0000000..e69de29 diff --git a/icon.png.url b/icon.png.url new file mode 100644 index 0000000..6192436 --- /dev/null +++ b/icon.png.url @@ -0,0 +1,2 @@ +[InternetShortcut] +URL=https://github.com/pystockhub/book/blob/master/ch18/day04/icon.png \ No newline at end of file diff --git a/java.js b/java.js new file mode 100644 index 0000000..e69de29 diff --git a/magic.xlsx b/magic.xlsx new file mode 100644 index 0000000..887d978 Binary files /dev/null and b/magic.xlsx differ diff --git a/magic_formula.py b/magic_formula.py new file mode 100644 index 0000000..f9cf53a --- /dev/null +++ b/magic_formula.py @@ -0,0 +1,73 @@ +import xlrd +import pandas as pd + +# df = pd.read_ex + +file_path = 'magic_formula_data.xlsx' +wd = xlrd.open_workbook(file_path) + +pbr_sh = wd.sheet_by_name('PBR') + +#'pbr' 순위 구하기. 양수 값의 데이터만 필요 & pbr값 작을수록 좋음 +pbr_dict = {} + +for i in range(1, pbr_sh.nrows): + data = pbr_sh.row_values(i) + name = data[0] + pbr = data[1] + if pbr > 0: + pbr_dict[name] = pbr + +import operator + +sorted_pbr = sorted(pbr_dict.items(),key=operator.itemgetter(1)) + +#pbr 순위 지정 +pbr_rank = {} + +for num, firm in enumerate(sorted_pbr): + pbr_rank[firm[0]] = num + 1 + +#GP_A 순위 구하기. 값이 존재하는 데이터만 필요 & GP_A 값 클 수록 좋음 +gp_a_sh = wd.sheet_by_name('GP_A') + +gp_a_dict = {} + +for j in range(1, gp_a_sh.nrows): + data = gp_a_sh.row_values(j) + name = data[0] + gp_a = data[1] + if gp_a != 0: + gp_a_dict[name] = gp_a + +sorted_gp_a = sorted(gp_a_dict.items(), key=operator.itemgetter(1), reverse=True) + +gp_a_rank = {} +for num, firm in enumerate(sorted_gp_a): + gp_a_rank[firm[0]] = num + 1 + +total_rank = {} + +for name in gp_a_rank.keys(): + if name in pbr_rank.keys(): + total_rank[name] = pbr_rank[name] + gp_a_rank[name] + +#total_rank의 value 값을 기준키로 하여 total_rank를 오르차순으로 저장. value값이 작은 순서대로 정렬 +sorted_total = sorted(total_rank.items(), key=operator.itemgetter(1)) + +magic_rank = {} + +for num, firm in enumerate(sorted_total): + magic_rank[firm[0]] = num +1 + + +sorted_magic = sorted(magic_rank.items(), key=operator.itemgetter(1)) + +print(sorted_magic[:20]) + + +df = pd.DataFrame.from_records(sorted_magic[:20]) +df.to_excel('magic.xlsx') + + + diff --git a/magic_formula_data.xlsx b/magic_formula_data.xlsx new file mode 100644 index 0000000..07da64c Binary files /dev/null and b/magic_formula_data.xlsx differ diff --git a/predict.py b/predict.py new file mode 100644 index 0000000..f001659 --- /dev/null +++ b/predict.py @@ -0,0 +1,154 @@ +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +import seaborn as sns +import warnings +import os +import tensorflow as tf +import FinanceDataReader as fdr +#from Kiwoom import * + + +warnings.filterwarnings('ignore') + +plt.rcParams['font.family'] = 'NanumGothic' + + +# 삼성전자(005930) 전체 (1996-11-05 ~ 현재) +# 데브시스터즈(194480) +# gs리테일(007070) +# 쎄미시스코(136510) + +#해당시점 이후의 데이터 +#apple = fdr.DataReader('AAPL', '2017') + +STOCK_CODE = '005930' +stock = fdr.DataReader(STOCK_CODE) +stock.head() + +stock.tail() +stock.index + +stock['Year'] = stock.index.year +stock['Month'] = stock.index.month +stock['Day'] = stock.index.day +stock.head() + +#plt.figure(figsize=(16, 9)) +#sns.lineplot(y=stock['Close'], x=stock.index) +#plt.xlabel('time') +#plt.ylabel('price') + +#time_steps = [['1990', '2000'], + # ['2000', '2010'], + # ['2010', '2015'], + # ['2015', '2021']] + +#fig, axes = plt.subplots(2, 2) +##fig.set_size_inches(16, 9) +#for i in range(4): + # ax = axes[i//2, i%2] + # df = stock.loc[(stock.index > time_steps[i][0]) & (stock.index < time_steps[i][1])] + #sns.lineplot(y=df['Close'], x=df.index, ax=ax) + #ax.set_title(f'{time_steps[i][0]}~{time_steps[i][1]}') + #ax.set_xlabel('time') + #ax.set_ylabel('price') +#plt.tight_layout() +#plt.show() + +from sklearn.preprocessing import MinMaxScaler + +scaler = MinMaxScaler() +# 스케일을 적용할 column을 정의합니다. +scale_cols = ['Open', 'High', 'Low', 'Close', 'Volume'] +# 스케일 후 columns +scaled = scaler.fit_transform(stock[scale_cols]) +scaled + +df = pd.DataFrame(scaled, columns=scale_cols) + +from sklearn.model_selection import train_test_split + +x_train, x_test, y_train, y_test = train_test_split(df.drop('Close', 1), df['Close'], test_size=0.2, random_state=0, shuffle=False) + +x_train.shape, y_train.shape +x_test.shape, y_test.shape +x_train + +#데이터셋구성 +def windowed_dataset(series, window_size, batch_size, shuffle): + series = tf.expand_dims(series, axis=-1) + ds = tf.data.Dataset.from_tensor_slices(series) + ds = ds.window(window_size + 1, shift=1, drop_remainder=True) + ds = ds.flat_map(lambda w: w.batch(window_size + 1)) + if shuffle: + ds = ds.shuffle(1000) + ds = ds.map(lambda w: (w[:-1], w[-1])) + return ds.batch(batch_size).prefetch(1) + +WINDOW_SIZE=20 +BATCH_SIZE=32 + +train_data = windowed_dataset(y_train, WINDOW_SIZE, BATCH_SIZE, True) +test_data = windowed_dataset(y_test, WINDOW_SIZE, BATCH_SIZE, False) + +# 아래의 코드로 데이터셋의 구성을 확인해 볼 수 있습니다. + #X: (batch_size, window_size, feature) + #Y: (batch_size, feature) +for data in train_data.take(1): + print(f'데이터셋(X) 구성(batch_size, window_size, feature갯수): {data[0].shape}') + print(f'데이터셋(Y) 구성(batch_size, window_size, feature갯수): {data[1].shape}') + + #모델 +from tensorflow.keras.models import Sequential +from tensorflow.keras.layers import Dense, LSTM, Conv1D, Lambda +from tensorflow.keras.losses import Huber +from tensorflow.keras.optimizers import Adam +from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint + + + +model = Sequential([ + # 1차원 feature map 생성 + Conv1D(filters=32, kernel_size=5, + padding="causal", + activation="relu", + input_shape=[WINDOW_SIZE, 1]), + # LSTM + LSTM(16, activation='tanh'), + Dense(16, activation="relu"), + Dense(1), +]) + +# Sequence 학습에 비교적 좋은 퍼포먼스를 내는 Huber()를 사용합니다. +loss = Huber() +optimizer = Adam(0.0005) +model.compile(loss=Huber(), optimizer=optimizer, metrics=['mse']) + +# earlystopping은 10번 epoch통안 val_loss 개선이 없다면 학습을 멈춥니다. +earlystopping = EarlyStopping(monitor='val_loss', patience=10) +# val_loss 기준 체크포인터도 생성합니다. +filename = os.path.join('tmp', 'ckeckpointer.ckpt') +checkpoint = ModelCheckpoint(filename, + save_weights_only=True, + save_best_only=True, + monitor='val_loss', + verbose=1) + +history = model.fit(train_data, + validation_data=(test_data), + epochs=50, + callbacks=[checkpoint, earlystopping]) + +model.load_weights(filename) +pred = model.predict(test_data) +pred.shape + + +plt.figure(figsize=(12, 9)) +plt.plot(np.asarray(y_test)[20:], label='actual') +plt.plot(pred, label='prediction') +plt.grid() +plt.legend(loc='best') +#plt.tight_layout() +plt.show() diff --git a/pymon.py b/pymon.py new file mode 100644 index 0000000..764b1b8 --- /dev/null +++ b/pymon.py @@ -0,0 +1,155 @@ +import sys +from PyQt5.QtWidgets import * +import Kiwoom +import time +from pandas import DataFrame +import datetime +import webreader +import numpy as np + +MARKET_KOSPI = 0 +MARKET_KOSDAQ = 10 + +class PyMon: + def __init__(self): + self.kiwoom = Kiwoom.Kiwoom() + self.kiwoom.comm_connect() + self.get_code_list() + + def get_code_list(self): + self.kospi_codes = self.kiwoom.get_code_list_by_market(MARKET_KOSPI) + self.kosdaq_codes = self.kiwoom.get_code_list_by_market(MARKET_KOSDAQ) + + #현재 날짜를 기준으로 과거 거래일별로 시가, 고가, 저가, 종가, 거래량을 가져오는 메서드 구현 + def get_ohlcv(self, code, start): + self.kiwoom.ohlcv = {'date': [], 'open': [], 'high': [], 'low': [], 'close': [], 'volume': []} + + self.kiwoom.set_input_value("종목코드", code) + self.kiwoom.set_input_value("기준일자", start) + self.kiwoom.set_input_value("수정주가구분", 1) + self.kiwoom.comm_rq_data("opt10081_req", "opt10081", 0, "0101") + #0.2초의 간격을 두어 TR 요청 -> 더 늘려도 될 듯...? + time.sleep(0.5) + + df = DataFrame(self.kiwoom.ohlcv, columns=['open', 'high', 'low', 'close', 'volume'], + index=self.kiwoom.ohlcv['date']) + return df + + #이전 시점의 평균 거래랑을 특정 거래일 이전의 20일 동안의 평균 거래량으로 정의 + #특정 거래일의 거래량이 평균 거래량보다 25% 초과일 때 급등한 것으로 정의 + def check_speedy_rising_volume(self, code): + today = datetime.datetime.today().strftime("%Y%m%d") + df = self.get_ohlcv(code, today) + volumes = df['volume'] + + if len(volumes) < 11: + return False + + sum_vol20 = 0 + today_vol = 0 + + for i, vol in enumerate(volumes): + if i == 0: + today_vol = vol + elif 1 <= i <= 10: + sum_vol20 += vol + else: + break + + avg_vol20 = sum_vol20 / 10 + # 25% 초과인지 알아내는 부분, 초과한다면 True + if today_vol > avg_vol20 * 10: + return True + + #선정된 종목에 대한 정보 파일로 쓰기 + # 매수전이라고 buylist에 적었기 때문에 다음날 코드를 실행하면 pytrader에서 프로그램 실행. + def update_buy_list(self, buy_list): + f = open("buy_list.txt", "wt") + for code in buy_list: + f.writelines("매수;%s;시장가;10;0;매수전\n" % (code)) + f.close() + + def run(self): + buy_list = [] + num = len(self.kosdaq_codes) + + for i, code in enumerate(self.kosdaq_codes): + print(i, '/', num) + if self.check_speedy_rising_volume(code): + buy_list.append(code) + + self.update_buy_list(buy_list) + + def calculate_estimated_dividend_to_treasury(self, code): + estimated_dividend_yield = webreader.get_estimated_dividend_yield(code) + print("calculate_estimated_dividend_to_treasury", estimated_dividend_yield) + if estimated_dividend_yield == 0: + estimated_dividend_yield = webreader.get_dividend_yield(code) + + if estimated_dividend_yield == "": + estimated_dividend_yield = 0 + + current_3year_treasury = webreader.get_current_3year_treasury() + + estimated_dividend_to_treasury = float(estimated_dividend_yield) / float(current_3year_treasury) + return estimated_dividend_to_treasury + + + def get_min_max_dividend_to_treasury(self, code): + previous_dividend_yield = webreader.get_previous_dividend_yield(code) + three_years_treasury = webreader.get_3year_treasury() + + now = datetime.datetime.now() + cur_year = now.year + previous_dividend_to_treasury = {} + + for year in range(cur_year-5, cur_year): + if year in previous_dividend_yield.keys() and year in three_years_treasury.keys(): + ratio = float(previous_dividend_yield[year]) / float(three_years_treasury[year]) + previous_dividend_to_treasury[year] = ratio + + #print(previous_dividend_to_treasury) + if not previous_dividend_yield: + return (0, 0) + + min_ratio = min(previous_dividend_to_treasury.values()) + max_ratio = max(previous_dividend_to_treasury.values()) + + return (min_ratio, max_ratio) + + def buy_check_by_dividend_algorithm(self, code): + estimated_dividend_to_treasury = self.calculate_estimated_dividend_to_treasury(code) + (min_ratio, max_ratio) = self.get_min_max_dividend_to_treasury(code) + + if estimated_dividend_to_treasury >= max_ratio and max_ratio != 0: + return (1, estimated_dividend_to_treasury) + else: + return (0, estimated_dividend_to_treasury) + + + + def run_dividend(self): + buy_list = [] + + for code in self.kospi_codes[100:150]: + time.sleep(0.5) + ret = self.buy_check_by_dividend_algorithm(code) + if ret[0] == 1: + buy_list.append((code, ret[1])) + + sorted_list = sorted(buy_list, key=lambda t:t[1], reverse=True) + + buy_list = [] + for i in range(0, 5): + code = sorted_list[i][0] + buy_list.append(code) + + self.update_buy_list(buy_list) + +if __name__ == "__main__": + app = QApplication(sys.argv) + pymon = PyMon() + pymon.run_dividend() + #print(pymon.calculate_estimated_dividend_to_treasury('058470')) + #print(pymon.get_min_max_dividend_to_treasury("058470")) + #print(pymon.buy_check_by_dividend_algorithm("058470")) diff --git a/pytrader.py b/pytrader.py new file mode 100644 index 0000000..e32d176 --- /dev/null +++ b/pytrader.py @@ -0,0 +1,381 @@ +import sys +from PyQt5.QtCore import * +from Kiwoom import * +from PyQt5.QtWidgets import * +from PyQt5.QtGui import * +from PyQt5 import uic +from widgetfile import * +from PyQt5 import QtCore, QtGui, QtWidgets +import time +from pandas_datareader import data +import matplotlib.pyplot as plt +from matplotlib.figure import Figure +from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas +from mplfinance.original_flavor import candlestick2_ohlc +from datetime import datetime +import matplotlib.ticker as ticker +import os +import plotly.graph_objects as go +import tkinter as tk +from tkinter import ttk +from IPython.display import display +form_class = uic.loadUiType("pytrader.ui")[0] + +start_date = datetime(2020,5,8) +end_date = datetime(2020,10,8) + +dialog = tk.Tk() +dialog1 = tk.Tk() +dialog2 = tk.Tk() + +class MyWindow(QMainWindow, form_class): + def __init__(self): + super().__init__() + self.setupUi(self) + self.trade_stocks_done = False + + self.kiwoom = Kiwoom() + self.kiwoom.comm_connect() + + self.timer = QTimer(self) + self.timer.start(1000) + self.timer.timeout.connect(self.timeout) + + self.timer2 = QTimer(self) + self.timer2.start(1000 *10) + self.timer2.timeout.connect(self.timeout2) + + accouns_num = int(self.kiwoom.get_login_info("ACCOUNT_CNT")) + accounts = self.kiwoom.get_login_info("ACCNO") + + accounts_list = accounts.split(';')[0:accouns_num] + self.comboBox.addItems(accounts_list) + + self.lineEdit.textChanged.connect(self.code_changed) + self.pushButton.clicked.connect(self.send_order) + self.pushButton_2.clicked.connect(self.check_balance) + self.pushButton_4.clicked.connect(self.show_graph) + self.pushButton_5.clicked.connect(self.dialog_open) + self.pushButton_6.clicked.connect(self.dialog_open1) + self.pushButton_7.clicked.connect(self.dialog_open2) + + + # 차트확인하기 버튼 + self.button = QPushButton('차트 확인',self) + self.button.clicked.connect(self.chart) + #self.button.clicked.connect(self.show_graph) + self.button.setGeometry(105,239,75,23) + self.chart = QDialog() + self.canvas = FigureCanvas(Figure()) + + + self.load_buy_sell_list() + + def dialog_open(self): + + label = ttk.Label(dialog, text="현재 날짜를 기준으로 과거 거래 일 별로 시가, 고가, 저가, 종가, 거래량을 가져와 특정 거래일의 거래량이 평균 거래량보다 25% 초과시 매매하는 알고리즘") + label.pack() + dialog.title("급등주") + #self.dialog.geometry("300x300") + label.mainloop() + + # def change_test(self): + # change_label.configure(text="text change") + # change_button + + def dialog_open1(self): + label1 = ttk.Label(dialog1, + text="상위 20개의 종목을 추천하여 매수할 수 있도록 하는 알고리즘") + label1.pack() + dialog.title("신마법공식") + # self.dialog.geometry("300x300") + label1.mainloop() + + def dialog_open2(self): + + label2 = ttk.Label(dialog2, + text="과거의 데이터를 가지고 와 알고리즘 스스로 반복해 공부하여 향후 해당 주가에 대한 예측을 하는 알고리즘") + label2.pack() + dialog.title("주가예측") + # self.dialog.geometry("300x300") + label2.mainloop() + + def show_graph(self): + code = self.lineEdit.text() + self.fig = plt.figure(figsize=(20, 10)) + df1 = data.DataReader(code + ".ks", "yahoo") + ax = self.fig.add_subplot(111) + df1['MA20'] = df1['Adj Close'].rolling(window=20).mean() + df1['MA60'] = df1['Adj Close'].rolling(window=60).mean() + self.graph_viewer.canvas.axes.plot(df1.index, df1['Adj Close'], label='Adj Close') + self.graph_viewer.canvas.axes.plot(df1.index, df1['MA20'], label='MA20') + self.graph_viewer.canvas.axes.plot(df1.index, df1['MA60'], label='MA60') + + data_name = '이동평균선' + #self.graph_viewer.canvas.axes.plot(x_list, y_list, label=data_name) + self.graph_viewer.canvas.axes.legend() + self.graph_viewer.canvas.axes.set_xlabel('Date') + self.graph_viewer.canvas.axes.set_ylabel('주가') + self.graph_viewer.canvas.draw() + + + def chart(self): + self.chart.setGeometry(600, 200, 1200, 600) + self.chart.setWindowTitle("PyChart Viewer v0.1") + self.chart.setWindowIcon(QIcon('icon.png')) + + self.chart.lineEdit = QLineEdit() + self.chart.button1 = QPushButton("차트그리기") + self.chart.button1.clicked.connect(self.ButtonClicked) + + self.chart.button2 = QPushButton("유동성차트 확인") + self.chart.button2.clicked.connect(self.ButtonClicked1) + + self.fig = plt.Figure() + self.canvas = FigureCanvas(self.fig) + + leftLayout = QVBoxLayout() + leftLayout.addWidget(self.canvas) + + # Right Layout + rightLayout = QVBoxLayout() + rightLayout.addWidget(self.lineEdit) + rightLayout.addWidget(self.chart.button1) + rightLayout.addWidget(self.chart.button2) + rightLayout.addStretch(1) + + layout = QHBoxLayout() + layout.addLayout(leftLayout) + layout.addLayout(rightLayout) + layout.setStretchFactor(leftLayout, 1) + layout.setStretchFactor(rightLayout, 0) + + self.chart.setLayout(layout) + self.chart.show() + + def ButtonClicked1(self): + code = self.lineEdit.text() + df = data.DataReader(code + ".ks", "yahoo") + candle = go.Candlestick(x=df.index, + open=df['Open'], + high=df['High'], + low=df['Low'], + close=df['Close']) + fig = go.Figure(data=candle) + fig.show() + + def ButtonClicked(self): + code = self.lineEdit.text() + df = data.DataReader(code + ".ks", "yahoo") + df['MA20'] = df['Adj Close'].rolling(window=20).mean() + df['MA60'] = df['Adj Close'].rolling(window=60).mean() + + ax = self.fig.add_subplot(111) + """ax.plot(df.index, df['Adj Close'], label='Adj Close') + ax.plot(df.index, df['MA20'], label='MA20') + ax.plot(df.index, df['MA60'], label='MA60')""" + ax.legend(loc='upper right') + candlestick2_ohlc(ax, df['Open'], df['High'], + df['Low'], df['Close'], + width=0.5, colorup='r', colordown='b') + ax.set_title('KOSPI INDEX', fontsize=22) + ax.set_xlabel('Date') + ax.grid() + plt.pause(0.001) + self.canvas.draw() + + + + + + def closeEvent(self, event): + + self.deleteLater() + + def trade_stocks(self): + hoga_lookup = {'지정가': "00", '시장가': "03"} + + f = open("buy_list.txt", 'rt', encoding='utf-8') + buy_list = f.readlines() + f.close() + + f = open("sell_list.txt", 'rt', encoding='utf-8') + sell_list = f.readlines() + f.close() + + # account + account = self.comboBox.currentText() + + # buy list + for row_data in buy_list: + split_row_data = row_data.split(';') + hoga = split_row_data[2] + code = split_row_data[1] + num = split_row_data[3] + price = split_row_data[4] + + if split_row_data[-1].rstrip() == '매수전': + self.kiwoom.send_order("send_order_req", "0101", account, 1, code, num, price, hoga_lookup[hoga], "") + + # sell list + for row_data in sell_list: + split_row_data = row_data.split(';') + hoga = split_row_data[2] + code = split_row_data[1] + num = split_row_data[3] + price = split_row_data[4] + + if split_row_data[-1].rstrip() == '매도전': + self.kiwoom.send_order("send_order_req", "0101", account, 2, code, num, price, hoga_lookup[hoga], "") + + # buy list + for i, row_data in enumerate(buy_list): + buy_list[i] = buy_list[i].replace("매수전", "주문완료") + + # file update + f = open("buy_list.txt", 'w', encoding='utf-8') + for row_data in buy_list: + f.write(row_data) + f.close() + + # sell list + for i, row_data in enumerate(sell_list): + sell_list[i] = sell_list[i].replace("매도전", "주문완료") + + # file update + f = open("sell_list.txt", 'w', encoding='utf-8') + for row_data in sell_list: + f.write(row_data) + f.close() + + def load_buy_sell_list(self): + f = open("buy_list.txt", 'rt', encoding='utf-8') + buy_list = f.readlines() + f.close() + + f = open("sell_list.txt", 'rt', encoding='utf-8') + sell_list = f.readlines() + f.close() + + row_count = len(buy_list) + len(sell_list) + self.tableWidget_4.setRowCount(row_count) + + # buy list + for j in range(len(buy_list)): + row_data = buy_list[j] + split_row_data = row_data.split(';') + split_row_data[1] = self.kiwoom.get_master_code_name(split_row_data[1].rsplit()) + + for i in range(len(split_row_data)): + item = QTableWidgetItem(split_row_data[i].rstrip()) + item.setTextAlignment(Qt.AlignVCenter | Qt.AlignCenter) + self.tableWidget_4.setItem(j, i, item) + + # sell list + for j in range(len(sell_list)): + row_data = sell_list[j] + split_row_data = row_data.split(';') + split_row_data[1] = self.kiwoom.get_master_code_name(split_row_data[1].rstrip()) + + for i in range(len(split_row_data)): + item = QTableWidgetItem(split_row_data[i].rstrip()) + item.setTextAlignment(Qt.AlignVCenter | Qt.AlignCenter) + self.tableWidget_4.setItem(len(buy_list) + j, i, item) + + self.tableWidget_4.resizeRowsToContents() + + def code_changed(self): + code = self.lineEdit.text() + name = self.kiwoom.get_master_code_name(code) + self.lineEdit_2.setText(name) + + def send_order(self): + order_type_lookup = {'신규매수': 1, '신규매도': 2, '매수취소': 3, '매도취소': 4} + hoga_lookup = {'지정가': "00", '시장가': "03"} + + account = self.comboBox.currentText() + order_type = self.comboBox_2.currentText() + code = self.lineEdit.text() + hoga = self.comboBox_3.currentText() + num = self.spinBox.value() + price = self.spinBox_2.value() + + self.kiwoom.send_order("send_order_req", "0101", account, order_type_lookup[order_type], code, num, price, hoga_lookup[hoga], "") + + def timeout(self): + market_start_time = QTime(9, 0, 0) + current_time = QTime.currentTime() + + if current_time > market_start_time and self.trade_stocks_done is False: + self.trade_stocks() + self.trade_stocks_done = True + + text_time = current_time.toString("hh:mm:ss") + time_msg = "현재시간: " + text_time + + state = self.kiwoom.get_connect_state() + if state == 1: + state_msg = "서버 연결 중" + else: + state_msg = "서버 미 연결 중" + + self.statusbar.showMessage(state_msg + " | " + time_msg) + + def timeout2(self): + if self.checkBox.isChecked(): + self.check_balance() + + def check_balance(self): + self.kiwoom.reset_opw00018_output() + account_number = self.kiwoom.get_login_info("ACCNO") + account_number = account_number.split(';')[0] + + self.kiwoom.set_input_value("계좌번호", account_number) + self.kiwoom.comm_rq_data("opw00018_req", "opw00018", 0, "2000") + + while self.kiwoom.remained_data: + time.sleep(0.05) + self.kiwoom.set_input_value("계좌번호", account_number) + self.kiwoom.comm_rq_data("opw00018_req", "opw00018", 2, "2000") + + # opw00001 + self.kiwoom.set_input_value("계좌번호", account_number) + self.kiwoom.comm_rq_data("opw00001_req", "opw00001", 0, "2000") + + # balance + item = QTableWidgetItem(self.kiwoom.d2_deposit) + item.setTextAlignment(Qt.AlignVCenter | Qt.AlignRight) + self.tableWidget.setItem(0, 0, item) + + for i in range(1, 6): + item = QTableWidgetItem(self.kiwoom.opw00018_output['single'][i - 1]) + item.setTextAlignment(Qt.AlignVCenter | Qt.AlignRight) + self.tableWidget.setItem(0, i, item) + + self.tableWidget.resizeRowsToContents() + + # Item list + item_count = len(self.kiwoom.opw00018_output['multi']) + self.tableWidget_2.setRowCount(item_count) + + for j in range(item_count): + row = self.kiwoom.opw00018_output['multi'][j] + for i in range(len(row)): + item = QTableWidgetItem(row[i]) + item.setTextAlignment(Qt.AlignVCenter | Qt.AlignRight) + self.tableWidget_2.setItem(j, i, item) + + self.tableWidget_2.resizeRowsToContents() + + def closeEvent(self, event): + + self.deleteLater() + + + +if __name__ == "__main__": + app = QApplication(sys.argv) + myWindow = MyWindow() + myWindow.show() + sys.exit(app.exec()) + window = MWindow() \ No newline at end of file diff --git a/pytrader.ui b/pytrader.ui new file mode 100644 index 0000000..8ced2d5 --- /dev/null +++ b/pytrader.ui @@ -0,0 +1,649 @@ + + + MainWindow + + + + 0 + 0 + 1055 + 789 + + + + PyTrader v0.4 + + + + Auto_Stock-main/Auto_Stock-main/icon.pngAuto_Stock-main/Auto_Stock-main/icon.png + + + background-color:rgb(242, 230, 216); + + + + + + 10 + 19 + 181 + 251 + + + + font: 9pt "나눔고딕"; +background-color: rgb(255, 255, 255); + + + + 수동주문 + + + + + 10 + 20 + 31 + 16 + + + + 계좌 + + + + + + 45 + 15 + 120 + 22 + + + + background-color:rgb(242, 178, 121); + + + + + + + 10 + 50 + 31 + 16 + + + + 주문 + + + + + + 45 + 45 + 120 + 22 + + + + + 신규매수 + + + + + 신규매도 + + + + + 매수취소 + + + + + 매도취소 + + + + + + + 10 + 80 + 31 + 16 + + + + 종목 + + + + + + 45 + 75 + 120 + 20 + + + + + + + 45 + 135 + 120 + 22 + + + + + 지정가 + + + + + 시장가 + + + + + + + 10 + 140 + 31 + 16 + + + + 종류 + + + + + + 10 + 170 + 31 + 16 + + + + 수량 + + + + + + 45 + 165 + 120 + 22 + + + + 1000000 + + + + + + 10 + 200 + 31 + 16 + + + + 가격 + + + + + + 45 + 195 + 120 + 22 + + + + + + + 10000000 + + + 100 + + + 0 + + + + + + 10 + 220 + 75 + 23 + + + + background-color:rgb(242, 178, 121); +border-radius: 20px; +border-color: rgb(255, 255, 255); + + + 현금주문 + + + + + + 45 + 105 + 120 + 20 + + + + background-color:rgb(242, 178, 121); + + + true + + + + + + + 200 + 9 + 831 + 441 + + + + font: 9pt "나눔고딕"; + + + + 잔고 및 보유종목현황 + + + + + 10 + 20 + 811 + 65 + + + + background-color: rgb(255, 255, 255); + + + + 1 + + + 135 + + + + + 예수금 (d+2) + + + + + 총매입 + + + + + 총평가 + + + + + 총손익 + + + + + 총수익률 (%) + + + + + 추정자산 + + + AlignCenter + + + + + + + 750 + 410 + 75 + 23 + + + + background-color:rgb(242, 178, 121); +font: 9pt "나눔고딕"; +border-radius: 25px; +border-color: rgb(255, 255, 255); + + + 조회 + + + + + + 670 + -140 + 611 + 131 + + + + 잔고확인 + + + + + 10 + 20 + 591 + 61 + + + + + 예수금 + + + + + 총매입 + + + + + 총평가 + + + + + 총손익 + + + + + 총수익률 + + + + + 추정자산 + + + + + + + 490 + 90 + 75 + 23 + + + + 현금주문 + + + + + + + 660 + 410 + 81 + 16 + + + + 실시간 조회 + + + + + + 10 + 90 + 811 + 311 + + + + background-color: rgb(255, 255, 255); + + + + 135 + + + + 종목명 + + + + + 보유량 + + + + + 매입가 + + + + + 현재가 + + + + + 평가손익 + + + + + 수익률 (%) + + + + + + + + 0 + 280 + 201 + 201 + + + + font: 9pt "나눔고딕"; + + + + 자동 선정 종목 리스트 + + + + + 10 + 20 + 181 + 171 + + + + background-color: rgb(255, 255, 255); +border-radius:15px; + + + + 주문유형 + + + + + 종목명 + + + + + 호가구분 + + + + + 수량 + + + + + 가격 + + + + + 상태 + + + + + + + + 200 + 459 + 831 + 281 + + + + + + + 20 + 490 + 161 + 41 + + + + background-color:rgb(242, 178, 121); +font: 9pt "나눔고딕"; +border-radius: 15px; +border-color: rgb(255, 255, 255); + + + 그래프 조회 + + + + + + 20 + 550 + 161 + 41 + + + + background-color:rgb(246,211,148); +font: 9pt "나눔고딕"; +border-radius: 15px; +border-color: rgb(255, 255, 255); + + + 알고리즘 설명 + + + + + + 20 + 620 + 161 + 41 + + + + background-color:rgb(242, 178, 121); +font: 9pt "나눔고딕"; +border-radius: 15px; +border-color: rgb(255, 255, 255); + + + 오늘도 공부하는 개미 + + + + + + 20 + 690 + 161 + 41 + + + + background-color:rgb(246,211,148); +font: 9pt "나눔고딕"; +border-radius: 15px; +border-color: rgb(255, 255, 255); + + + 기업 데이터는 여기서~ + + + + + + + 0 + 0 + 1055 + 21 + + + + + + + + Widget + QWidget +
widgetfile.h
+ 1 +
+
+ + +
diff --git a/sell_list.txt b/sell_list.txt new file mode 100644 index 0000000..5c4ea13 --- /dev/null +++ b/sell_list.txt @@ -0,0 +1,5 @@ +매수;001720;시장가;10;0;매수전 +매수;001725;시장가;10;0;매수전 +매수;002460;시장가;10;0;매수전 +매수;001800;시장가;10;0;매수전 +매수;001790;시장가;10;0;매수전 diff --git a/table.html b/table.html new file mode 100644 index 0000000..bccdc85 --- /dev/null +++ b/table.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + +
항목 2013 2014 2015
매출액 100 200 300
+ \ No newline at end of file diff --git a/test.html b/test.html new file mode 100644 index 0000000..7247a6a --- /dev/null +++ b/test.html @@ -0,0 +1,25 @@ + + + + + + + Document + + + + + + + + + + + + + \ No newline at end of file diff --git a/tmp/checkpoint b/tmp/checkpoint new file mode 100644 index 0000000..e6c74d8 --- /dev/null +++ b/tmp/checkpoint @@ -0,0 +1,2 @@ +model_checkpoint_path: "ckeckpointer.ckpt" +all_model_checkpoint_paths: "ckeckpointer.ckpt" diff --git a/tmp/ckeckpointer.ckpt.data-00000-of-00001 b/tmp/ckeckpointer.ckpt.data-00000-of-00001 new file mode 100644 index 0000000..aac2442 Binary files /dev/null and b/tmp/ckeckpointer.ckpt.data-00000-of-00001 differ diff --git a/tmp/ckeckpointer.ckpt.index b/tmp/ckeckpointer.ckpt.index new file mode 100644 index 0000000..3f26f52 Binary files /dev/null and b/tmp/ckeckpointer.ckpt.index differ diff --git a/webreader.py b/webreader.py new file mode 100644 index 0000000..c5c9ed3 --- /dev/null +++ b/webreader.py @@ -0,0 +1,116 @@ +import requests +import pandas as pd +from bs4 import BeautifulSoup +import numpy as np +import datetime + +pd.set_option('display.expand_frame_repr', False) + +import re + + +def get_financial_statements(code): + # 인증값 추출 + re_enc = re.compile("encparam: '(.*)'", re.IGNORECASE) + re_id = re.compile("id: '([a-zA-Z0-9]*)' ?", re.IGNORECASE) + + url = "http://companyinfo.stock.naver.com/v1/company/c1010001.aspx?cmp_cd={}".format(code) + html = requests.get(url, verify=False).text + + search = re_enc.search(html) + if search is None: + return {} + encparam = re_enc.search(html).group(1) + encid = re_id.search(html).group(1) + + # 스크래핑 + url = "http://companyinfo.stock.naver.com/v1/company/ajax/cF1001.aspx?cmp_cd={}&fin_typ=0&freq_typ=A&encparam={}&id={}".format( + code, encparam, encid) + headers = {"Referer": "HACK"} + html = requests.get(url, headers=headers, verify=False).text + + soup = BeautifulSoup(html, "html5lib") + dividend = soup.select("table:nth-of-type(2) tr:nth-of-type(31) td span") + years = soup.select("table:nth-of-type(2) th") + + dividend_dict = {} + for i in range(len(dividend)): + dividend_dict[years[i + 3].text.strip()[:4]] = dividend[i].text + + return dividend_dict + + +def get_3year_treasury(): + url = "http://www.index.go.kr/strata/jsp/showStblGams3.jsp?stts_cd=107301&idx_cd=1073&freq=Y&period=1997%3A2021" + html = requests.get(url, verify=False).text + soup = BeautifulSoup(html, 'html5lib') + td_data = soup.select("tr td") + + treasury_3year = {} + start_year = 1998 + + for x in td_data: + treasury_3year[start_year] = x.text + start_year += 1 + if start_year == datetime.datetime.now().year: + break + + return treasury_3year + + +def get_dividend_yield(code): + url = "http://companyinfo.stock.naver.com/company/c1010001.aspx?cmp_cd=" + code + html = requests.get(url, verify=False).text + + soup = BeautifulSoup(html, 'html5lib') + dt_data = soup.select("td dl dt") + + dividend_yield = dt_data[-2].text + dividend_yield = dividend_yield.split(' ')[1] + dividend_yield = dividend_yield[:-1] + + return dividend_yield + + +def get_estimated_dividend_yield(code): + dividend_yield = get_financial_statements(code) + if len(dividend_yield) == 0: + return 0 + dividend_yield = sorted(dividend_yield.items())[-1] + return dividend_yield[1] + + +def get_current_3year_treasury(): + url = "http://finance.naver.com/marketindex/interestDailyQuote.nhn?marketindexCd=IRR_GOVT03Y&page=1" + html = requests.get(url, verify=False).text + + soup = BeautifulSoup(html, 'html5lib') + td_data = soup.select("tr td") + return td_data[1].text + + +def get_previous_dividend_yield(code): + dividend_yield = get_financial_statements(code) + + now = datetime.datetime.now() + cur_year = now.year + + previous_dividend_yield = {} + + for year in range(cur_year - 5, cur_year): + if str(year) in dividend_yield: + previous_dividend_yield[year] = dividend_yield[str(year)] + + return previous_dividend_yield + + +if __name__ == "__main__": + estimated_dividend_yield = get_estimated_dividend_yield("058470") + print(estimated_dividend_yield) + current_3year_treasury = get_current_3year_treasury() + print(current_3year_treasury) + estimated_dividend_to_treasury = float(estimated_dividend_yield) / float(current_3year_treasury) + print(estimated_dividend_to_treasury) + # print(get_estimated_dividend_yield('058470')) + # print(get_current_3year_treasury()) + # print(get_previous_dividend_yield('058470')) \ No newline at end of file diff --git a/widgetfile.py b/widgetfile.py new file mode 100644 index 0000000..a069c32 --- /dev/null +++ b/widgetfile.py @@ -0,0 +1,15 @@ +from PyQt5.QtWidgets import* +from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.figure import Figure + + +class Widget(QWidget): + + def __init__(self, parent = None): + QWidget.__init__(self, parent) + self.canvas = FigureCanvas(Figure()) + vertical_layout=QVBoxLayout() + vertical_layout.addWidget(self.canvas) + vertical_layout.setContentsMargins(1, 1, 1, 1) + self.canvas.axes=self.canvas.figure.add_subplot(111) + self.setLayout(vertical_layout)\