analyser_hj3415 2.7.8__py2.py3-none-any.whl → 2.8.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- analyser_hj3415/{myprophet.py → tsa.py} +86 -26
- {analyser_hj3415-2.7.8.dist-info → analyser_hj3415-2.8.0.dist-info}/METADATA +1 -1
- {analyser_hj3415-2.7.8.dist-info → analyser_hj3415-2.8.0.dist-info}/RECORD +6 -6
- {analyser_hj3415-2.7.8.dist-info → analyser_hj3415-2.8.0.dist-info}/LICENSE +0 -0
- {analyser_hj3415-2.7.8.dist-info → analyser_hj3415-2.8.0.dist-info}/WHEEL +0 -0
- {analyser_hj3415-2.7.8.dist-info → analyser_hj3415-2.8.0.dist-info}/entry_points.txt +0 -0
@@ -1,24 +1,36 @@
|
|
1
|
+
"""
|
2
|
+
Time Series Analysis
|
3
|
+
"""
|
1
4
|
import yfinance as yf
|
2
5
|
from datetime import datetime, timedelta
|
3
6
|
import pandas as pd
|
4
7
|
from prophet import Prophet
|
5
8
|
from sklearn.preprocessing import StandardScaler
|
6
|
-
from utils_hj3415 import utils
|
9
|
+
from utils_hj3415 import utils, helpers
|
7
10
|
from typing import Optional
|
8
11
|
import plotly.graph_objs as go
|
9
12
|
from plotly.offline import plot
|
10
13
|
import matplotlib.pyplot as plt # Matplotlib 수동 임포트
|
11
14
|
from db_hj3415 import myredis
|
15
|
+
from collections import OrderedDict
|
16
|
+
from analyser_hj3415 import eval
|
17
|
+
|
18
|
+
import logging
|
19
|
+
analyser_logger = helpers.setup_logger('analyser_logger', logging.WARNING)
|
20
|
+
|
21
|
+
expire_time = 3600 * 12
|
12
22
|
|
13
23
|
class MyProphet:
|
14
24
|
def __init__(self, code: str):
|
15
25
|
assert utils.is_6digit(code), f'Invalid value : {code}'
|
16
|
-
self._code = code
|
17
|
-
self.name = myredis.Corps(code, 'c101').get_name()
|
18
|
-
self.raw_data = self.get_raw_data()
|
19
|
-
|
20
26
|
self.scaler = StandardScaler()
|
27
|
+
|
21
28
|
self.model = Prophet()
|
29
|
+
self._code = code
|
30
|
+
self.name = myredis.Corps(code, 'c101').get_name()
|
31
|
+
self.raw_data = self._get_raw_data()
|
32
|
+
self.df_real = self._preprocessing_for_prophet()
|
33
|
+
self.df_forecast = self._make_forecast()
|
22
34
|
|
23
35
|
@property
|
24
36
|
def code(self) -> str:
|
@@ -27,11 +39,25 @@ class MyProphet:
|
|
27
39
|
@code.setter
|
28
40
|
def code(self, code: str):
|
29
41
|
assert utils.is_6digit(code), f'Invalid value : {code}'
|
42
|
+
analyser_logger.info(f'change code : {self.code} -> {code}')
|
43
|
+
self.model = Prophet()
|
30
44
|
self._code = code
|
31
45
|
self.name = myredis.Corps(code, 'c101').get_name()
|
32
|
-
self.raw_data = self.
|
33
|
-
|
34
|
-
|
46
|
+
self.raw_data = self._get_raw_data()
|
47
|
+
self.df_real = self._preprocessing_for_prophet()
|
48
|
+
self.df_forecast = self._make_forecast()
|
49
|
+
|
50
|
+
@staticmethod
|
51
|
+
def is_valid_date(date_string):
|
52
|
+
try:
|
53
|
+
# %Y-%m-%d 형식으로 문자열을 datetime 객체로 변환 시도
|
54
|
+
datetime.strptime(date_string, '%Y-%m-%d')
|
55
|
+
return True
|
56
|
+
except ValueError:
|
57
|
+
# 변환이 실패하면 ValueError가 발생, 형식이 맞지 않음
|
58
|
+
return False
|
59
|
+
|
60
|
+
def _get_raw_data(self) -> pd.DataFrame:
|
35
61
|
"""
|
36
62
|
야후에서 해당 종목의 4년간 주가 raw data를 받아온다.
|
37
63
|
:return:
|
@@ -48,7 +74,7 @@ class MyProphet:
|
|
48
74
|
end=today.strftime('%Y-%m-%d')
|
49
75
|
)
|
50
76
|
|
51
|
-
def
|
77
|
+
def _preprocessing_for_prophet(self) -> pd.DataFrame:
|
52
78
|
"""
|
53
79
|
Prophet이 사용할 수 있도록 데이터 준비
|
54
80
|
ds는 날짜, y는 주가
|
@@ -61,14 +87,11 @@ class MyProphet:
|
|
61
87
|
df['volume_scaled'] = self.scaler.fit_transform(df[['volume']])
|
62
88
|
return df
|
63
89
|
|
64
|
-
def
|
65
|
-
# Prophet을 위한 dataframe 만들기
|
66
|
-
df_for_prophet = self.preprocessing_for_prophet()
|
67
|
-
|
90
|
+
def _make_forecast(self) -> pd.DataFrame:
|
68
91
|
# 정규화된 'volume_scaled' 변수를 외부 변수로 추가
|
69
92
|
self.model.add_regressor('volume_scaled')
|
70
93
|
|
71
|
-
self.model.fit(
|
94
|
+
self.model.fit(self.df_real)
|
72
95
|
|
73
96
|
# 향후 180일 동안의 주가 예측
|
74
97
|
future = self.model.make_future_dataframe(periods=180)
|
@@ -80,30 +103,36 @@ class MyProphet:
|
|
80
103
|
forecast = self.model.predict(future)
|
81
104
|
return forecast
|
82
105
|
|
106
|
+
def get_yhat(self) -> dict:
|
107
|
+
"""
|
108
|
+
예측하는 첫째날의 예측 데이터를 반환한다.
|
109
|
+
:return: {'ds':..., 'yhat':.., 'yhat_lower':.., 'yhat_upper':..,}
|
110
|
+
"""
|
111
|
+
df = self.df_forecast
|
112
|
+
analyser_logger.debug(df)
|
113
|
+
yhat_dict = df.iloc[0][['ds', 'yhat_lower', 'yhat_upper', 'yhat']].to_dict()
|
114
|
+
analyser_logger.info(yhat_dict)
|
115
|
+
return yhat_dict
|
116
|
+
|
83
117
|
def export_to(self, to="str") -> Optional[str]:
|
84
118
|
"""
|
85
119
|
prophet과 plotly로 그래프를 그려서 html을 문자열로 반환
|
86
120
|
:param to: str, png, htmlfile, show
|
87
121
|
:return:
|
88
122
|
"""
|
89
|
-
# 실제 데이터
|
90
|
-
df = self.preprocessing_for_prophet()
|
91
|
-
# 예측 데이터
|
92
|
-
forecast = self.make_forecast()
|
93
|
-
|
94
123
|
# Plotly를 사용한 시각화
|
95
124
|
fig = go.Figure()
|
96
125
|
|
97
126
|
# 실제 데이터
|
98
|
-
fig.add_trace(go.Scatter(x=
|
127
|
+
fig.add_trace(go.Scatter(x=self.df_real['ds'], y=self.df_real['y'], mode='markers', name='실제주가'))
|
99
128
|
# 예측 데이터
|
100
|
-
fig.add_trace(go.Scatter(x=
|
129
|
+
fig.add_trace(go.Scatter(x=self.df_forecast['ds'], y=self.df_forecast['yhat'], mode='lines', name='예측치'))
|
101
130
|
|
102
131
|
# 상한/하한 구간
|
103
132
|
fig.add_trace(
|
104
|
-
go.Scatter(x=
|
133
|
+
go.Scatter(x=self.df_forecast['ds'], y=self.df_forecast['yhat_upper'], fill=None, mode='lines', name='상한'))
|
105
134
|
fig.add_trace(
|
106
|
-
go.Scatter(x=
|
135
|
+
go.Scatter(x=self.df_forecast['ds'], y=self.df_forecast['yhat_lower'], fill='tonexty', mode='lines', name='하한'))
|
107
136
|
|
108
137
|
fig.update_layout(
|
109
138
|
title=f'{self.code} {self.name} 주가 예측 그래프(prophet)',
|
@@ -130,15 +159,46 @@ class MyProphet:
|
|
130
159
|
return None
|
131
160
|
elif to == 'show':
|
132
161
|
# 예측 결과 출력
|
133
|
-
print(
|
162
|
+
print(self.df_forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())
|
134
163
|
# 예측 결과 시각화 (Matplotlib 사용)
|
135
|
-
fig = self.model.plot(
|
164
|
+
fig = self.model.plot(self.df_forecast)
|
136
165
|
# 추세 및 계절성 시각화
|
137
|
-
fig2 = self.model.plot_components(
|
166
|
+
fig2 = self.model.plot_components(self.df_forecast)
|
138
167
|
plt.show() # 시각화 창 띄우기
|
139
168
|
else:
|
140
169
|
Exception("to 인자가 맞지 않습니다.")
|
141
170
|
|
171
|
+
@classmethod
|
172
|
+
def ranking(cls, refresh = False) -> OrderedDict:
|
173
|
+
"""
|
174
|
+
가장 최근 날짜의 랭킹 분석
|
175
|
+
:param refresh:
|
176
|
+
:return:
|
177
|
+
"""
|
178
|
+
print("**** Start myprophet_ranking... ****")
|
179
|
+
redis_name = 'myprophet_ranking'
|
180
|
+
|
181
|
+
print(
|
182
|
+
f"redisname: '{redis_name}' / refresh : {refresh} / expire_time : {expire_time / 3600}h")
|
183
|
+
|
184
|
+
def fetch_ranking() -> dict:
|
185
|
+
data = {}
|
186
|
+
p = MyProphet('005930')
|
187
|
+
for i, code in enumerate(myredis.Corps.list_all_codes()):
|
188
|
+
p.code = code
|
189
|
+
recent_price = p._preprocessing_for_prophet().iloc[-1]['y']
|
190
|
+
yhat_dict = p.get_yhat()
|
191
|
+
analyser_logger.info(f'recent_price: {recent_price}, yhat_dict: {yhat_dict}')
|
192
|
+
yhat_lower = int(yhat_dict['yhat_lower'])
|
193
|
+
if recent_price < yhat_lower:
|
194
|
+
deviation = int(eval.Tools.cal_deviation(recent_price, yhat_lower))
|
195
|
+
data[code] = deviation
|
196
|
+
print(f"{i}.{p.code}/{p.name} 최근가격:{recent_price} 기대하한값:{yhat_lower} 편차:{deviation}")
|
197
|
+
return data
|
198
|
+
|
199
|
+
data_dict = myredis.Base.fetch_and_cache_data(redis_name, refresh, fetch_ranking, timer=expire_time)
|
200
|
+
|
201
|
+
return OrderedDict(sorted(data_dict.items(), key=lambda item: item[1], reverse=True))
|
142
202
|
|
143
203
|
|
144
204
|
|
@@ -2,15 +2,15 @@ analyser_hj3415/.DS_Store,sha256=qr9-0FPn5CFKe6kEu8_dWCNhzQ0sN7bwQgffKsaJEEo,614
|
|
2
2
|
analyser_hj3415/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
analyser_hj3415/cli.py,sha256=7ys-b9H_tJAbLLi_XpjmEvDiyNHddpg9F1FNAACfWnE,11005
|
4
4
|
analyser_hj3415/eval.py,sha256=4F0GIknCogAhv_iTq8auLrmwW20u8kH0HY0fP4SaVa4,39099
|
5
|
-
analyser_hj3415/
|
5
|
+
analyser_hj3415/tsa.py,sha256=4fg92xzEnp9kChvEzXbnAv6jGLuDK4zMaZjBoobp6I0,7649
|
6
6
|
analyser_hj3415/workroom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
7
|
analyser_hj3415/workroom/lstm.py,sha256=gF7i1NqPOhNysvkSQcC_mkOmvLk96jPxoqajZ-FFD8I,4078
|
8
8
|
analyser_hj3415/workroom/mysklearn.py,sha256=wJXKz5MqqTzADdG2mqRMMzc_G9RzwYjj5_j4gyOopxQ,2030
|
9
9
|
analyser_hj3415/workroom/mysklearn2.py,sha256=1lIy6EWEQHkOzDS-av8U0zQH6DuCLKWMI73dnJx5KRs,1495
|
10
10
|
analyser_hj3415/workroom/score.py,sha256=P6nHBJYmyhigGtT4qna4BmNtvt4B93b7SKyzdstJK24,17376
|
11
11
|
analyser_hj3415/workroom/trash.py,sha256=zF-W0piqkGr66UP6-iybo9EXh2gO0RP6R1FnIpsGkl8,12262
|
12
|
-
analyser_hj3415-2.
|
13
|
-
analyser_hj3415-2.
|
14
|
-
analyser_hj3415-2.
|
15
|
-
analyser_hj3415-2.
|
16
|
-
analyser_hj3415-2.
|
12
|
+
analyser_hj3415-2.8.0.dist-info/entry_points.txt,sha256=ZfjPnJuH8SzvhE9vftIPMBIofsc65IAWYOhqOC_L5ck,65
|
13
|
+
analyser_hj3415-2.8.0.dist-info/LICENSE,sha256=QVKTp0dTnB5xG8RLgG17LwSWCKNEzYoVVM6KjoCPKc0,1079
|
14
|
+
analyser_hj3415-2.8.0.dist-info/WHEEL,sha256=Sgu64hAMa6g5FdzHxXv9Xdse9yxpGGMeagVtPMWpJQY,99
|
15
|
+
analyser_hj3415-2.8.0.dist-info/METADATA,sha256=4Zf9g7uum4fIQqqY1IF0_HRzQwT-JAJvAPdfRY0eW9Q,6607
|
16
|
+
analyser_hj3415-2.8.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|