analyser_hj3415 2.7.6__py2.py3-none-any.whl → 2.7.8__py2.py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
analyser_hj3415/cli.py CHANGED
@@ -117,7 +117,7 @@ def analyser_manager():
117
117
  for i, code in enumerate(myredis.Corps.list_all_codes()):
118
118
  red.code = code
119
119
  print(f"*** {i} / {red} ***")
120
- pprint.pprint(red.get(args.refresh))
120
+ pprint.pprint(red.get(args.refresh, verbose=False))
121
121
 
122
122
  # 원래 저장되었던 기대수익률로 다시 복원
123
123
  eval.Red.expect_earn = ee_orig
@@ -140,10 +140,7 @@ def analyser_manager():
140
140
  noti.telegram_to('manager', f"오늘의 Red({args.code})를 레디스캐시에 저장했습니다.(유효 12시간)")
141
141
 
142
142
  elif args.command == 'ranking':
143
- if args.refresh:
144
- result = eval.Red.ranking(expect_earn=args.expect_earn, refresh=True)
145
- else:
146
- result = eval.Red.ranking(expect_earn=args.expect_earn, refresh=False)
143
+ result = eval.Red.ranking(expect_earn=args.expect_earn, refresh=args.refresh)
147
144
  print(result)
148
145
  if args.noti:
149
146
  noti.telegram_to('manager', "오늘의 red ranking을 레디스캐시에 저장했습니다.(유효 12시간)")
@@ -156,7 +153,7 @@ def analyser_manager():
156
153
  for i, code in enumerate(myredis.Corps.list_all_codes()):
157
154
  mil.code = code
158
155
  print(f"*** {i} / {mil} ***")
159
- pprint.pprint(mil.get(args.refresh))
156
+ pprint.pprint(mil.get(args.refresh, verbose=False))
160
157
  else:
161
158
  assert utils.is_6digit(args.code), "code 인자는 6자리 숫자이어야 합니다."
162
159
  mil = eval.Mil(args.code)
@@ -173,7 +170,7 @@ def analyser_manager():
173
170
  for i, code in enumerate(myredis.Corps.list_all_codes()):
174
171
  blue.code = code
175
172
  print(f"*** {i} / {blue} ***")
176
- pprint.pprint(blue.get(args.refresh))
173
+ pprint.pprint(blue.get(args.refresh, verbose=False))
177
174
  else:
178
175
  assert utils.is_6digit(args.code), "code 인자는 6자리 숫자이어야 합니다."
179
176
  blue = eval.Blue(args.code)
@@ -190,7 +187,7 @@ def analyser_manager():
190
187
  for i, code in enumerate(myredis.Corps.list_all_codes()):
191
188
  growth.code = code
192
189
  print(f"*** {i} / {growth} ***")
193
- pprint.pprint(growth.get(args.refresh))
190
+ pprint.pprint(growth.get(args.refresh, verbose=False))
194
191
  else:
195
192
  assert utils.is_6digit(args.code), "code 인자는 6자리 숫자이어야 합니다."
196
193
  growth = eval.Growth(args.code)
analyser_hj3415/eval.py CHANGED
@@ -324,7 +324,7 @@ class Red:
324
324
  score = score,
325
325
  )
326
326
 
327
- def get(self, refresh = False) -> RedData:
327
+ def get(self, refresh = False, verbose = True) -> RedData:
328
328
  """
329
329
  RedData 형식의 데이터를 계산하여 리턴하고 레디스 캐시에 저장한다.
330
330
  :param refresh:
@@ -333,7 +333,8 @@ class Red:
333
333
  redis_name = f"{self.code}_red"
334
334
  analyser_logger.info(f"{self} RedData를 레디스캐시에서 가져오거나 새로 생성합니다.. refresh : {refresh}")
335
335
  expire_time = 3600 * 12
336
- print(f"{self} redisname: '{redis_name}' / expect_earn: {Red.expect_earn} / refresh : {refresh} / expire_time : {expire_time/3600}h")
336
+ if verbose:
337
+ print(f"{self} redisname: '{redis_name}' / expect_earn: {Red.expect_earn} / refresh : {refresh} / expire_time : {expire_time/3600}h")
337
338
 
338
339
  def fetch_generate_data(refresh_in: bool) -> dict:
339
340
  return asdict(self._generate_data(refresh_in))
@@ -375,7 +376,7 @@ class Red:
375
376
  red = Red('005930')
376
377
  for i, code in enumerate(myredis.Corps.list_all_codes()):
377
378
  red.code = code
378
- red_score = red.get(refresh=refresh_in).score
379
+ red_score = red.get(refresh=refresh_in, verbose=False).score
379
380
  if red_score > 0:
380
381
  data[code] = red_score
381
382
  print(f"{i}: {red} - {red_score}")
@@ -632,7 +633,7 @@ class Mil:
632
633
  date = date_list,
633
634
  )
634
635
 
635
- def get(self, refresh = False) -> MilData:
636
+ def get(self, refresh = False, verbose = True) -> MilData:
636
637
  """
