commit
bee0f632a6
33 changed files with 1853 additions and 0 deletions
-
3.idea/.gitignore
-
1.idea/.name
-
8.idea/Auto_stock.iml
-
6.idea/inspectionProfiles/profiles_settings.xml
-
7.idea/misc.xml
-
8.idea/modules.xml
-
6.idea/vcs.xml
-
220Kiwoom.py
-
BIN__pycache__/Kiwoom.cpython-37.pyc
-
BIN__pycache__/Kiwoom.cpython-38.pyc
-
BIN__pycache__/Kiwoom.cpython-39.pyc
-
BIN__pycache__/webreader.cpython-37.pyc
-
BIN__pycache__/webreader.cpython-38.pyc
-
BIN__pycache__/widgetfile.cpython-37.pyc
-
BIN__pycache__/widgetfile.cpython-38.pyc
-
0buy_list.txt
-
2icon.png.url
-
0java.js
-
BINmagic.xlsx
-
73magic_formula.py
-
BINmagic_formula_data.xlsx
-
154predict.py
-
155pymon.py
-
381pytrader.py
-
649pytrader.ui
-
5sell_list.txt
-
17table.html
-
25test.html
-
2tmp/checkpoint
-
BINtmp/ckeckpointer.ckpt.data-00000-of-00001
-
BINtmp/ckeckpointer.ckpt.index
-
116webreader.py
-
15widgetfile.py
@ -0,0 +1,3 @@ |
|||
# Default ignored files |
|||
/shelf/ |
|||
/workspace.xml |
|||
@ -0,0 +1 @@ |
|||
predict.py |
|||
@ -0,0 +1,8 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<module type="PYTHON_MODULE" version="4"> |
|||
<component name="NewModuleRootManager"> |
|||
<content url="file://$MODULE_DIR$" /> |
|||
<orderEntry type="jdk" jdkName="Python 3.7 (5)" jdkType="Python SDK" /> |
|||
<orderEntry type="sourceFolder" forTests="false" /> |
|||
</component> |
|||
</module> |
|||
@ -0,0 +1,6 @@ |
|||
<component name="InspectionProjectProfileManager"> |
|||
<settings> |
|||
<option name="USE_PROJECT_PROFILE" value="false" /> |
|||
<version value="1.0" /> |
|||
</settings> |
|||
</component> |
|||
@ -0,0 +1,7 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (5)" project-jdk-type="Python SDK" /> |
|||
<component name="PyCharmProfessionalAdvertiser"> |
|||
<option name="shown" value="true" /> |
|||
</component> |
|||
</project> |
|||
@ -0,0 +1,8 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="ProjectModuleManager"> |
|||
<modules> |
|||
<module fileurl="file://$PROJECT_DIR$/.idea/Auto_stock.iml" filepath="$PROJECT_DIR$/.idea/Auto_stock.iml" /> |
|||
</modules> |
|||
</component> |
|||
</project> |
|||
@ -0,0 +1,6 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="VcsDirectoryMappings"> |
|||
<mapping directory="$PROJECT_DIR$" vcs="Git" /> |
|||
</component> |
|||
</project> |
|||
@ -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']) |
|||
@ -0,0 +1,2 @@ |
|||
[InternetShortcut] |
|||
URL=https://github.com/pystockhub/book/blob/master/ch18/day04/icon.png |
|||
@ -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') |
|||
|
|||
|
|||
|
|||
@ -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() |
|||
@ -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")) |
|||
@ -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() |
|||
@ -0,0 +1,649 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<ui version="4.0"> |
|||
<class>MainWindow</class> |
|||
<widget class="QMainWindow" name="MainWindow"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>0</x> |
|||
<y>0</y> |
|||
<width>1055</width> |
|||
<height>789</height> |
|||
</rect> |
|||
</property> |
|||
<property name="windowTitle"> |
|||
<string>PyTrader v0.4</string> |
|||
</property> |
|||
<property name="windowIcon"> |
|||
<iconset> |
|||
<normaloff>Auto_Stock-main/Auto_Stock-main/icon.png</normaloff>Auto_Stock-main/Auto_Stock-main/icon.png</iconset> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color:rgb(242, 230, 216);</string> |
|||
</property> |
|||
<widget class="QWidget" name="centralwidget"> |
|||
<widget class="QGroupBox" name="groupBox"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>19</y> |
|||
<width>181</width> |
|||
<height>251</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">font: 9pt "나눔고딕"; |
|||
background-color: rgb(255, 255, 255); |
|||
</string> |
|||
</property> |
|||
<property name="title"> |
|||
<string>수동주문</string> |
|||
</property> |
|||
<widget class="QLabel" name="label"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>20</y> |
|||
<width>31</width> |
|||
<height>16</height> |
|||
</rect> |
|||
</property> |
|||
<property name="text"> |
|||
<string>계좌</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QComboBox" name="comboBox"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>45</x> |
|||
<y>15</y> |
|||
<width>120</width> |
|||
<height>22</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color:rgb(242, 178, 121); |
|||
</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QLabel" name="label_2"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>50</y> |
|||
<width>31</width> |
|||
<height>16</height> |
|||
</rect> |
|||
</property> |
|||
<property name="text"> |
|||
<string>주문</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QComboBox" name="comboBox_2"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>45</x> |
|||
<y>45</y> |
|||
<width>120</width> |
|||
<height>22</height> |
|||
</rect> |
|||
</property> |
|||
<item> |
|||
<property name="text"> |
|||
<string>신규매수</string> |
|||
</property> |
|||
</item> |
|||
<item> |
|||
<property name="text"> |
|||
<string>신규매도</string> |
|||
</property> |
|||
</item> |
|||
<item> |
|||
<property name="text"> |
|||
<string>매수취소</string> |
|||
</property> |
|||
</item> |
|||
<item> |
|||
<property name="text"> |
|||
<string>매도취소</string> |
|||
</property> |
|||
</item> |
|||
</widget> |
|||
<widget class="QLabel" name="label_3"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>80</y> |
|||
<width>31</width> |
|||
<height>16</height> |
|||
</rect> |
|||
</property> |
|||
<property name="text"> |
|||
<string>종목</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QLineEdit" name="lineEdit"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>45</x> |
|||
<y>75</y> |
|||
<width>120</width> |
|||
<height>20</height> |
|||
</rect> |
|||
</property> |
|||
</widget> |
|||
<widget class="QComboBox" name="comboBox_3"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>45</x> |
|||
<y>135</y> |
|||
<width>120</width> |
|||
<height>22</height> |
|||
</rect> |
|||
</property> |
|||
<item> |
|||
<property name="text"> |
|||
<string>지정가</string> |
|||
</property> |
|||
</item> |
|||
<item> |
|||
<property name="text"> |
|||
<string>시장가</string> |
|||
</property> |
|||
</item> |
|||
</widget> |
|||
<widget class="QLabel" name="label_4"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>140</y> |
|||
<width>31</width> |
|||
<height>16</height> |
|||
</rect> |
|||
</property> |
|||
<property name="text"> |
|||
<string>종류</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QLabel" name="label_5"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>170</y> |
|||
<width>31</width> |
|||
<height>16</height> |
|||
</rect> |
|||
</property> |
|||
<property name="text"> |
|||
<string>수량</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QSpinBox" name="spinBox"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>45</x> |
|||
<y>165</y> |
|||
<width>120</width> |
|||
<height>22</height> |
|||
</rect> |
|||
</property> |
|||
<property name="maximum"> |
|||
<number>1000000</number> |
|||
</property> |
|||
</widget> |
|||
<widget class="QLabel" name="label_6"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>200</y> |
|||
<width>31</width> |
|||
<height>16</height> |
|||
</rect> |
|||
</property> |
|||
<property name="text"> |
|||
<string>가격</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QSpinBox" name="spinBox_2"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>45</x> |
|||
<y>195</y> |
|||
<width>120</width> |
|||
<height>22</height> |
|||
</rect> |
|||
</property> |
|||
<property name="prefix"> |
|||
<string/> |
|||
</property> |
|||
<property name="maximum"> |
|||
<number>10000000</number> |
|||
</property> |
|||
<property name="singleStep"> |
|||
<number>100</number> |
|||
</property> |
|||
<property name="value"> |
|||
<number>0</number> |
|||
</property> |
|||
</widget> |
|||
<widget class="QPushButton" name="pushButton"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>220</y> |
|||
<width>75</width> |
|||
<height>23</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color:rgb(242, 178, 121); |
|||
border-radius: 20px; |
|||
border-color: rgb(255, 255, 255);</string> |
|||
</property> |
|||
<property name="text"> |
|||
<string>현금주문</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QLineEdit" name="lineEdit_2"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>45</x> |
|||
<y>105</y> |
|||
<width>120</width> |
|||
<height>20</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color:rgb(242, 178, 121);</string> |
|||
</property> |
|||
<property name="readOnly"> |
|||
<bool>true</bool> |
|||
</property> |
|||
</widget> |
|||
</widget> |
|||
<widget class="QGroupBox" name="groupBox_2"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>200</x> |
|||
<y>9</y> |
|||
<width>831</width> |
|||
<height>441</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">font: 9pt "나눔고딕"; |
|||
</string> |
|||
</property> |
|||
<property name="title"> |
|||
<string>잔고 및 보유종목현황</string> |
|||
</property> |
|||
<widget class="QTableWidget" name="tableWidget"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>20</y> |
|||
<width>811</width> |
|||
<height>65</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color: rgb(255, 255, 255); |
|||
</string> |
|||
</property> |
|||
<property name="rowCount"> |
|||
<number>1</number> |
|||
</property> |
|||
<attribute name="horizontalHeaderDefaultSectionSize"> |
|||
<number>135</number> |
|||
</attribute> |
|||
<row/> |
|||
<column> |
|||
<property name="text"> |
|||
<string>예수금 (d+2)</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>총매입</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>총평가</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>총손익</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>총수익률 (%)</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>추정자산</string> |
|||
</property> |
|||
<property name="textAlignment"> |
|||
<set>AlignCenter</set> |
|||
</property> |
|||
</column> |
|||
</widget> |
|||
<widget class="QPushButton" name="pushButton_2"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>750</x> |
|||
<y>410</y> |
|||
<width>75</width> |
|||
<height>23</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color:rgb(242, 178, 121); |
|||
font: 9pt "나눔고딕"; |
|||
border-radius: 25px; |
|||
border-color: rgb(255, 255, 255);</string> |
|||
</property> |
|||
<property name="text"> |
|||
<string>조회</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QGroupBox" name="groupBox_4"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>670</x> |
|||
<y>-140</y> |
|||
<width>611</width> |
|||
<height>131</height> |
|||
</rect> |
|||
</property> |
|||
<property name="title"> |
|||
<string>잔고확인</string> |
|||
</property> |
|||
<widget class="QTableWidget" name="tableWidget_3"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>20</y> |
|||
<width>591</width> |
|||
<height>61</height> |
|||
</rect> |
|||
</property> |
|||
<column> |
|||
<property name="text"> |
|||
<string>예수금</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>총매입</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>총평가</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>총손익</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>총수익률</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>추정자산</string> |
|||
</property> |
|||
</column> |
|||
</widget> |
|||
<widget class="QPushButton" name="pushButton_3"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>490</x> |
|||
<y>90</y> |
|||
<width>75</width> |
|||
<height>23</height> |
|||
</rect> |
|||
</property> |
|||
<property name="text"> |
|||
<string>현금주문</string> |
|||
</property> |
|||
</widget> |
|||
</widget> |
|||
<widget class="QCheckBox" name="checkBox"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>660</x> |
|||
<y>410</y> |
|||
<width>81</width> |
|||
<height>16</height> |
|||
</rect> |
|||
</property> |
|||
<property name="text"> |
|||
<string>실시간 조회</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QTableWidget" name="tableWidget_2"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>90</y> |
|||
<width>811</width> |
|||
<height>311</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color: rgb(255, 255, 255); |
|||
</string> |
|||
</property> |
|||
<attribute name="horizontalHeaderDefaultSectionSize"> |
|||
<number>135</number> |
|||
</attribute> |
|||
<column> |
|||
<property name="text"> |
|||
<string>종목명</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>보유량</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>매입가</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>현재가</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>평가손익</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>수익률 (%)</string> |
|||
</property> |
|||
</column> |
|||
</widget> |
|||
</widget> |
|||
<widget class="QGroupBox" name="groupBox_3"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>0</x> |
|||
<y>280</y> |
|||
<width>201</width> |
|||
<height>201</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">font: 9pt "나눔고딕"; |
|||
</string> |
|||
</property> |
|||
<property name="title"> |
|||
<string>자동 선정 종목 리스트</string> |
|||
</property> |
|||
<widget class="QTableWidget" name="tableWidget_4"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>10</x> |
|||
<y>20</y> |
|||
<width>181</width> |
|||
<height>171</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color: rgb(255, 255, 255); |
|||
border-radius:15px;</string> |
|||
</property> |
|||
<column> |
|||
<property name="text"> |
|||
<string>주문유형</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>종목명</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>호가구분</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>수량</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>가격</string> |
|||
</property> |
|||
</column> |
|||
<column> |
|||
<property name="text"> |
|||
<string>상태</string> |
|||
</property> |
|||
</column> |
|||
</widget> |
|||
</widget> |
|||
<widget class="Widget" name="graph_viewer" native="true"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>200</x> |
|||
<y>459</y> |
|||
<width>831</width> |
|||
<height>281</height> |
|||
</rect> |
|||
</property> |
|||
</widget> |
|||
<widget class="QPushButton" name="pushButton_4"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>20</x> |
|||
<y>490</y> |
|||
<width>161</width> |
|||
<height>41</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color:rgb(242, 178, 121); |
|||
font: 9pt "나눔고딕"; |
|||
border-radius: 15px; |
|||
border-color: rgb(255, 255, 255);</string> |
|||
</property> |
|||
<property name="text"> |
|||
<string>그래프 조회</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QPushButton" name="pushButton_5"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>20</x> |
|||
<y>550</y> |
|||
<width>161</width> |
|||
<height>41</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color:rgb(246,211,148); |
|||
font: 9pt "나눔고딕"; |
|||
border-radius: 15px; |
|||
border-color: rgb(255, 255, 255);</string> |
|||
</property> |
|||
<property name="text"> |
|||
<string>알고리즘 설명</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QPushButton" name="pushButton_6"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>20</x> |
|||
<y>620</y> |
|||
<width>161</width> |
|||
<height>41</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color:rgb(242, 178, 121); |
|||
font: 9pt "나눔고딕"; |
|||
border-radius: 15px; |
|||
border-color: rgb(255, 255, 255);</string> |
|||
</property> |
|||
<property name="text"> |
|||
<string>오늘도 공부하는 개미</string> |
|||
</property> |
|||
</widget> |
|||
<widget class="QPushButton" name="pushButton_7"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>20</x> |
|||
<y>690</y> |
|||
<width>161</width> |
|||
<height>41</height> |
|||
</rect> |
|||
</property> |
|||
<property name="styleSheet"> |
|||
<string notr="true">background-color:rgb(246,211,148); |
|||
font: 9pt "나눔고딕"; |
|||
border-radius: 15px; |
|||
border-color: rgb(255, 255, 255);</string> |
|||
</property> |
|||
<property name="text"> |
|||
<string>기업 데이터는 여기서~</string> |
|||
</property> |
|||
</widget> |
|||
</widget> |
|||
<widget class="QMenuBar" name="menubar"> |
|||
<property name="geometry"> |
|||
<rect> |
|||
<x>0</x> |
|||
<y>0</y> |
|||
<width>1055</width> |
|||
<height>21</height> |
|||
</rect> |
|||
</property> |
|||
</widget> |
|||
<widget class="QStatusBar" name="statusbar"/> |
|||
</widget> |
|||
<customwidgets> |
|||
<customwidget> |
|||
<class>Widget</class> |
|||
<extends>QWidget</extends> |
|||
<header>widgetfile.h</header> |
|||
<container>1</container> |
|||
</customwidget> |
|||
</customwidgets> |
|||
<resources/> |
|||
<connections/> |
|||
</ui> |
|||
@ -0,0 +1,5 @@ |
|||
매수;001720;시장가;10;0;매수전 |
|||
매수;001725;시장가;10;0;매수전 |
|||
매수;002460;시장가;10;0;매수전 |
|||
매수;001800;시장가;10;0;매수전 |
|||
매수;001790;시장가;10;0;매수전 |
|||
@ -0,0 +1,17 @@ |
|||
<html> |
|||
<table border=1> |
|||
<tr> |
|||
<td> 항목 </td> |
|||
<td> 2013 </td> |
|||
<td> 2014 </td> |
|||
<td> 2015 </td> |
|||
</tr> |
|||
|
|||
<tr> |
|||
<td> 매출액 </td> |
|||
<td> 100 </td> |
|||
<td> 200 </td> |
|||
<td> 300 </td> |
|||
</tr> |
|||
</table> |
|||
</html> |
|||
@ -0,0 +1,25 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Document</title> |
|||
</head> |
|||
|
|||
<body> |
|||
<Script> |
|||
var account = { |
|||
예금주:"황기태", 계좌번호:"711-21-902010", 잔액:"20000" |
|||
} |
|||
document.write(account); |
|||
</Script> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,2 @@ |
|||
model_checkpoint_path: "ckeckpointer.ckpt" |
|||
all_model_checkpoint_paths: "ckeckpointer.ckpt" |
|||
@ -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')) |
|||
@ -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)\ |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue