analyser_hj3415 2.7.6__py2.py3-none-any.whl → 2.7.8__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/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() # 시각화 창 띄우기