analyser_hj3415 2.7.7__tar.gz → 2.8.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/PKG-INFO +7 -1
  2. analyser_hj3415-2.8.0/analyser_hj3415/tsa.py +204 -0
  3. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/analyser_hj3415/workroom/lstm.py +3 -3
  4. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/pyproject.toml +7 -1
  5. analyser_hj3415-2.7.7/analyser_hj3415/workroom/myprophet.py +0 -58
  6. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/.DS_Store +0 -0
  7. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/.gitattributes +0 -0
  8. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/.gitignore +0 -0
  9. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/.idea/.gitignore +0 -0
  10. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/.idea/analyser-hj3415.iml +0 -0
  11. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  12. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/.idea/misc.xml +0 -0
  13. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/.idea/modules.xml +0 -0
  14. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/.idea/vcs.xml +0 -0
  15. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/LICENSE +0 -0
  16. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/README.md +0 -0
  17. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/analyser_hj3415/.DS_Store +0 -0
  18. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/analyser_hj3415/__init__.py +0 -0
  19. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/analyser_hj3415/cli.py +0 -0
  20. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/analyser_hj3415/eval.py +0 -0
  21. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/analyser_hj3415/workroom/__init__.py +0 -0
  22. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/analyser_hj3415/workroom/mysklearn.py +0 -0
  23. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/analyser_hj3415/workroom/mysklearn2.py +0 -0
  24. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/analyser_hj3415/workroom/score.py +0 -0
  25. {analyser_hj3415-2.7.7 → analyser_hj3415-2.8.0}/analyser_hj3415/workroom/trash.py +0 -0
@@ -1,12 +1,18 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: analyser_hj3415
3
- Version: 2.7.7
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
7
7
  Classifier: License :: OSI Approved :: MIT License
8
8
  Requires-Dist: utils-hj3415>=2.9.2
9
9
  Requires-Dist: db-hj3415>=4.0.3
10
+ Requires-Dist: scikit-learn>=1.5.2
11
+ Requires-Dist: plotly>=5.24.1
12
+ Requires-Dist: yfinance>=0.2.44
13
+ Requires-Dist: prophet>=1.1.6
14
+ Requires-Dist: kaleido>=0.2.1
15
+ Requires-Dist: matplotlib>=3.9.2
10
16
  Project-URL: Home, https://www.hyungjin.kr
11
17
 
12
18
  ### analyser-hj3415