637
638
  MilData 형식의 데이터를 계산하여 리턴하고 레디스 캐시에 저장한다.
638
639
  :param refresh:
@@ -640,7 +641,8 @@ class Mil:
640
641
  """
641
642
  redis_name = f"{self.code}_mil"
642
643
  analyser_logger.info(f"{self} MilData를 레디스캐시에서 가져오거나 새로 생성합니다.. refresh : {refresh}")
643
- print(f"{self} redisname: '{redis_name}' / refresh : {refresh} / expire_time : {expire_time/3600}h")
644
+ if verbose:
645
+ print(f"{self} redisname: '{redis_name}' / refresh : {refresh} / expire_time : {expire_time/3600}h")
644
646
 
645
647
  def fetch_generate_data(refresh_in: bool) -> dict:
646
648
  return asdict(self._generate_data(refresh_in))
@@ -804,7 +806,7 @@ class Blue:
804
806
  date= date_list,
805
807
  )
806
808
 
807
- def get(self, refresh = False) -> BlueData:
809
+ def get(self, refresh = False, verbose = True) -> BlueData:
808
810
  """
809
811
  BlueData 형식의 데이터를 계산하여 리턴하고 레디스 캐시에 저장한다.
810
812
  :param refresh:
@@ -812,7 +814,8 @@ class Blue:
812
814
  """
813
815
  redis_name = f"{self.code}_blue"
814
816
  analyser_logger.info(f"{self} BlueData를 레디스캐시에서 가져오거나 새로 생성합니다.. refresh : {refresh}")
815
- print(f"{self} redisname: '{redis_name}' / refresh : {refresh} / expire_time : {expire_time/3600}h")
817
+ if verbose:
818
+ print(f"{self} redisname: '{redis_name}' / refresh : {refresh} / expire_time : {expire_time/3600}h")
816
819
 
817
820
  def fetch_generate_data(refresh_in: bool) -> dict:
818
821
  return asdict(self._generate_data(refresh_in))
@@ -903,7 +906,7 @@ class Growth:
903
906
  date= date_list,
904
907
  )
905
908
 
906
- def get(self, refresh = False) -> GrowthData:
909
+ def get(self, refresh = False, verbose = True) -> GrowthData:
907
910
  """
908
911
  GrowthData 형식의 데이터를 계산하여 리턴하고 레디스 캐시에 저장한다.
909
912
  :param refresh:
