analyser_hj3415 3.2.2__py3-none-any.whl → 3.3.0__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/analyser/__init__.py +30 -12
- analyser_hj3415/analyser/compile.py +87 -133
- analyser_hj3415/analyser/eval/blue.py +78 -9
- analyser_hj3415/analyser/eval/common.py +72 -110
- analyser_hj3415/analyser/eval/growth.py +77 -6
- analyser_hj3415/analyser/eval/mil.py +119 -18
- analyser_hj3415/analyser/eval/red.py +95 -66
- analyser_hj3415/analyser/tsa/__init__.py +1 -1
- analyser_hj3415/analyser/tsa/common.py +33 -0
- analyser_hj3415/analyser/tsa/lstm.py +108 -133
- analyser_hj3415/analyser/tsa/prophet.py +261 -124
- analyser_hj3415/cli.py +12 -9
- {analyser_hj3415-3.2.2.dist-info → analyser_hj3415-3.3.0.dist-info}/METADATA +1 -1
- analyser_hj3415-3.3.0.dist-info/RECORD +23 -0
- analyser_hj3415-3.2.2.dist-info/RECORD +0 -22
- {analyser_hj3415-3.2.2.dist-info → analyser_hj3415-3.3.0.dist-info}/WHEEL +0 -0
- {analyser_hj3415-3.2.2.dist-info → analyser_hj3415-3.3.0.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,5 @@
|
|
1
1
|
import os
|
2
|
-
from dataclasses import dataclass
|
2
|
+
from dataclasses import dataclass
|
3
3
|
from typing import Tuple
|
4
4
|
import math
|
5
5
|
|
@@ -16,34 +16,31 @@ expire_time = tools.to_int(os.getenv('DEFAULT_EXPIRE_TIME_H', 48)) * 3600
|
|
16
16
|
@dataclass
|
17
17
|
class RedData:
|
18
18
|
"""
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
Raises:
|
46
|
-
ValueError: If the 'code' attribute is not a 6-digit numeric string.
|
19
|
+
재무 데이터를 표현하고 계산하기 위한 데이터 구조.
|
20
|
+
|
21
|
+
이 클래스는 기업의 재무 데이터를 관리하며, 사업가치, 재산가치, 부채평가 등 다양한 재무
|
22
|
+
지표를 포함합니다. 초기화 시 특정 속성 값을 검증하며, 재무 데이터 분석에 유용하게 활용됩니다.
|
23
|
+
|
24
|
+
속성:
|
25
|
+
code (str): 기업의 6자리 숫자 코드.
|
26
|
+
name (str): 기업명.
|
27
|
+
사업가치 (float): 지배주주 당기순이익 / 기대수익률로 계산된 사업가치.
|
28
|
+
지배주주당기순이익 (float): 지배주주에게 귀속된 당기순이익.
|
29
|
+
expect_earn (float): 기대수익률.
|
30
|
+
재산가치 (float): 유동자산 - (유동부채 * 1.2) + 고정자산(투자자산, 투자부동산)으로 계산된 재산가치.
|
31
|
+
유동자산 (float): 기업의 유동자산.
|
32
|
+
유동부채 (float): 기업의 유동부채.
|
33
|
+
투자자산 (float): 투자자산.
|
34
|
+
투자부동산 (float): 투자부동산.
|
35
|
+
부채평가 (float): 비유동부채를 평가한 값.
|
36
|
+
발행주식수 (int): 발행된 주식 수.
|
37
|
+
date (list): 재무 데이터와 관련된 날짜 목록.
|
38
|
+
주가 (float): 최근 주가.
|
39
|
+
red_price (float): 계산된 레드 가격.
|
40
|
+
score (int): 최근 주가와 레드 가격 간 괴리율로 산출된 점수.
|
41
|
+
|
42
|
+
예외:
|
43
|
+
ValueError: 'code'가 6자리 숫자 문자열이 아닌 경우 발생.
|
47
44
|
"""
|
48
45
|
code: str
|
49
46
|
name: str
|
@@ -78,17 +75,18 @@ class RedData:
|
|
78
75
|
|
79
76
|
class Red:
|
80
77
|
"""
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
tools for financial calculations and analysis. This includes fetching and
|
86
|
-
processing information related to liabilities, assets, stock prices, and
|
87
|
-
other financial indicators. The class facilitates both specific calculations
|
88
|
-
such as 비유동부채(Non-current Liability) and the generation of comprehensive
|
89
|
-
financial datasets.
|
90
|
-
"""
|
78
|
+
특정 기업의 재무 데이터를 계산하고 분석하기 위한 클래스.
|
79
|
+
|
80
|
+
이 클래스는 주어진 종목 코드에 대해 데이터를 가져오고, 사업가치, 재산가치, 부채평가 등 다양한
|
81
|
+
재무 지표를 계산하며, Redis 캐시를 활용하여 데이터 저장 및 재사용을 관리합니다.
|
91
82
|
|
83
|
+
속성:
|
84
|
+
c101 (myredis.C101): 기업 정보 및 데이터 접근을 위한 객체.
|
85
|
+
c103 (myredis.C103): 재무 상태표 데이터 접근을 위한 객체.
|
86
|
+
name (str): 기업명.
|
87
|
+
recent_price (float): 최근 주가.
|
88
|
+
expect_earn (float): 기대수익률. 기본값은 0.06 (6%).
|
89
|
+
"""
|
92
90
|
|
93
91
|
def __init__(self, code: str, expect_earn: float = 0.06):
|
94
92
|
assert tools.is_6digit(code), f'Invalid value : {code}'
|
@@ -121,10 +119,23 @@ class Red:
|
|
121
119
|
self._code = code
|
122
120
|
|
123
121
|
def _calc비유동부채(self, refresh: bool) -> Tuple[str, float]:
|
124
|
-
"""
|
122
|
+
"""
|
123
|
+
비유동부채를 계산합니다.
|
124
|
+
|
125
|
+
기본적으로 재무 상태표에서 비유동부채 데이터를 가져오며, 만약 데이터가 누락되었거나 NaN인 경우
|
126
|
+
직접 계산하여 반환합니다.
|
127
|
+
|
128
|
+
매개변수:
|
129
|
+
refresh (bool): 데이터 새로고침 여부. True일 경우 최신 데이터를 가져옵니다.
|
125
130
|
|
126
|
-
|
127
|
-
|
131
|
+
반환값:
|
132
|
+
Tuple[str, float]: 가장 최근 날짜와 계산된 비유동부채 값.
|
133
|
+
|
134
|
+
예외:
|
135
|
+
ValueError: 필요한 데이터가 누락된 경우 발생.
|
136
|
+
|
137
|
+
로그:
|
138
|
+
- 비유동부채 데이터가 없을 경우 경고 메시지를 출력합니다.
|
128
139
|
"""
|
129
140
|
mylogger.info(f'In the calc비유동부채... refresh : {refresh}')
|
130
141
|
self.c103.page = 'c103재무상태표q'
|
@@ -154,11 +165,18 @@ class Red:
|
|
154
165
|
return d, 비유동부채
|
155
166
|
|
156
167
|
def _score(self, red_price: int) -> int:
|
157
|
-
"""
|
168
|
+
"""
|
169
|
+
최근 주가와 레드 가격 간 괴리율을 계산하여 점수를 반환합니다.
|
170
|
+
|
171
|
+
매개변수:
|
172
|
+
red_price (int): 계산된 레드 가격.
|
173
|
+
|
174
|
+
반환값:
|
175
|
+
int: 괴리율 기반 점수. 양수는 저평가, 음수는 과대평가를 나타냅니다.
|
158
176
|
|
159
|
-
|
160
|
-
|
161
|
-
|
177
|
+
로그:
|
178
|
+
- 최근 주가와 레드 가격, 괴리율, 계산된 점수를 출력합니다.
|
179
|
+
"""
|
162
180
|
if math.isnan(self.recent_price):
|
163
181
|
return 0
|
164
182
|
|
@@ -174,6 +192,24 @@ class Red:
|
|
174
192
|
return score
|
175
193
|
|
176
194
|
def _generate_data(self, refresh: bool) -> RedData:
|
195
|
+
"""
|
196
|
+
RedData 객체를 생성하기 위해 재무 데이터를 계산합니다.
|
197
|
+
|
198
|
+
내부적으로 사업가치, 재산가치, 비유동부채 등을 계산하며, 계산된 결과를 RedData 객체로 반환합니다.
|
199
|
+
|
200
|
+
매개변수:
|
201
|
+
refresh (bool): 데이터 새로고침 여부. True일 경우 최신 데이터를 가져옵니다.
|
202
|
+
|
203
|
+
반환값:
|
204
|
+
RedData: 계산된 재무 데이터를 포함하는 RedData 객체.
|
205
|
+
|
206
|
+
예외:
|
207
|
+
ZeroDivisionError: 발행 주식 수가 0인 경우 발생.
|
208
|
+
ValueError: 필요한 날짜 데이터가 없는 경우 발생.
|
209
|
+
|
210
|
+
로그:
|
211
|
+
- 각 단계의 계산 결과와 주요 값을 출력합니다.
|
212
|
+
"""
|
177
213
|
d1, 지배주주당기순이익 = Tools.calc당기순이익(self.c103, refresh)
|
178
214
|
mylogger.debug(f"{self} 지배주주당기순이익: {지배주주당기순이익}")
|
179
215
|
d2, 유동자산 = Tools.calc유동자산(self.c103, refresh)
|
@@ -230,35 +266,28 @@ class Red:
|
|
230
266
|
|
231
267
|
def get(self, refresh = False, verbose = True) -> RedData:
|
232
268
|
"""
|
233
|
-
RedData
|
234
|
-
|
235
|
-
redis_name = f"{self.code}_red_data"
|
236
|
-
|
237
|
-
Fetch or create RedData from Redis cache.
|
269
|
+
RedData 객체를 Redis 캐시에서 가져오거나, 새로 계산하여 반환합니다.
|
238
270
|
|
239
|
-
|
240
|
-
|
241
|
-
them back in Redis. The function logs its operations and can provide
|
242
|
-
verbose output when specified.
|
271
|
+
캐시에서 데이터를 검색하고, 없을 경우 `_generate_data`를 호출하여 새로운 데이터를 생성한 후,
|
272
|
+
캐시에 저장합니다.
|
243
273
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
verbose : bool, optional
|
248
|
-
Whether to enable verbose logging/display of additional runtime information.
|
274
|
+
매개변수:
|
275
|
+
refresh (bool, optional): 캐시 데이터를 무시하고 새로 계산 여부. 기본값은 False.
|
276
|
+
verbose (bool, optional): 실행 중 상세 정보를 출력 여부. 기본값은 True.
|
249
277
|
|
250
|
-
|
251
|
-
|
252
|
-
The RedData object either retrieved from the cache or newly generated.
|
278
|
+
반환값:
|
279
|
+
RedData: Redis 캐시에서 가져오거나 새로 생성된 RedData 객체.
|
253
280
|
|
281
|
+
로그:
|
282
|
+
- 캐시 검색 상태와 새로 계산된 데이터를 출력합니다.
|
254
283
|
"""
|
255
284
|
redis_name = f"{self.code}_red_data"
|
256
285
|
mylogger.info(f"{self} RedData를 레디스캐시에서 가져오거나 새로 생성합니다.. refresh : {refresh}")
|
257
286
|
if verbose:
|
258
287
|
print(f"{self} redisname: '{redis_name}' / expect_earn: {self.expect_earn} / refresh : {refresh} / expire_time : {expire_time/3600}h")
|
259
288
|
|
260
|
-
def fetch_generate_data(refresh_in: bool) ->
|
261
|
-
return
|
289
|
+
def fetch_generate_data(refresh_in: bool) -> RedData:
|
290
|
+
return self._generate_data(refresh_in) # type: ignore
|
262
291
|
|
263
|
-
return
|
292
|
+
return myredis.Base.fetch_and_cache_data(redis_name, refresh, fetch_generate_data, refresh, timer=expire_time)
|
264
293
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import numpy as np
|
2
|
+
|
3
|
+
|
4
|
+
def is_up_by_OLS(data: dict) -> bool:
|
5
|
+
if not data:
|
6
|
+
# 데이터가 비어있으면 추세를 판단할 수 없음
|
7
|
+
return False
|
8
|
+
|
9
|
+
# 1) 날짜(키) 기준 오름차순 정렬
|
10
|
+
sorted_dates = sorted(data.keys())
|
11
|
+
values = [data[d] for d in sorted_dates]
|
12
|
+
|
13
|
+
# 2) x 축을 0,1,2... 형태로 부여 (날짜 간격을 동일하게 가정)
|
14
|
+
x = np.arange(len(values), dtype=float)
|
15
|
+
y = np.array(values, dtype=float)
|
16
|
+
|
17
|
+
# 3) 선형 회귀(최소제곱법)로 기울기(slope) 계산
|
18
|
+
x_mean = np.mean(x)
|
19
|
+
y_mean = np.mean(y)
|
20
|
+
|
21
|
+
# 분자: sum((xi - x_mean) * (yi - y_mean))
|
22
|
+
numerator = np.sum((x - x_mean) * (y - y_mean))
|
23
|
+
# 분모: sum((xi - x_mean)^2)
|
24
|
+
denominator = np.sum((x - x_mean) ** 2)
|
25
|
+
|
26
|
+
if denominator == 0:
|
27
|
+
# 데이터가 1개 이하인 경우 등
|
28
|
+
return False
|
29
|
+
|
30
|
+
slope = numerator / denominator
|
31
|
+
|
32
|
+
# 4) 기울기가 양수면 "우상향 추세"로 판별
|
33
|
+
return slope > 0
|
@@ -8,17 +8,16 @@ import plotly.graph_objs as go
|
|
8
8
|
from plotly.offline import plot
|
9
9
|
import matplotlib.pyplot as plt # Matplotlib 수동 임포트
|
10
10
|
from sklearn.preprocessing import MinMaxScaler
|
11
|
-
from tensorflow.keras.models import Sequential
|
12
|
-
from tensorflow.keras.layers import LSTM, Dense, Dropout
|
13
|
-
from tensorflow.keras.callbacks import EarlyStopping
|
14
|
-
from tensorflow.keras import Input
|
11
|
+
from tensorflow.keras.models import Sequential # type: ignore
|
12
|
+
from tensorflow.keras.layers import LSTM, Dense, Dropout # type: ignore
|
13
|
+
from tensorflow.keras.callbacks import EarlyStopping # type: ignore
|
14
|
+
from tensorflow.keras import Input # type: ignore
|
15
15
|
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
|
16
16
|
from dataclasses import dataclass
|
17
17
|
|
18
18
|
from utils_hj3415 import tools, setup_logger
|
19
19
|
from db_hj3415 import myredis
|
20
|
-
from analyser_hj3415.analyser import MIs
|
21
|
-
|
20
|
+
from analyser_hj3415.analyser import MIs, tsa
|
22
21
|
|
23
22
|
mylogger = setup_logger(__name__,'WARNING')
|
24
23
|
expire_time = tools.to_int(os.getenv('DEFAULT_EXPIRE_TIME_H', 48)) * 3600
|
@@ -26,6 +25,20 @@ expire_time = tools.to_int(os.getenv('DEFAULT_EXPIRE_TIME_H', 48)) * 3600
|
|
26
25
|
|
27
26
|
@dataclass
|
28
27
|
class LSTMData:
|
28
|
+
"""
|
29
|
+
LSTM 모델에서 사용할 데이터를 저장하는 데이터 클래스.
|
30
|
+
|
31
|
+
속성:
|
32
|
+
ticker (str): 주식 티커(symbol).
|
33
|
+
data_2d (np.ndarray): 원본 종가 데이터를 저장한 2차원 배열.
|
34
|
+
train_size (int): 학습 데이터 크기.
|
35
|
+
train_data_2d (np.ndarray): 학습 데이터 2차원 배열.
|
36
|
+
test_data_2d (np.ndarray): 테스트 데이터 2차원 배열.
|
37
|
+
X_train_3d (np.ndarray): 학습 데이터 3차원 배열.
|
38
|
+
X_test_3d (np.ndarray): 테스트 데이터 3차원 배열.
|
39
|
+
y_train_1d (np.ndarray): 학습 정답 데이터 1차원 배열.
|
40
|
+
y_test_1d (np.ndarray): 테스트 정답 데이터 1차원 배열.
|
41
|
+
"""
|
29
42
|
ticker: str
|
30
43
|
|
31
44
|
data_2d: np.ndarray
|
@@ -42,7 +55,16 @@ class LSTMData:
|
|
42
55
|
@dataclass
|
43
56
|
class LSTMGrade:
|
44
57
|
"""
|
45
|
-
|
58
|
+
LSTM 모델 학습 결과를 평가하기 위한 데이터 클래스.
|
59
|
+
|
60
|
+
속성:
|
61
|
+
ticker (str): 주식 티커(symbol).
|
62
|
+
train_mse (float): 학습 데이터에 대한 평균 제곱 오차(MSE).
|
63
|
+
train_mae (float): 학습 데이터에 대한 평균 절대 오차(MAE).
|
64
|
+
train_r2 (float): 학습 데이터에 대한 결정 계수(R²).
|
65
|
+
test_mse (float): 테스트 데이터에 대한 평균 제곱 오차(MSE).
|
66
|
+
test_mae (float): 테스트 데이터에 대한 평균 절대 오차(MAE).
|
67
|
+
test_r2 (float): 테스트 데이터에 대한 결정 계수(R²).
|
46
68
|
"""
|
47
69
|
ticker: str
|
48
70
|
train_mse: float
|
@@ -54,6 +76,16 @@ class LSTMGrade:
|
|
54
76
|
|
55
77
|
|
56
78
|
class MyLSTM:
|
79
|
+
"""
|
80
|
+
주가 데이터를 기반으로 LSTM 모델을 생성, 학습 및 예측하는 클래스.
|
81
|
+
|
82
|
+
속성:
|
83
|
+
future_days (int): 미래 예측할 일 수. 기본값은 30.
|
84
|
+
scaler (MinMaxScaler): 데이터 정규화를 위한 MinMaxScaler.
|
85
|
+
_ticker (str): 주식 티커(symbol).
|
86
|
+
raw_data (pd.DataFrame): 원본 주가 데이터.
|
87
|
+
lstm_data (LSTMData): LSTM 학습에 사용할 데이터.
|
88
|
+
"""
|
57
89
|
# 미래 몇일을 예측할 것인가?
|
58
90
|
future_days = 30
|
59
91
|
|
@@ -100,12 +132,11 @@ class MyLSTM:
|
|
100
132
|
|
101
133
|
def initializing(self):
|
102
134
|
"""
|
103
|
-
LSTM
|
104
|
-
get_final_predictions(refresh=True)를 시행하기전에 반드시 먼저 실행해줘아 한다.
|
135
|
+
LSTM 모델 학습을 위한 데이터를 준비합니다.
|
105
136
|
|
106
|
-
|
107
|
-
|
108
|
-
|
137
|
+
Yahoo Finance에서 주가 데이터를 가져와 정규화, 학습 및 테스트 데이터로 분리,
|
138
|
+
LSTM 모델 입력 형식으로 변환합니다. `get_final_predictions` 메서드 실행 전에
|
139
|
+
반드시 호출해야 합니다.
|
109
140
|
"""
|
110
141
|
def get_raw_data() -> pd.DataFrame:
|
111
142
|
"""
|
@@ -196,34 +227,24 @@ class MyLSTM:
|
|
196
227
|
y_train_1d=y_train_1d,
|
197
228
|
y_test_1d=y_test_1d,
|
198
229
|
)
|
230
|
+
|
231
|
+
self.scaler = MinMaxScaler(feature_range=(0, 1))
|
232
|
+
|
199
233
|
self.raw_data = get_raw_data()
|
200
234
|
self.lstm_data = preprocessing_for_lstm()
|
201
235
|
|
202
236
|
def ensemble_training(self, num) -> Tuple[list, LSTMGrade]:
|
203
237
|
"""
|
204
|
-
|
205
|
-
Defines functions for LSTM model training, prediction, grading results, and ensemble model training.
|
238
|
+
앙상블 LSTM 모델을 훈련하고, 예측 결과를 생성 및 평가합니다.
|
206
239
|
|
207
|
-
|
208
|
-
|
209
|
-
- prediction: Uses a trained model to perform predictions, restores normalization, and returns results.
|
210
|
-
- grading: Analyzes the training and testing predictions, computes evaluation metrics, and returns grading details.
|
211
|
-
- ensemble_training: Trains multiple LSTM models to create ensemble predictions and future forecasts.
|
240
|
+
매개변수:
|
241
|
+
num (int): 앙상블에 포함할 모델의 수.
|
212
242
|
|
213
|
-
|
214
|
-
|
215
|
-
and future trend forecasting. Evaluates the models collectively using grading metrics.
|
243
|
+
반환값:
|
244
|
+
Tuple[list, LSTMGrade]: 미래 예측 값 리스트와 학습 결과 평가 데이터.
|
216
245
|
|
217
|
-
|
218
|
-
|
219
|
-
The number of ensemble LSTM models to train.
|
220
|
-
|
221
|
-
Returns:
|
222
|
-
Tuple[list, LSTMGrade]
|
223
|
-
A list of predicted scaled values for future forecasts and the performance grading object.
|
224
|
-
|
225
|
-
Raises:
|
226
|
-
Does not explicitly raise errors but logs warnings for possible issues during training or prediction.
|
246
|
+
예외:
|
247
|
+
IndexError: 모델 훈련을 위한 데이터가 부족한 경우 경고 로그를 출력합니다.
|
227
248
|
"""
|
228
249
|
def model_training() -> Sequential:
|
229
250
|
# LSTM 모델 생성 - 유닛과 드롭아웃의 수는 테스트로 최적화 됨.
|
@@ -375,25 +396,18 @@ class MyLSTM:
|
|
375
396
|
|
376
397
|
def get_final_predictions(self, refresh: bool, num=5) -> Tuple[dict, LSTMGrade]:
|
377
398
|
"""
|
378
|
-
|
399
|
+
LSTM 모델을 사용하여 미래 주가를 예측하고 평가 데이터를 반환합니다.
|
379
400
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
and caches whether the predicted data demonstrates an increasing trend over time.
|
401
|
+
매개변수:
|
402
|
+
refresh (bool): 데이터 새로고침 여부.
|
403
|
+
num (int): 앙상블 모델의 수. 기본값은 5.
|
384
404
|
|
385
|
-
|
386
|
-
|
387
|
-
num (int): Number of times to repeat ensemble training for more consistent predictions.
|
388
|
-
Defaults to 5.
|
405
|
+
반환값:
|
406
|
+
Tuple[dict, LSTMGrade]: 날짜별 예측 주가와 모델 평가 데이터.
|
389
407
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
Raises:
|
395
|
-
AssertionError: Raised if the lengths of 'future_dates' and 'final_future_predictions' do
|
396
|
-
not match during the data preparation.
|
408
|
+
로그:
|
409
|
+
- 캐시 데이터 검색 및 새 데이터 생성 과정 출력.
|
410
|
+
- 예측 값의 증가 추세를 분석하여 캐시에 저장.
|
397
411
|
"""
|
398
412
|
print("**** Start get_final_predictions... ****")
|
399
413
|
redis_name = f'{self.ticker}_mylstm_predictions'
|
@@ -414,36 +428,8 @@ class MyLSTM:
|
|
414
428
|
redis_name = f'{self.ticker}_is_lstm_up'
|
415
429
|
print(f"redisname: '{redis_name}' / expire_time : {expire_time / 3600}h")
|
416
430
|
|
417
|
-
|
418
|
-
|
419
|
-
# 데이터가 비어있으면 추세를 판단할 수 없음
|
420
|
-
return False
|
421
|
-
|
422
|
-
# 1) 날짜(키) 기준 오름차순 정렬
|
423
|
-
sorted_dates = sorted(future_data_in.keys())
|
424
|
-
values = [future_data_in[d] for d in sorted_dates]
|
425
|
-
|
426
|
-
# 2) x 축을 0,1,2... 형태로 부여 (날짜 간격을 동일하게 가정)
|
427
|
-
x = np.arange(len(values), dtype=float)
|
428
|
-
y = np.array(values, dtype=float)
|
429
|
-
|
430
|
-
# 3) 선형 회귀(최소제곱법)로 기울기(slope) 계산
|
431
|
-
x_mean = np.mean(x)
|
432
|
-
y_mean = np.mean(y)
|
433
|
-
|
434
|
-
# 분자: sum((xi - x_mean) * (yi - y_mean))
|
435
|
-
numerator = np.sum((x - x_mean) * (y - y_mean))
|
436
|
-
# 분모: sum((xi - x_mean)^2)
|
437
|
-
denominator = np.sum((x - x_mean) ** 2)
|
438
|
-
|
439
|
-
if denominator == 0:
|
440
|
-
# 데이터가 1개 이하인 경우 등
|
441
|
-
return False
|
442
|
-
|
443
|
-
slope = numerator / denominator
|
444
|
-
|
445
|
-
# 4) 기울기가 양수면 "우상향 추세"로 판별
|
446
|
-
is_up = slope > 0
|
431
|
+
is_up = tsa.common.is_up_by_OLS(future_data_in)
|
432
|
+
mylogger.debug(f"is_up: {is_up}")
|
447
433
|
myredis.Base.set_value(redis_name, is_up, expire_time)
|
448
434
|
|
449
435
|
def fetch_final_predictions(num_in) -> tuple:
|
@@ -470,6 +456,7 @@ class MyLSTM:
|
|
470
456
|
data[future_dates[i].strftime("%Y-%m-%d")] = final_future_predictions[i][0]
|
471
457
|
return data
|
472
458
|
|
459
|
+
self.initializing()
|
473
460
|
# 앙상블 트레이닝 시행
|
474
461
|
future_predictions_2d, lstm_grade = self.ensemble_training(num=num_in)
|
475
462
|
mylogger.debug(f'future_predictions_2d[:5] : {future_predictions_2d[:5]}')
|
@@ -490,32 +477,21 @@ class MyLSTM:
|
|
490
477
|
|
491
478
|
return future_data, lstm_grade
|
492
479
|
|
493
|
-
def export(self, refresh=False, to="
|
480
|
+
def export(self, refresh=False, to="html", num=5) -> Optional[str]:
|
494
481
|
"""
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
Returns
|
510
|
-
-------
|
511
|
-
Optional[str]
|
512
|
-
A string representation of the graph in HTML format if `to` is set to 'str'.
|
513
|
-
Returns None if `to` is set to either 'png' or 'htmlfile'.
|
514
|
-
|
515
|
-
Raises
|
516
|
-
------
|
517
|
-
Exception
|
518
|
-
Raised if the `to` parameter does not match the allowed values: 'str', 'png', or 'htmlfile'.
|
482
|
+
과거 및 예측된 주가 데이터를 기반으로 시각화를 생성하고 저장합니다.
|
483
|
+
|
484
|
+
매개변수:
|
485
|
+
refresh (bool): 데이터 새로고침 여부. 기본값은 False.
|
486
|
+
to (str): 그래프 출력 형식 ('hrml', 'png', 'file'). 기본값은 'html'.
|
487
|
+
num (int): 예측 모델 수. 기본값은 5.
|
488
|
+
|
489
|
+
반환값:
|
490
|
+
Optional[str]: HTML 형식의 그래프 문자열(`to='html'`인 경우).
|
491
|
+
None: PNG 또는 HTML 파일로 저장된 경우.
|
492
|
+
|
493
|
+
예외:
|
494
|
+
Exception: 잘못된 `to` 값이 주어졌을 때 발생.
|
519
495
|
"""
|
520
496
|
def prepare_past_data(past_days) -> tuple:
|
521
497
|
# 데이터 준비
|
@@ -597,7 +573,7 @@ class MyLSTM:
|
|
597
573
|
showlegend=False,
|
598
574
|
)
|
599
575
|
|
600
|
-
if to == '
|
576
|
+
if to == 'html':
|
601
577
|
# 그래프 HTML로 변환 (string 형식으로 저장)
|
602
578
|
graph_html = plot(fig, output_type='div')
|
603
579
|
return graph_html
|
@@ -605,7 +581,7 @@ class MyLSTM:
|
|
605
581
|
# 그래프를 PNG 파일로 저장
|
606
582
|
fig.write_image(f"myLSTM_{self.ticker}.png")
|
607
583
|
return None
|
608
|
-
elif to == '
|
584
|
+
elif to == 'file':
|
609
585
|
# 그래프를 HTML로 저장
|
610
586
|
plot(fig, filename=f'myLSTM_{self.ticker}.html', auto_open=False)
|
611
587
|
return None
|
@@ -614,24 +590,13 @@ class MyLSTM:
|
|
614
590
|
|
615
591
|
def visualization(self, refresh=True):
|
616
592
|
"""
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
refresh : bool, optional
|
625
|
-
Indicates whether to refresh and retrieve the latest predictions before
|
626
|
-
visualizing. Defaults to True.
|
627
|
-
|
628
|
-
Raises
|
629
|
-
------
|
630
|
-
None
|
631
|
-
|
632
|
-
Returns
|
633
|
-
-------
|
634
|
-
None
|
593
|
+
실제 주가와 예측 주가를 시각화합니다.
|
594
|
+
|
595
|
+
매개변수:
|
596
|
+
refresh (bool): 예측 데이터를 새로고침할지 여부. 기본값은 True.
|
597
|
+
|
598
|
+
반환값:
|
599
|
+
None: 시각화를 출력합니다.
|
635
600
|
"""
|
636
601
|
self.initializing()
|
637
602
|
future_data, _ = self.get_final_predictions(refresh=refresh)
|
@@ -668,18 +633,22 @@ class MyLSTM:
|
|
668
633
|
|
669
634
|
def is_lstm_up(self) -> bool:
|
670
635
|
"""
|
671
|
-
|
636
|
+
LSTM 모델의 추세가 상승인지 여부를 확인합니다.
|
672
637
|
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
Returns:
|
677
|
-
bool: True if the LSTM model is active (up), False otherwise.
|
638
|
+
반환값:
|
639
|
+
bool: 추세가 상승 상태(True) 또는 추세가 하락 상태(False).
|
678
640
|
"""
|
679
641
|
return myredis.Base.get_value(f'{self.ticker}_is_lstm_up')
|
680
642
|
|
681
643
|
|
682
644
|
class CorpLSTM(MyLSTM):
|
645
|
+
"""
|
646
|
+
특정 기업 코드를 기반으로 주가를 예측하는 LSTM 클래스.
|
647
|
+
|
648
|
+
속성:
|
649
|
+
code (str): 기업 코드.
|
650
|
+
name (str): 기업명.
|
651
|
+
"""
|
683
652
|
def __init__(self, code: str):
|
684
653
|
assert tools.is_6digit(code), f'Invalid value : {code}'
|
685
654
|
self._code = code
|
@@ -699,10 +668,16 @@ class CorpLSTM(MyLSTM):
|
|
699
668
|
|
700
669
|
|
701
670
|
class MILSTM(MyLSTM):
|
671
|
+
"""
|
672
|
+
특정 MI 타입에 따라 주가를 예측하는 LSTM 클래스.
|
673
|
+
|
674
|
+
속성:
|
675
|
+
mi_type (str): MI 타입.
|
676
|
+
"""
|
702
677
|
def __init__(self, mi_type: str):
|
703
|
-
assert mi_type in MIs.
|
678
|
+
assert mi_type in MIs._fields, f"Invalid MI type ({MIs._fields})"
|
704
679
|
self._mi_type = mi_type
|
705
|
-
super().__init__(ticker=MIs
|
680
|
+
super().__init__(ticker=getattr(MIs, mi_type))
|
706
681
|
|
707
682
|
@property
|
708
683
|
def mi_type(self) -> str:
|
@@ -710,7 +685,7 @@ class MILSTM(MyLSTM):
|
|
710
685
|
|
711
686
|
@mi_type.setter
|
712
687
|
def mi_type(self, mi_type: str):
|
713
|
-
assert mi_type in MIs.
|
688
|
+
assert mi_type in MIs._fields, f"Invalid MI type ({MIs._fields})"
|
714
689
|
self._mi_type = mi_type
|
715
|
-
self.ticker = MIs
|
690
|
+
self.ticker = getattr(MIs, mi_type)
|
716
691
|
|