@@ -0,0 +1,204 @@
1
+ """
2
+ Time Series Analysis
3
+ """
4
+ import yfinance as yf
5
+ from datetime import datetime, timedelta
6
+ import pandas as pd
7
+ from prophet import Prophet
8
+ from sklearn.preprocessing import StandardScaler
9
+ from utils_hj3415 import utils, helpers
10
+ from typing import Optional
11
+ import plotly.graph_objs as go
12
+ from plotly.offline import plot
13
+ import matplotlib.pyplot as plt # Matplotlib 수동 임포트
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
22
+
23
+ class MyProphet:
24
+ def __init__(self, code: str):
25
+ assert utils.is_6digit(code), f'Invalid value : {code}'
26
+ self.scaler = StandardScaler()
27
+
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()
34
+
35
+ @property
36
+ def code(self) -> str:
37
+ return self._code
38
+
39
+ @code.setter
40
+ def code(self, code: str):
41
+ assert utils.is_6digit(code), f'Invalid value : {code}'
42
+ analyser_logger.info(f'change code : {self.code} -> {code}')
43
+ self.model = Prophet()
44
+ self._code = code
45
+ self.name = myredis.Corps(code, 'c101').get_name()
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:
61
+ """
62
+ 야후에서 해당 종목의 4년간 주가 raw data를 받아온다.
63
+ :return:
64
+ """
65
+ # 오늘 날짜 가져오기
66
+ today = datetime.today()
67
+
68
+ # 4년 전 날짜 계산 (4년 = 365일 * 4)
69
+ four_years_ago = today - timedelta(days=365 * 4)
70
+
71
+ return yf.download(
72
+ self.code + '.KS',
73
+ start=four_years_ago.strftime('%Y-%m-%d'),
74
+ end=today.strftime('%Y-%m-%d')
75
+ )
76
+
77
+ def _preprocessing_for_prophet(self) -> pd.DataFrame:
78
+ """
79
+ Prophet이 사용할 수 있도록 데이터 준비
80
+ ds는 날짜, y는 주가
81
+ :return:
82
+ """
83
+ df = self.raw_data[['Close', 'Volume']].reset_index()
84
+ df.columns = ['ds', 'y', 'volume'] # Prophet의 형식에 맞게 열 이름 변경
85
+
86
+ # 추가 변수를 정규화
87
+ df['volume_scaled'] = self.scaler.fit_transform(df[['volume']])
88
+ return df
89
+
90
+ def _make_forecast(self) -> pd.DataFrame:
91
+ # 정규화된 'volume_scaled' 변수를 외부 변수로 추가
92
+ self.model.add_regressor('volume_scaled')
93
+
94
+ self.model.fit(self.df_real)
95
+
96
+ # 향후 180일 동안의 주가 예측
97
+ future = self.model.make_future_dataframe(periods=180)
98
+
99
+ # 미래 데이터에 거래량 추가 (평균 거래량을 사용해 정규화)
100
+ future_volume = pd.DataFrame({'volume': [self.raw_data['Volume'].mean()] * len(future)})
101
+ future['volume_scaled'] = self.scaler.transform(future_volume[['volume']])
102
+
103
+ forecast = self.model.predict(future)
104
+ return forecast
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
+
117
+ def export_to(self, to="str") -> Optional[str]:
118
+ """
119
+ prophet과 plotly로 그래프를 그려서 html을 문자열로 반환
120
+ :param to: str, png, htmlfile, show
121
+ :return:
122
+ """
123
+ # Plotly를 사용한 시각화
124
+ fig = go.Figure()
125
+
126
+ # 실제 데이터
127
+ fig.add_trace(go.Scatter(x=self.df_real['ds'], y=self.df_real['y'], mode='markers', name='실제주가'))
128
+ # 예측 데이터
129
+ fig.add_trace(go.Scatter(x=self.df_forecast['ds'], y=self.df_forecast['yhat'], mode='lines', name='예측치'))
130
+
131
+ # 상한/하한 구간
132
+ fig.add_trace(
133
+ go.Scatter(x=self.df_forecast['ds'], y=self.df_forecast['yhat_upper'], fill=None, mode='lines', name='상한'))
134
+ fig.add_trace(
135
+ go.Scatter(x=self.df_forecast['ds'], y=self.df_forecast['yhat_lower'], fill='tonexty', mode='lines', name='하한'))
136
+
137
+ fig.update_layout(
138
+ title=f'{self.code} {self.name} 주가 예측 그래프(prophet)',
139
+ xaxis_title='일자',
140
+ yaxis_title='주가(원)',
141
+ xaxis = dict(
142
+ tickformat='%Y/%m', # X축을 '연/월' 형식으로 표시
143
+ ),
144
+ yaxis = dict(
145
+ tickformat=".0f", # 소수점 없이 원래 숫자 표시
146
+ )
147
+ )
148
+
149
+ if to == 'str':
150
+ # 그래프 HTML로 변환 (string 형식으로 저장)
151
+ graph_html = plot(fig, output_type='div')
152
+ return graph_html
153
+ elif to == 'png':
154
+ # 그래프를 PNG 파일로 저장
155
+ fig.write_image("plotly_graph.png")
156
+ elif to == 'htmlfile':
157
+ # 그래프를 HTML로 저장
158
+ plot(fig, filename='graph_plotly.html', auto_open=False)
159
+ return None
160
+ elif to == 'show':
161
+ # 예측 결과 출력
162
+ print(self.df_forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())
163
+ # 예측 결과 시각화 (Matplotlib 사용)
164
+ fig = self.model.plot(self.df_forecast)
165
+ # 추세 및 계절성 시각화
166
+ fig2 = self.model.plot_components(self.df_forecast)
167
+ plt.show() # 시각화 창 띄우기
168
+ else:
169
+ Exception("to 인자가 맞지 않습니다.")
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))
202
+
203
+
204
+
@@ -9,11 +9,11 @@ import matplotlib.pyplot as plt
9
9
  # 1. 데이터 다운로드 (애플 주식 데이터를 사용)
10
10
  #stock_data = yf.download('AAPL', start='2020-01-01', end='2023-01-01')
11
11
  # 삼성전자 주식 데이터 가져오기 (KOSPI 상장)
