analyser_hj3415 2.10.6__py3-none-any.whl → 3.0.1__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.
@@ -0,0 +1,13 @@
1
+ from dotenv import load_dotenv
2
+ from utils_hj3415.tools import get_env_path
3
+ from utils_hj3415.logger import mylogger
4
+
5
+ env_path = get_env_path()
6
+ if env_path is None:
7
+ mylogger.warning(f"환경변수 파일(.env)를 찾을수 없습니다. 기본 설정값으로 프로그램을 실행합니다.")
8
+ load_dotenv(env_path)
9
+
10
+ from analyser_hj3415.analyser import eval
11
+ from analyser_hj3415.analyser import score
12
+ from analyser_hj3415.analyser import tsa
13
+
File without changes
@@ -0,0 +1,4 @@
1
+ from .red import *
2
+ from .mil import *
3
+ from .blue import *
4
+ from .growth import *
@@ -0,0 +1,187 @@
1
+ import os
2
+ from dataclasses import dataclass, asdict
3
+ from typing import Tuple
4
+ import math
5
+
6
+ from utils_hj3415 import tools, setup_logger
7
+ from db_hj3415 import myredis
8
+
9
+ from analyser_hj3415.analyser.eval.common import Tools
10
+
11
+
12
+ mylogger = setup_logger(__name__,'WARNING')
13
+ expire_time = tools.to_int(os.getenv('DEFAULT_EXPIRE_TIME_H', 48)) * 3600
14
+
15
+
16
+ @dataclass()
17
+ class BlueData:
18
+ code: str
19
+ name: str
20
+
21
+ 유동비율: float
22
+
23
+ 이자보상배율_r: float
24
+ 이자보상배율_dict: dict
25
+
26
+ 순운전자본회전율_r: float
27
+ 순운전자본회전율_dict: dict
28
+
29
+ 재고자산회전율_r: float
30
+ 재고자산회전율_dict: dict
31
+ 재고자산회전율_c106: dict
32
+
33
+ 순부채비율_r: float
34
+ 순부채비율_dict: dict
35
+
36
+ score: list
37
+ date: list
38
+
39
+
40
+ class Blue:
41
+ def __init__(self, code: str):
42
+ assert tools.is_6digit(code), f'Invalid value : {code}'
43
+ mylogger.debug(f"Blue : 종목코드 ({code})")
44
+
45
+ self.c101 = myredis.C101(code)
46
+ self.c103 = myredis.C103(code, 'c103재무상태표q')
47
+ self.c104 = myredis.C104(code, 'c104q')
48
+
49
+ self.name = self.c101.get_name()
50
+ self._code = code
51
+
52
+ def __str__(self):
53
+ return f"Blue({self.code}/{self.name})"
54
+
55
+ @property
56
+ def code(self) -> str:
57
+ return self._code
58
+
59
+ @code.setter
60
+ def code(self, code: str):
61
+ assert tools.is_6digit(code), f'Invalid value : {code}'
62
+ mylogger.debug(f"Blue : 종목코드 변경({self.code} -> {code})")
63
+
64
+ self.c101.code = code
65
+ self.c103.code = code
66
+ self.c104.code = code
67
+
68
+ self.name = self.c101.get_name()
69
+ self._code = code
70
+
71
+ def _calc유동비율(self, pop_count: int, refresh: bool) -> Tuple[str, float]:
72
+ """유동비율계산 - Blue에서 사용
73
+
74
+ c104q에서 최근유동비율 찾아보고 유효하지 않거나 \n
75
+ 100이하인 경우에는수동으로 계산해서 다시 한번 평가해 본다.\n
76
+ """
77
+ mylogger.info(f'In the calc유동비율... refresh : {refresh}')
78
+ self.c104.page = 'c104q'
79
+
80
+ 유동비율date, 유동비율value = self.c104.latest_value('유동비율', pop_count=pop_count)
81
+ mylogger.info(f'{self} 유동비율 : {유동비율value}/({유동비율date})')
82
+
83
+ if math.isnan(유동비율value) or 유동비율value < 100:
84
+ 유동자산date, 유동자산value = Tools.calc유동자산(self.c103, refresh)
85
+ 유동부채date, 유동부채value = Tools.calc유동부채(self.c103, refresh)
86
+
87
+ self.c103.page = 'c103현금흐름표q'
88
+ 추정영업현금흐름date, 추정영업현금흐름value = self.c103.sum_recent_4q('영업활동으로인한현금흐름', refresh)
89
+ mylogger.debug(f'{self} 계산전 유동비율 : {유동비율value} / ({유동비율date})')
90
+
91
+ 계산된유동비율 = 0
92
+ try:
93
+ 계산된유동비율 = round(((유동자산value + 추정영업현금흐름value) / 유동부채value) * 100, 2)
94
+ except ZeroDivisionError:
95
+ mylogger.info(f'유동자산: {유동자산value} + 추정영업현금흐름: {추정영업현금흐름value} / 유동부채: {유동부채value}')
96
+ 계산된유동비율 = float('inf')
97
+ finally:
98
+ mylogger.debug(f'{self} 계산된 유동비율 : {계산된유동비율}')
99
+
100
+ try:
101
+ date, *_ = Tools.date_set(유동자산date, 유동부채date, 추정영업현금흐름date)
102
+ except ValueError:
103
+ # 날짜 데이터가 없는경우
104
+ date = ''
105
+ mylogger.warning(f'{self} 유동비율 이상(100 이하 또는 nan) : {유동비율value} -> 재계산 : {계산된유동비율}')
106
+ return date, 계산된유동비율
107
+ else:
108
+ return 유동비율date, 유동비율value
109
+
110
+ def _score(self) -> list:
111
+ return [0 ,]
112
+
113
+ def _generate_data(self, refresh: bool) -> BlueData:
114
+ d1, 유동비율 = self._calc유동비율(pop_count=3, refresh=refresh)
115
+ mylogger.info(f'유동비율 {유동비율} / [{d1}]')
116
+
117
+ 재고자산회전율_c106 = myredis.C106.make_like_c106(self.code, 'c104q', '재고자산회전율', refresh)
118
+
119
+ self.c104.page = 'c104y'
120
+ _, 이자보상배율_dict = self.c104.find('이자보상배율', remove_yoy=True, refresh=refresh)
121
+ _, 순운전자본회전율_dict = self.c104.find('순운전자본회전율', remove_yoy=True, refresh=refresh)
122
+ _, 재고자산회전율_dict = self.c104.find('재고자산회전율', remove_yoy=True, refresh=refresh)
123
+ _, 순부채비율_dict = self.c104.find('순부채비율', remove_yoy=True, refresh=refresh)
124
+
125
+ self.c104.page = 'c104q'
126
+ d6, 이자보상배율_r = self.c104.latest_value_pop2('이자보상배율', refresh)
127
+ d7, 순운전자본회전율_r = self.c104.latest_value_pop2('순운전자본회전율', refresh)
128
+ d8, 재고자산회전율_r = self.c104.latest_value_pop2('재고자산회전율', refresh)
129
+ d9, 순부채비율_r = self.c104.latest_value_pop2('순부채비율', refresh)
130
+
131
+ if len(이자보상배율_dict) == 0:
132
+ mylogger.warning(f'empty dict - 이자보상배율 : {이자보상배율_r} / {이자보상배율_dict}')
133
+
134
+ if len(순운전자본회전율_dict) == 0:
135
+ mylogger.warning(f'empty dict - 순운전자본회전율 : {순운전자본회전율_r} / {순운전자본회전율_dict}')
136
+
137
+ if len(재고자산회전율_dict) == 0:
138
+ mylogger.warning(f'empty dict - 재고자산회전율 : {재고자산회전율_r} / {재고자산회전율_dict}')
139
+
140
+ if len(순부채비율_dict) == 0:
141
+ mylogger.warning(f'empty dict - 순부채비율 : {순부채비율_r} / {순부채비율_dict}')
142
+
143
+ score = self._score()
144
+
145
+ try:
146
+ date_list = Tools.date_set(d1, d6, d7, d8, d9)
147
+ except ValueError:
148
+ # 날짜 데이터가 없는경우
149
+ date_list = ['' ,]
150
+
151
+ return BlueData(
152
+ code= self.code,
153
+ name= self.name,
154
+ 유동비율= 유동비율,
155
+ 이자보상배율_r= 이자보상배율_r,
156
+ 이자보상배율_dict= 이자보상배율_dict,
157
+
158
+ 순운전자본회전율_r= 순운전자본회전율_r,
159
+ 순운전자본회전율_dict= 순운전자본회전율_dict,
160
+
161
+ 재고자산회전율_r= 재고자산회전율_r,
162
+ 재고자산회전율_dict= 재고자산회전율_dict,
163
+ 재고자산회전율_c106= 재고자산회전율_c106,
164
+
165
+ 순부채비율_r= 순부채비율_r,
166
+ 순부채비율_dict= 순부채비율_dict,
167
+
168
+ score= score,
169
+ date= date_list,
170
+ )
171
+
172
+ def get(self, refresh = False, verbose = True) -> BlueData:
173
+ """
174
+ BlueData 형식의 데이터를 계산하여 리턴하고 레디스 캐시에 저장한다.
175
+ :param refresh:
176
+ :return:
177
+ """
178
+ redis_name = f"{self.code}_blue"
179
+ mylogger.info(f"{self} BlueData를 레디스캐시에서 가져오거나 새로 생성합니다.. refresh : {refresh}")
180
+ if verbose:
181
+ print(f"{self} redisname: '{redis_name}' / refresh : {refresh} / expire_time : {expire_time /3600}h")
182
+
183
+ def fetch_generate_data(refresh_in: bool) -> dict:
184
+ return asdict(self._generate_data(refresh_in))
185
+
186
+ return BlueData \
187
+ (**myredis.Base.fetch_and_cache_data(redis_name, refresh, fetch_generate_data, refresh, timer=expire_time))
@@ -0,0 +1,267 @@
1
+ import math
2
+ from typing import Tuple
3
+
4
+ from db_hj3415 import myredis
5
+ from utils_hj3415.tools import nan_to_zero
6
+ from utils_hj3415 import setup_logger
7
+
8
+ mylogger = setup_logger(__name__,'WARNING')
9
+
10
+
11
+ class Tools:
12
+ @staticmethod
13
+ def cal_deviation(v1: float, v2: float) -> float:
14
+ """
15
+ Calculates the percentage deviation between two values.
16
+
17
+ This method computes the percentage deviation of the second value
18
+ from the first value based on the formula:
19
+ deviation = abs((v1 - v2) / v1) * 100. In the event the first value is
20
+ zero (division by zero), the function will return NaN to signify
21
+ an invalid computation.
22
+
23
+ Parameters:
24
+ v1 (float): The reference value. It represents the base for the relative
25
+ deviation calculation.
26
+ v2 (float): The value to compare against the reference.
27
+
28
+ Returns:
29
+ float: The computed percentage deviation. Returns NaN if the reference
30
+ value (v1) is zero.
31
+ """
32
+ try:
33
+ deviation = abs((v1 - v2) / v1) * 100
34
+ except ZeroDivisionError:
35
+ deviation = math.nan
36
+ return deviation
37
+
38
+ @staticmethod
39
+ def date_set(*args) -> list:
40
+ """
41
+ 인자로 받은 값의 비유효한 내용 제거(None,nan)하고 중복된 항목 제거하고 리스트로 반환한다.
42
+
43
+ 여기서 set의 의미는 집합을 뜻함
44
+
45
+ Filters and returns a list of unique non-null, non-empty values from
46
+ the provided arguments.
47
+
48
+ This static method processes the input arguments to retain only unique
49
+ values that are not empty strings, NaN values, or None. The result is
50
+ returned as a list.
51
+
52
+ Args:
53
+ *args: Arbitrary positional arguments to be filtered.
54
+
55
+ Returns:
56
+ list: A list of unique values after filtering out invalid entries.
57
+ """
58
+ return [i for i in {*args} if i != "" and i is not math.nan and i is not None]
59
+
60
+ @staticmethod
61
+ def calc당기순이익(c103: myredis.C103, refresh: bool) -> Tuple[str, float]:
62
+ """
63
+ 지배지분 당기순이익 계산
64
+
65
+ 일반적인 경우로는 직전 지배주주지분 당기순이익을 찾아서 반환한다.
66
+
67
+ 금융기관의 경우는 지배당기순이익이 없기 때문에 계산을 통해서 간접적으로 구한다.
68
+
69
+ Calculates "지배당기순이익" (Controlling Comprehensive Income) based on the given
70
+ financial data. The method retrieves or computes the value utilizing methods from
71
+ the `myredis.C103` class. It handles missing or 'Not-a-Number' conditions by
72
+ manually calculating from quarterly and annual financial figures. Logs the process
73
+ at various stages for debugging and auditing.
74
+
75
+ Args:
76
+ c103 (myredis.C103): An instance containing financial data and utilities to
77
+ access specific data points for the targeted calculation.
78
+ refresh (bool): A flag to determine whether or not to refresh the data
79
+ while accessing or computing financial values.
80
+
81
+ Returns:
82
+ Tuple[str, float]: A tuple where the first item is the most relevant date for
83
+ the calculated or retrieved value, and the second item is the calculated
84
+ or retrieved "지배당기순이익" (Controlling Comprehensive Income).
85
+ """
86
+ name = myredis.Corps(c103.code, 'c101').get_name(refresh=refresh)
87
+
88
+ mylogger.info(f'{c103.code} / {name} Tools : 당기순이익 계산.. refresh : {refresh}')
89
+ c103.page = 'c103재무상태표q'
90
+
91
+ d1, 지배당기순이익 = c103.latest_value_pop2('*(지배)당기순이익', refresh)
92
+ mylogger.debug(f"*(지배)당기순이익: {지배당기순이익}")
93
+
94
+ if math.isnan(지배당기순이익):
95
+ mylogger.warning(f"{c103.code} / {name} - (지배)당기순이익이 없는 종목. 수동으로 계산합니다.")
96
+ c103.page = 'c103손익계산서q'
97
+ d2, 최근4분기당기순이익 = c103.sum_recent_4q('당기순이익', refresh)
98
+ mylogger.debug(f"{c103.code} / {name} - 최근4분기당기순이익 : {최근4분기당기순이익}")
99
+ c103.page = 'c103재무상태표y'
100
+ d3, 비지배당기순이익 = c103.latest_value_pop2('*(비지배)당기순이익', refresh)
101
+ mylogger.debug(f"{c103.code} / {name} - 비지배당기순이익y : {비지배당기순이익}")
102
+ # 가변리스트 언패킹으로 하나의 날짜만 사용하고 나머지는 버린다.
103
+ # 여기서 *_는 “나머지 값을 다 무시하겠다”는 의미
104
+ mylogger.debug(f"d2:{d2}, d3: {d3}")
105
+ try:
106
+ date, *_ = Tools.date_set(d2, d3)
107
+ except ValueError:
108
+ # 날짜 데이터가 없는경우
109
+ date = ''
110
+ 계산된지배당기순이익 = round(최근4분기당기순이익 - nan_to_zero(비지배당기순이익), 1)
111
+ mylogger.debug(f"{c103.code} / {name} - 계산된 지배당기순이익 : {계산된지배당기순이익}")
112
+ return date, 계산된지배당기순이익
113
+ else:
114
+ return d1, 지배당기순이익
115
+
116
+ @staticmethod
117
+ def calc유동자산(c103: myredis.C103, refresh: bool) -> Tuple[str, float]:
118
+ """
119
+ 유효한 유동자산 계산
120
+
121
+ 일반적인 경우로 유동자산을 찾아서 반환한다.
122
+
123
+ 금융기관의 경우는 간접적으로 계산한다.
124
+
125
+ Calculates the current assets for a given company code.
126
+
127
+ For a specified company, the function calculates the recent 4-quarter
128
+ sum of current assets if available. If the data is not available or
129
+ contains invalid values, it attempts to calculate the current assets
130
+ manually using financial asset data such as cash equivalents, trading
131
+ securities, available-for-sale securities, and held-to-maturity securities.
132
+
133
+ Logs relevant information and warnings during the calculation process,
134
+ including any cases where data is unavailable or a manual calculation
135
+ is required.
136
+
137
+ Parameters:
138
+ c103 (myredis.C103): The instance representing financial data of a
139
+ specific company. This includes methods to extract and calculate
140
+ various data points.
141
+ refresh (bool): Indicator flag to determine whether to refresh the
142
+ underlying data before performing calculations.
143
+
144
+ Returns:
145
+ Tuple[str, float]: A tuple containing the date associated with the
146
+ financial data and the calculated or retrieved value of current
147
+ assets. If dates are not available, the date field may be empty.
148
+ """
149
+
150
+ name = myredis.Corps(c103.code, 'c101').get_name(refresh=refresh)
151
+
152
+ mylogger.info(f'{c103.code} / {name} Tools : 유동자산계산... refresh : {refresh}')
153
+ c103.page = 'c103재무상태표q'
154
+
155
+ d, 유동자산 = c103.sum_recent_4q('유동자산', refresh)
156
+ if math.isnan(유동자산):
157
+ mylogger.warning(f"{c103.code} / {name} - 유동자산이 없는 종목. 수동으로 계산합니다(금융관련업종일 가능성있음).")
158
+ d1, v1 = c103.latest_value_pop2('현금및예치금', refresh)
159
+ d2, v2 = c103.latest_value_pop2('단기매매금융자산', refresh)
160
+ d3, v3 = c103.latest_value_pop2('매도가능금융자산', refresh)
161
+ d4, v4 = c103.latest_value_pop2('만기보유금융자산', refresh)
162
+ mylogger.debug(f'{c103.code} / {name} 현금및예치금 : {d1}, {v1}')
163
+ mylogger.debug(f'{c103.code} / {name} 단기매매금융자산 : {d2}, {v2}')
164
+ mylogger.debug(f'{c103.code} / {name} 매도가능금융자산 : {d3}, {v3}')
165
+ mylogger.debug(f'{c103.code} / {name} 만기보유금융자산 : {d4}, {v4}')
166
+
167
+ try:
168
+ date, *_ = Tools.date_set(d1, d2, d3, d4)
169
+ except ValueError:
170
+ # 날짜 데이터가 없는경우
171
+ date = ''
172
+ 계산된유동자산value = round(
173
+ nan_to_zero(v1) + nan_to_zero(v2) + nan_to_zero(v3) + nan_to_zero(v4), 1)
174
+
175
+ mylogger.info(f"{c103.code} / {name} - 계산된 유동자산 : {계산된유동자산value}")
176
+ return date, 계산된유동자산value
177
+ else:
178
+ return d, 유동자산
179
+
180
+ @staticmethod
181
+ def calc유동부채(c103: myredis.C103, refresh: bool) -> Tuple[str, float]:
182
+ """
183
+ 유효한 유동부채 계산
184
+
185
+ 일반적인 경우로 유동부채를 찾아서 반환한다.
186
+
187
+ 금융기관의 경우는 간접적으로 계산한다.
188
+
189
+ Calculate '유동부채' (Current Liabilities) based on financial data of a specific entity.
190
+
191
+ This static method computes the recent '유동부채' value either from the sum of recent four
192
+ quarters using predefined keys or calculates manually if no valid data is available.
193
+ It includes logging for intermediate steps and supports handling missing values by logging
194
+ warnings and attempting a composed manual computation using alternative financial terms.
195
+
196
+ Args:
197
+ c103 (myredis.C103): The object containing financial data and operations for obtaining the required data.
198
+ refresh (bool): A flag to indicate whether to fetch the latest data forcibly.
199
+
200
+ Returns:
201
+ Tuple[str, float]: A tuple containing the `date` of financial data and the computed '유동부채' value.
202
+ """
203
+
204
+ name = myredis.Corps(c103.code, 'c101').get_name(refresh=refresh)
205
+
206
+ mylogger.info(f'{c103.code} / {name} Tools : 유동부채계산... refresh : {refresh}')
207
+ c103.page = 'c103재무상태표q'
208
+
209
+ d, 유동부채 = c103.sum_recent_4q('유동부채', refresh)
210
+ if math.isnan(유동부채):
211
+ mylogger.warning(f"{c103.code} / {name} - 유동부채가 없는 종목. 수동으로 계산합니다.")
212
+ d1, v1 = c103.latest_value_pop2('당기손익인식(지정)금융부채', refresh)
213
+ d2, v2 = c103.latest_value_pop2('당기손익-공정가치측정금융부채', refresh)
214
+ d3, v3 = c103.latest_value_pop2('매도파생결합증권', refresh)
215
+ d4, v4 = c103.latest_value_pop2('단기매매금융부채', refresh)
216
+ mylogger.debug(f'{c103.code} / {name} 당기손익인식(지정)금융부채 : {d1}, {v1}')
217
+ mylogger.debug(f'{c103.code} / {name} 당기손익-공정가치측정금융부채 : {d2}, {v2}')
218
+ mylogger.debug(f'{c103.code} / {name} 매도파생결합증권 : {d3}, {v3}')
219
+ mylogger.debug(f'{c103.code} / {name} 단기매매금융부채 : {d4}, {v4}')
220
+
221
+ try:
222
+ date, *_ = Tools.date_set(d1, d2, d3, d4)
223
+ except ValueError:
224
+ # 날짜 데이터가 없는경우
225
+ date = ''
226
+ 계산된유동부채value = round(
227
+ nan_to_zero(v1) + nan_to_zero(v2) + nan_to_zero(v3) + nan_to_zero(v4), 1)
228
+
229
+ mylogger.info(f"{c103.code} / {name} - 계산된 유동부채 : {계산된유동부채value}")
230
+ return date, 계산된유동부채value
231
+ else:
232
+ return d, 유동부채
233
+
234
+
235
+ """
236
+ - 각분기의 합이 연이 아닌 타이틀(즉 sum_4q를 사용하면 안됨)
237
+ '*(지배)당기순이익'
238
+ '*(비지배)당기순이익'
239
+ '장기차입금'
240
+ '현금및예치금'
241
+ '매도가능금융자산'
242
+ '매도파생결합증권'
243
+ '만기보유금융자산'
244
+ '당기손익-공정가치측정금융부채'
245
+ '당기손익인식(지정)금융부채'
246
+ '단기매매금융자산'
247
+ '단기매매금융부채'
248
+ '예수부채'
249
+ '차입부채'
250
+ '기타부채'
251
+ '보험계약부채(책임준비금)'
252
+ '*CAPEX'
253
+ 'ROE'
254
+ """
255
+
256
+ """
257
+ - sum_4q를 사용해도 되는 타이틀
258
+ '자산총계'
259
+ '당기순이익'
260
+ '유동자산'
261
+ '유동부채'
262
+ '비유동부채'
263
+
264
+ '영업활동으로인한현금흐름'
265
+ '재무활동으로인한현금흐름'
266
+ 'ROIC'
267
+ """
@@ -0,0 +1,110 @@
1
+ import os
2
+ from dataclasses import dataclass, asdict
3
+
4
+ from utils_hj3415 import tools, setup_logger
5
+ from db_hj3415 import myredis
6
+
7
+ from analyser_hj3415.analyser.eval.common import Tools
8
+
9
+
10
+ mylogger = setup_logger(__name__,'WARNING')
11
+ expire_time = tools.to_int(os.getenv('DEFAULT_EXPIRE_TIME_H', 48)) * 3600
12
+
13
+
14
+ @dataclass()
15
+ class GrowthData:
16
+ code: str
17
+ name: str
18
+
19
+ 매출액증가율_r: float
20
+ 매출액증가율_dict: dict
21
+
22
+ 영업이익률_c106: dict
23
+
24
+ score: list
25
+ date: list
26
+
27
+
28
+ class Growth:
29
+ def __init__(self, code: str):
30
+ assert tools.is_6digit(code), f'Invalid value : {code}'
31
+ mylogger.debug(f"Growth : 종목코드 ({code})")
32
+
33
+ self.c101 = myredis.C101(code)
34
+ self.c104 = myredis.C104(code, 'c104q')
35
+ self.c106 = myredis.C106(code, 'c106q')
36
+
37
+ self.name = self.c101.get_name()
38
+ self._code = code
39
+
40
+ def __str__(self):
41
+ return f"Growth({self.code}/{self.name})"
42
+
43
+ @property
44
+ def code(self) -> str:
45
+ return self._code
46
+
47
+ @code.setter
48
+ def code(self, code: str):
49
+ assert tools.is_6digit(code), f'Invalid value : {code}'
50
+ mylogger.debug(f"Growth : 종목코드 변경({self.code} -> {code})")
51
+
52
+ self.c101.code = code
53
+ self.c104.code = code
54
+ self.c106.code = code
55
+
56
+ self.name = self.c101.get_name()
57
+ self._code = code
58
+
59
+ def _score(self) -> list:
60
+ return [0,]
61
+
62
+ def _generate_data(self, refresh=False) -> GrowthData:
63
+ self.c104.page = 'c104y'
64
+ _, 매출액증가율_dict = self.c104.find('매출액증가율', remove_yoy=True, refresh=refresh)
65
+
66
+ self.c104.page = 'c104q'
67
+ d2, 매출액증가율_r = self.c104.latest_value_pop2('매출액증가율')
68
+
69
+ mylogger.info(f'매출액증가율 : {매출액증가율_r} {매출액증가율_dict}')
70
+
71
+ # c106 에서 타 기업과 영업이익률 비교
72
+ self.c106.page = 'c106y'
73
+ 영업이익률_c106 = self.c106.find('영업이익률', refresh)
74
+
75
+ score = self._score()
76
+
77
+ try:
78
+ date_list = Tools.date_set(d2)
79
+ except ValueError:
80
+ # 날짜 데이터가 없는경우
81
+ date_list = ['', ]
82
+
83
+ return GrowthData(
84
+ code= self.code,
85
+ name= self.name,
86
+
87
+ 매출액증가율_r= 매출액증가율_r,
88
+ 매출액증가율_dict= 매출액증가율_dict,
89
+
90
+ 영업이익률_c106= 영업이익률_c106,
91
+
92
+ score= score,
93
+ date= date_list,
94
+ )
95
+
96
+ def get(self, refresh = False, verbose = True) -> GrowthData:
97
+ """
98
+ GrowthData 형식의 데이터를 계산하여 리턴하고 레디스 캐시에 저장한다.
99
+ :param refresh:
100
+ :return:
101
+ """
102
+ redis_name = f"{self.code}_growth"
103
+ mylogger.info(f"{self} GrowthData를 레디스캐시에서 가져오거나 새로 생성합니다.. refresh : {refresh}")
104
+ if verbose:
105
+ print(f"{self} redisname: '{redis_name}' / refresh : {refresh} / expire_time : {expire_time/3600}h")
106
+
107
+ def fetch_generate_data(refresh_in: bool) -> dict:
108
+ return asdict(self._generate_data(refresh_in))
109
+
110
+ return GrowthData(**myredis.Base.fetch_and_cache_data(redis_name, refresh, fetch_generate_data, refresh, timer=expire_time))