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.
@@ -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.get_raw_data()
33
-
34
- def get_raw_data(self) -> pd.DataFrame:
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 preprocessing_for_prophet(self) -> pd.DataFrame:
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 make_forecast(self) -> pd.DataFrame:
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(df_for_prophet)
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=df['ds'], y=df['y'], mode='markers', name='실제주가'))
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=forecast['ds'], y=forecast['yhat'], mode='lines', name='예측치'))
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=forecast['ds'], y=forecast['yhat_upper'], fill=None, mode='lines', name='상한'))
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=forecast['ds'], y=forecast['yhat_lower'], fill='tonexty', mode='lines', name='하한'))
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(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())
162
+ print(self.df_forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())
134
163
  # 예측 결과 시각화 (Matplotlib 사용)
135
- fig = self.model.plot(forecast)
164
+ fig = self.model.plot(self.df_forecast)
136
165
  # 추세 및 계절성 시각화
137
- fig2 = self.model.plot_components(forecast)
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: analyser_hj3415
3
- Version: 2.7.8
3
+ Version: 2.8.0
4
4
  Summary: Stock analyser and database processing programs
5
5
  Author-email: Hyungjin Kim <hj3415@gmail.com>
6
6
  Description-Content-Type: text/markdown
@@ -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/myprophet.py,sha256=N_eUzAmrbEuqJBJ9OqbnMrHC3_kc3JXGq6pND5o4yuE,5096
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.7.8.dist-info/entry_points.txt,sha256=ZfjPnJuH8SzvhE9vftIPMBIofsc65IAWYOhqOC_L5ck,65
13
- analyser_hj3415-2.7.8.dist-info/LICENSE,sha256=QVKTp0dTnB5xG8RLgG17LwSWCKNEzYoVVM6KjoCPKc0,1079
14
- analyser_hj3415-2.7.8.dist-info/WHEEL,sha256=Sgu64hAMa6g5FdzHxXv9Xdse9yxpGGMeagVtPMWpJQY,99
15
- analyser_hj3415-2.7.8.dist-info/METADATA,sha256=Ru0TFe19ItTPkffO_39zz7vuX0b78V7EZoiO4f1wCEM,6607
16
- analyser_hj3415-2.7.8.dist-info/RECORD,,
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,,