@@ -911,7 +914,8 @@ class Growth:
911
914
  """
912
915
  redis_name = f"{self.code}_growth"
913
916
  analyser_logger.info(f"{self} GrowthData를 레디스캐시에서 가져오거나 새로 생성합니다.. refresh : {refresh}")
914
- print(f"{self} redisname: '{redis_name}' / refresh : {refresh} / expire_time : {expire_time/3600}h")
917
+ if verbose:
918
+ print(f"{self} redisname: '{redis_name}' / refresh : {refresh} / expire_time : {expire_time/3600}h")
915
919
 
916
920
  def fetch_generate_data(refresh_in: bool) -> dict:
917
921
  return asdict(self._generate_data(refresh_in))
@@ -0,0 +1,144 @@
1
+ import yfinance as yf
2
+ from datetime import datetime, timedelta
3
+ import pandas as pd
4
+ from prophet import Prophet
5
+ from sklearn.preprocessing import StandardScaler
6
+ from utils_hj3415 import utils
7
+ from typing import Optional
8
+ import plotly.graph_objs as go
9
+ from plotly.offline import plot
10
+ import matplotlib.pyplot as plt # Matplotlib 수동 임포트
11
+ from db_hj3415 import myredis
12
+
13
+ class MyProphet:
14
+ def __init__(self, code: str):
15
+ 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
+ self.scaler = StandardScaler()
21
+ self.model = Prophet()
22
+
23
+ @property
24
+ def code(self) -> str:
25
+ return self._code
26
+
27
+ @code.setter
28
+ def code(self, code: str):
29
+ assert utils.is_6digit(code), f'Invalid value : {code}'
30
+ self._code = code
31
+ 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:
35
+ """
36
+ 야후에서 해당 종목의 4년간 주가 raw data를 받아온다.
37
+ :return:
38
+ """
39
+ # 오늘 날짜 가져오기
40
+ today = datetime.today()
41
+
42
+ # 4년 전 날짜 계산 (4년 = 365일 * 4)
43
+ four_years_ago = today - timedelta(days=365 * 4)
44
+
45
+ return yf.download(
46
+ self.code + '.KS',
47
+ start=four_years_ago.strftime('%Y-%m-%d'),
48
+ end=today.strftime('%Y-%m-%d')
49
+ )
50
+
51
+ def preprocessing_for_prophet(self) -> pd.DataFrame:
52
+ """
53
+ Prophet이 사용할 수 있도록 데이터 준비
54
+ ds는 날짜, y는 주가
55
+ :return:
56
+ """
57
+ df = self.raw_data[['Close', 'Volume']].reset_index()
58
+ df.columns = ['ds', 'y', 'volume'] # Prophet의 형식에 맞게 열 이름 변경
59
+
60
+ # 추가 변수를 정규화
61
+ df['volume_scaled'] = self.scaler.fit_transform(df[['volume']])
62
+ return df
63
+
64
+ def make_forecast(self) -> pd.DataFrame:
65
+ # Prophet을 위한 dataframe 만들기
66
+ df_for_prophet = self.preprocessing_for_prophet()
67
+
68
+ # 정규화된 'volume_scaled' 변수를 외부 변수로 추가
69
+ self.model.add_regressor('volume_scaled')
70
+
71
+ self.model.fit(df_for_prophet)
72
+
73
+ # 향후 180일 동안의 주가 예측
74
+ future = self.model.make_future_dataframe(periods=180)
75
+
76
+ # 미래 데이터에 거래량 추가 (평균 거래량을 사용해 정규화)
77
+ future_volume = pd.DataFrame({'volume': [self.raw_data['Volume'].mean()] * len(future)})
78
+ future['volume_scaled'] = self.scaler.transform(future_volume[['volume']])
79
+
80
+ forecast = self.model.predict(future)
81
+ return forecast
82
+
83
+ def export_to(self, to="str") -> Optional[str]:
84
+ """
85
+ prophet과 plotly로 그래프를 그려서 html을 문자열로 반환
86
+ :param to: str, png, htmlfile, show
87
+ :return:
88
+ """
89
+ # 실제 데이터
90
+ df = self.preprocessing_for_prophet()
91
+ # 예측 데이터
92
+ forecast = self.make_forecast()
93
+
94
+ # Plotly를 사용한 시각화
95
+ fig = go.Figure()
96
+
97
+ # 실제 데이터
98
+ fig.add_trace(go.Scatter(x=df['ds'], y=df['y'], mode='markers', name='실제주가'))
99
+ # 예측 데이터
100
+ fig.add_trace(go.Scatter(x=forecast['ds'], y=forecast['yhat'], mode='lines', name='예측치'))
101
+
102
+ # 상한/하한 구간
103
+ fig.add_trace(
104
+ go.Scatter(x=forecast['ds'], y=forecast['yhat_upper'], fill=None, mode='lines', name='상한'))
105
+ fig.add_trace(
106
+ go.Scatter(x=forecast['ds'], y=forecast['yhat_lower'], fill='tonexty', mode='lines', name='하한'))
107
+
108
+ fig.update_layout(
109
+ title=f'{self.code} {self.name} 주가 예측 그래프(prophet)',
110
+ xaxis_title='일자',
111
+ yaxis_title='주가(원)',
112
+ xaxis = dict(
113
+ tickformat='%Y/%m', # X축을 '연/월' 형식으로 표시
114
+ ),
115
+ yaxis = dict(
116
+ tickformat=".0f", # 소수점 없이 원래 숫자 표시
117
+ )
118
+ )
119
+
120
+ if to == 'str':
121
+ # 그래프 HTML로 변환 (string 형식으로 저장)
122
+ graph_html = plot(fig, output_type='div')
123
+ return graph_html
124
+ elif to == 'png':
125
+ # 그래프를 PNG 파일로 저장
126
+ fig.write_image("plotly_graph.png")
127
+ elif to == 'htmlfile':
128
+ # 그래프를 HTML로 저장
129
+ plot(fig, filename='graph_plotly.html', auto_open=False)
130
+ return None
131
+ elif to == 'show':
132
+ # 예측 결과 출력
133
+ print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())
134
+ # 예측 결과 시각화 (Matplotlib 사용)
135
+ fig = self.model.plot(forecast)
136
+ # 추세 및 계절성 시각화
137
+ fig2 = self.model.plot_components(forecast)
138
+ plt.show() # 시각화 창 띄우기
139
+ else:
140
+ Exception("to 인자가 맞지 않습니다.")
141
+
142
+
143
+
144
+
@@ -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. 필요한 열만 선택 (종가만 사용)
@@ -1,12 +1,18 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: analyser_hj3415
3
- Version: 2.7.6
3
+ Version: 2.7.8
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
@@ -1,16 +1,16 @@
1
1
  analyser_hj3415/.DS_Store,sha256=qr9-0FPn5CFKe6kEu8_dWCNhzQ0sN7bwQgffKsaJEEo,6148
2
2
  analyser_hj3415/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- analyser_hj3415/cli.py,sha256=IAABc8Q6thB8FhHUeWsA2m6sW3iHtlqNEm80tpgiyCs,11075
4
- analyser_hj3415/eval.py,sha256=oz3KckQ_GiMcBp_sHjBJnQRmYtRyGWKdlhqW0oCaqSo,38924
3
+ analyser_hj3415/cli.py,sha256=7ys-b9H_tJAbLLi_XpjmEvDiyNHddpg9F1FNAACfWnE,11005
4
+ analyser_hj3415/eval.py,sha256=4F0GIknCogAhv_iTq8auLrmwW20u8kH0HY0fP4SaVa4,39099
5
+ analyser_hj3415/myprophet.py,sha256=N_eUzAmrbEuqJBJ9OqbnMrHC3_kc3JXGq6pND5o4yuE,5096
5
6
  analyser_hj3415/workroom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- analyser_hj3415/workroom/lstm.py,sha256=O_VYURGNsLw6q_7Yi0nH4Y6nKbVBwzMojDN446cyJKM,4078
7
- analyser_hj3415/workroom/myprophet.py,sha256=xGbs4_cCeSNAX62H6rG-bUz6_rUOyO6787WAjLexMkw,1855
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.6.dist-info/entry_points.txt,sha256=ZfjPnJuH8SzvhE9vftIPMBIofsc65IAWYOhqOC_L5ck,65
13
- analyser_hj3415-2.7.6.dist-info/LICENSE,sha256=QVKTp0dTnB5xG8RLgG17LwSWCKNEzYoVVM6KjoCPKc0,1079
14
- analyser_hj3415-2.7.6.dist-info/WHEEL,sha256=Sgu64hAMa6g5FdzHxXv9Xdse9yxpGGMeagVtPMWpJQY,99
15
- analyser_hj3415-2.7.6.dist-info/METADATA,sha256=B1c2kZOnrJ4oiteINJ8eTpWWTrIdbpEivGi1mqpfNsg,6417
16
- analyser_hj3415-2.7.6.dist-info/RECORD,,
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,,
@@ -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() # 시각화 창 띄우기