12
- #stock_data = yf.download('005930.KS', start='2019-01-01', end='2024-10-10')
12
+ #stock_data = yf.download('005930.KS', start='2019-01-01', end='2024-10-11')
13
13
  # 크래프톤 주식 데이터 가져오기 (KOSPI 상장)
14
- #stock_data = yf.download('259960.KS', start='2020-01-01', end='2024-10-08')
14
+ stock_data = yf.download('259960.KS', start='2020-01-01', end='2024-10-11')
15
15
  # 하이닉스 주식 데이터 가져오기 (KOSPI 상장)
16
- stock_data = yf.download('000660.KS', start='2019-01-01', end='2024-10-10')
16
+ #stock_data = yf.download('000660.KS', start='2019-01-01', end='2024-10-11')
17
17
 
18
18
 
19
19
  # 2. 필요한 열만 선택 (종가만 사용)
@@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi"
4
4
 
5
5
  [project]
6
6
  name = "analyser_hj3415"
7
- version = "2.7.7"
7
+ version = "2.8.0"
8
8
  authors = [{name = "Hyungjin Kim", email = "hj3415@gmail.com"}]
9
9
  description = "Stock analyser and database processing programs"
10
10
  readme = "README.md"
@@ -13,6 +13,12 @@ classifiers = ["License :: OSI Approved :: MIT License"]
13
13
  dependencies = [
14
14
  "utils-hj3415>=2.9.2",
15
15
  "db-hj3415>=4.0.3",
16
+ "scikit-learn>=1.5.2",
17
+ "plotly>=5.24.1",
18
+ "yfinance>=0.2.44",
19
+ "prophet>=1.1.6",
20
+ "kaleido>=0.2.1", #plotly로 이미지출력위해
21
+ "matplotlib>=3.9.2",
16
22
  ]
17
23
 
18
24
  [project.scripts]
@@ -1,58 +0,0 @@
1
- # prophet 사용 공부
2
-
3
- import yfinance as yf
4
- import pandas as pd
5
- from prophet import Prophet
6
- import matplotlib.pyplot as plt # Matplotlib 수동 임포트
7
-
8
-
9
- # 애플 주식 데이터를 다운로드
10
- #stock_data = yf.download('AAPL', start='2020-01-01', end='2024-10-09')
11
- # 삼성전자 주식 데이터 가져오기 (KOSPI 상장)
12
- #stock_data = yf.download('005930.KS', start='2020-01-01', end='2024-08-01')
13
- # 크래프톤 주식 데이터 가져오기 (KOSPI 상장)
14
- #stock_data = yf.download('259960.KS', start='2020-01-01', end='2024-10-08')
15
- # 하이닉스 주식 데이터 가져오기 (KOSPI 상장)
16
- stock_data = yf.download('000660.KS', start='2020-01-01', end='2024-10-08')
17
-
18
-
19
- # Prophet이 사용할 수 있도록 데이터 준비
20
- df = stock_data[['Close', 'Volume']].reset_index()
21
- df.columns = ['ds', 'y', 'volume'] # Prophet의 형식에 맞게 열 이름 변경
22
-
23
- from sklearn.preprocessing import StandardScaler
24
-
25
- # 추가 변수를 정규화
26
- scaler = StandardScaler()
27
- df['volume_scaled'] = scaler.fit_transform(df[['volume']])
28
-
29
- # Prophet 모델 생성 및 학습
30
- model = Prophet()
31
-
32
- # 정규화된 'volume_scaled' 변수를 외부 변수로 추가
33
- model.add_regressor('volume_scaled')
34
-
35
- model.fit(df)
36
-
37
- # 향후 180일 동안의 주가 예측
38
- future = model.make_future_dataframe(periods=180)
39
-
40
- # 미래 데이터에 거래량 추가 (평균 거래량을 사용해 정규화)
41
- future_volume = pd.DataFrame({'volume': [stock_data['Volume'].mean()] * len(future)})
42
- future['volume_scaled'] = scaler.transform(future_volume[['volume']])
43
-
44
-
45
- forecast = model.predict(future)
46
-
47
-
48
-
49
- # 예측 결과 출력
50
- print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())
51
-
52
- # 예측 결과 시각화 (Matplotlib 사용)
53
- fig = model.plot(forecast)
54
-
55
- # 추세 및 계절성 시각화
56
- fig2 = model.plot_components(forecast)
57
-
58
- plt.show() # 시각화 창 띄우기
File without changes