analyser_hj3415 2.0.2__py2.py3-none-any.whl → 2.2.0__py2.py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,175 @@
1
+ from analyser_hj3415.analysers import eval
2
+ from db_hj3415.myredis import Base
3
+ import json
4
+
5
+ page = '.analyser'
6
+
7
+
8
+ def red(code: str) -> dict:
9
+ """
10
+ redis 사용 - 소멸타이머 사용
11
+ 리턴값
12
+ {
13
+ 'red_price': red_price,
14
+ '사업가치': 사업가치,
15
+ '재산가치': 재산가치,
16
+ '부채평가': 부채평가,
17
+ '발행주식수': 발행주식수,
18
+ 'date': [각 유효한 값의 년월값 리스트(ex- 2020/09)],
19
+ }
20
+ """
21
+ redis_name = code + page + '_eval_' + 'red'
22
+ try:
23
+ cached_data = Base.redis_client.get(redis_name).decode('utf-8')
24
+ except AttributeError:
25
+ # redis에 해당하는 값이 없는 경우
26
+ data = eval.red(code)
27
+ # print(data)
28
+ if data:
29
+ # 데이터를 Redis에 캐싱
30
+ Base.redis_client.set(redis_name, json.dumps(data))
31
+ # 60분후 키가 자동으로 제거됨
32
+ Base.redis_client.expire(redis_name, 3600)
33
+ print("analysers.eval 데이터 계산하기 - myredis.red")
34
+ return data
35
+ else:
36
+ print(f"Redis 캐시에서 데이터 가져오기(남은시간:{Base.redis_client.ttl(redis_name)}초) - myredis.red")
37
+ return json.loads(cached_data)
38
+
39
+
40
+ def mil(code: str) -> dict:
41
+ """
42
+ redis 사용 - 소멸타이머 사용
43
+ 리턴값
44
+ {
45
+ '주주수익률': 주주수익률,
46
+ '이익지표': 이익지표,
47
+ '투자수익률': {'ROIC': roic, 'ROE': roe , 'ROE106': {}},
48
+ '가치지표': {'FCF': fcf_dict, 'PFCF': pfcf_dict, 'PCR': pcr_dict},
49
+ 'date': [각 유효한 값의 년월값 리스트(ex- 2020/09)],
50
+ }
51
+
52
+ - 재무활동현금흐름이 마이너스라는 것은 배당급 지급했거나, 자사주 매입했거나, 부채를 상환한 상태임.
53
+ - 반대는 채권자로 자금을 조달했거나 신주를 발행했다는 의미
54
+ <주주수익률> - 재무활동현금흐름/시가총액 => 5%이상인가?
55
+
56
+ 투하자본수익률(ROIC)가 30%이상인가
57
+ ROE(자기자본이익률) 20%이상이면 아주 우수 다른 투자이익률과 비교해볼것 10%미만이면 별로...단, 부채비율을 확인해야함.
58
+
59
+ 이익지표 ...영업현금흐름이 순이익보다 많은가 - 결과값이 음수인가..
60
+
61
+ FCF는 영업현금흐름에서 자본적 지출(유·무형투자 비용)을 차감한 순수한 현금력이라 할 수 있다.
62
+ 말 그대로 자유롭게(Free) 사용할 수 있는 여윳돈을 뜻한다.
63
+ 잉여현금흐름이 플러스라면 미래의 투자나 채무상환에 쓸 재원이 늘어난 것이다.
64
+ CAPEX(Capital expenditures)는 미래의 이윤을 창출하기 위해 지출된 비용을 말한다.
65
+ 이는 기업이 고정자산을 구매하거나, 유효수명이 당회계년도를 초과하는 기존의 고정자산에 대한 투자에 돈이 사용될 때 발생한다.
66
+
67
+ 잉여현금흐름이 마이너스일때는 설비투자가 많은 시기라 주가가 약세이며 이후 설비투자 마무리되면서 주가가 상승할수 있다.
68
+ 주가는 잉여현금흐름이 증가할때 상승하는 경향이 있다.
69
+ fcf = 영업현금흐름 - capex
70
+
71
+ 가치지표평가
72
+ price to fcf 계산
73
+ https://www.investopedia.com/terms/p/pricetofreecashflow.asp
74
+ pcr보다 정확하게 주식의 가치를 평가할수 있음. 10배이하 추천
75
+ """
76
+ redis_name = code + page + '_eval_' + 'mil'
77
+ try:
78
+ cached_data = Base.redis_client.get(redis_name).decode('utf-8')
79
+ except AttributeError:
80
+ # redis에 해당하는 값이 없는 경우
81
+ data = eval.mil(code)
82
+ # print(data)
83
+ if data:
84
+ # 데이터를 Redis에 캐싱
85
+ Base.redis_client.set(redis_name, json.dumps(data))
86
+ # 60분후 키가 자동으로 제거됨
87
+ Base.redis_client.expire(redis_name, 3600)
88
+ print("analysers.eval 데이터 계산하기 - myredis.mil")
89
+ return data
90
+ else:
91
+ print(f"Redis 캐시에서 데이터 가져오기(남은시간:{Base.redis_client.ttl(redis_name)}초) - myredis.mil")
92
+ return json.loads(cached_data)
93
+
94
+
95
+ def blue(code: str) -> dict:
96
+ """
97
+ redis 사용 - 소멸타이머 사용
98
+ 리턴값
99
+ {
100
+ 'date': [각 유효한 값의 최근분기 값 리스트(ex- 2020/09)],
101
+ '순부채비율': (29.99, {'2018/12': 19.45, '2019/12': 19.52, '2020/12': 12.07, '2021/12': 82.2, '2022/12': 29.99, '2023/12': nan}),
102
+ '순운전자본회전율': (1.04, {'2018/12': 21.91, '2019/12': 23.12, '2020/12': 5.88, '2021/12': 5.6, '2022/12': 6.04, '2023/12': nan}),
103
+ '유동비율': 64.29,
104
+ '이자보상배율': (-3.64, {'2018/12': 4.01, '2019/12': 1.3, '2020/12': -5.05, '2021/12': 0.56, '2022/12': -1.28, '2023/12': nan}),
105
+ '재고자산회전율': (1.66, {'2018/12': 12.41, '2019/12': 12.44, '2020/12': 9.18, '2021/12': 9.76, '2022/12': 8.79, '2023/12': nan})
106
+ }
107
+
108
+ <유동비율>
109
+ 100미만이면 주의하나 현금흐름창출력이 좋으면 괜찮을수 있다.
110
+ 만약 100%이하면 유동자산에 추정영업현금흐름을 더해서 다시계산해보아 기회를 준다.
111
+ <이자보상배율>
112
+ 이자보상배율 영업이익/이자비용으로 1이면 자금사정빡빡 5이상이면 양호
113
+ <순운전자금회전율>
114
+ 순운전자금 => 기업활동을 하기 위해 필요한 자금 (매출채권 + 재고자산 - 매입채무)
115
+ 순운전자본회전율은 매출액/순운전자본으로 일정비율이 유지되는것이 좋으며 너무 작아지면 순운전자본이 많아졌다는 의미로 재고나 외상이 쌓인다는 뜻
116
+ <재고자산회전율>
117
+ 재고자산회전율은 매출액/재고자산으로 회전율이 낮을수록 재고가 많다는 이야기이므로 불리 전년도등과 비교해서 큰차이 발생하면 알람.
118
+ 재고자산회전율이 작아지면 재고가 쌓인다는뜻
119
+ <순부채비율>
120
+ 부채비율은 업종마다 달라 일괄비교 어려우나 순부채 비율이 20%이하인것이 좋고 꾸준히 늘어나지 않는것이 좋다.
121
+ 순부채 비율이 30%이상이면 좋치 않다.
122
+ <매출액>
123
+ 매출액은 어떤경우에도 성장하는 기업이 좋다.매출이 20%씩 늘어나는 종목은 유망한 종목
124
+ <영업이익률>
125
+ 영업이익률은 기업의 경쟁력척도로 경쟁사에 비해 높으면 경제적해자를 갖춘셈
126
+ """
127
+ redis_name = code + page + '_eval_' + 'blue'
128
+ try:
129
+ cached_data = Base.redis_client.get(redis_name).decode('utf-8')
130
+ except AttributeError:
131
+ # redis에 해당하는 값이 없는 경우
132
+ data = eval.blue(code)
133
+ # print(data)
134
+ if data:
135
+ # 데이터를 Redis에 캐싱
136
+ Base.redis_client.set(redis_name, json.dumps(data))
137
+ # 60분후 키가 자동으로 제거됨
138
+ Base.redis_client.expire(redis_name, 3600)
139
+ print("analysers.eval 데이터 계산하기 - myredis.blue")
140
+ return data
141
+ else:
142
+ print(f"Redis 캐시에서 데이터 가져오기(남은시간:{Base.redis_client.ttl(redis_name)}초) - myredis.blue")
143
+ return json.loads(cached_data)
144
+
145
+
146
+ def growth(code: str) -> dict:
147
+ """
148
+ redis 사용 - 소멸타이머 사용
149
+ 리턴값
150
+ {'date': [각 유효한 값의 최근분기 값 리스트(ex- 2020/09)],
151
+ '매출액증가율': (-14.37, {'2018/12': -24.56, '2019/12': -20.19, '2020/12': -12.64, '2021/12': 38.65, '2022/12': -8.56, '2023/12': nan}),
152
+ '영업이익률': {'뉴프렉스': '17.36', '동일기연': '13.58', '비에이치': '16.23', '에이엔피': '-9.30', '이브이첨단소재': '-4.93'}}
153
+
154
+ <매출액>
155
+ 매출액은 어떤경우에도 성장하는 기업이 좋다.매출이 20%씩 늘어나는 종목은 유망한 종목
156
+ <영업이익률>
157
+ 영업이익률은 기업의 경쟁력척도로 경쟁사에 비해 높으면 경제적해자를 갖춘셈
158
+ """
159
+ redis_name = code + page + '_eval_' + 'growth'
160
+ try:
161
+ cached_data = Base.redis_client.get(redis_name).decode('utf-8')
162
+ except AttributeError:
163
+ # redis에 해당하는 값이 없는 경우
164
+ data = eval.growth(code)
165
+ # print(data)
166
+ if data:
167
+ # 데이터를 Redis에 캐싱
168
+ Base.redis_client.set(redis_name, json.dumps(data))
169
+ # 60분후 키가 자동으로 제거됨
170
+ Base.redis_client.expire(redis_name, 3600)
171
+ print("analysers.eval 데이터 계산하기 - myredis.growth")
172
+ return data
173
+ else:
174
+ print(f"Redis 캐시에서 데이터 가져오기(남은시간:{Base.redis_client.ttl(redis_name)}초) - myredis.growth")
175
+ return json.loads(cached_data)
@@ -1,10 +1,9 @@
1
1
  import math
2
2
  from typing import Tuple
3
- from collections import OrderedDict
4
-
5
- from .mongo import C101, C103, C104, Corps
3
+ from db_hj3415.myredis import C101, C103, C104
6
4
 
7
5
  import logging
6
+
8
7
  logger = logging.getLogger(__name__)
9
8
  formatter = logging.Formatter('%(levelname)s: [%(name)s] %(message)s')
10
9
  ch = logging.StreamHandler()
@@ -13,24 +12,16 @@ logger.addHandler(ch)
13
12
  logger.setLevel(logging.WARNING)
14
13
 
15
14
 
16
- def extract_valid_one(*args):
15
+ def set_data(*args) -> list:
17
16
  """
18
- 유틸함수
19
- 딕셔너리 데이터를 입력받아 하나씩 pop 하여 빈데이터가 아닌 첫번째것을 반환한다.
17
+ 비유효한 내용 제거(None,nan)하고 중복된 항목 제거하고 리스트로 반환한다.
18
+ :param args:
19
+ :return:
20
20
  """
21
- logger.debug("In extract_valid_one func...")
22
- # 입력받은 데이터를 중복되는 것을 제하기 위해 집합으로 변환한다.
23
- d_set = {i for i in args}
24
- for i in d_set:
25
- logger.debug(i)
26
- # 하나씩 꺼내서 빈문자가 아니면 반환한다.
27
- if i != "" and i is not math.nan and i is not None:
28
- return i
29
- else:
30
- return None
21
+ return [i for i in {*args} if i != "" and i is not math.nan and i is not None]
31
22
 
32
23
 
33
- def calc당기순이익(client, code: str) -> Tuple[str, float]:
24
+ def calc당기순이익(code: str) -> Tuple[str, float]:
34
25
  """지배지분 당기순이익 계산
35
26
 
36
27
  일반적인 경우로는 직전 지배주주지분 당기순이익을 찾아서 반환한다.\n
@@ -38,25 +29,24 @@ def calc당기순이익(client, code: str) -> Tuple[str, float]:
38
29
  계산을 통해서 간접적으로 구한다.\n
39
30
  """
40
31
  logger.debug(f'In the calc당기순이익... code:{code}')
41
- c103q = C103(client, code, 'c103재무상태표q')
32
+ c103q = C103(code, 'c103재무상태표q')
42
33
  try:
43
- profit_dict = c103q.find(title='*(지배)당기순이익')
44
- logger.info(f'*(지배)당기순이익 : {profit_dict}')
45
- return c103q.latest_value('*(지배)당기순이익', nan_to_zero=True)
34
+ return c103q.latest_value_pop2('*(지배)당기순이익')
46
35
  except:
47
- # 금융관련은 재무상태표에 지배당기순이익이 없어서 손익계산서의 당기순이익에서 비지배당기순이익을 빼서 간접적으로 구한다.
36
+ logger.warning(f"{code} - (지배)당기순이익이 없는 종목. 수동으로 계산합니다(금융관련업종일 가능성있음).")
48
37
  c103q.page = 'c103손익계산서q'
49
- 최근당기순이익date, 최근당기순이익value = c103q.sum_recent_4q('당기순이익', nan_to_zero=True)
38
+ 최근당기순이익date, 최근당기순이익value = c103q.sum_recent_4q('당기순이익')
50
39
  c103q.page = 'c103재무상태표q'
51
- 비지배당기순이익date, 비지배당기순이익value= c103q.latest_value('*(비지배)당기순이익', nan_to_zero=True, allow_empty=True)
40
+ 비지배당기순이익date, 비지배당기순이익value = c103q.latest_value_pop2('*(비지배)당기순이익')
52
41
 
53
- date = extract_valid_one(최근당기순이익date, 비지배당기순이익date)
42
+ # 가변리스트 언패킹으로 하나의 날짜만 사용하고 나머지는 버린다.
43
+ date, *_ = set_data(최근당기순이익date, 비지배당기순이익date)
54
44
  계산된지배당기순이익value = 최근당기순이익value - 비지배당기순이익value
55
45
 
56
46
  return date, 계산된지배당기순이익value
57
47
 
58
48
 
59
- def calc유동자산(client, code: str) -> Tuple[str, float]:
49
+ def calc유동자산(code: str) -> Tuple[str, float]:
60
50
  """유효한 유동자산 계산
61
51
 
62
52
  일반적인 경우로 유동자산을 찾아서 반환한다.\n
@@ -64,29 +54,27 @@ def calc유동자산(client, code: str) -> Tuple[str, float]:
64
54
  Red와 Blue에서 사용한다.\n
65
55
  """
66
56
  logger.debug(f'In the calc유동자산... code:{code}')
67
- c103q = C103(client, code, 'c103재무상태표q')
57
+ c103q = C103(code, 'c103재무상태표q')
68
58
  try:
69
- asset_dict = c103q.find(title='유동자산')
70
- logger.info(f'유동자산 : {asset_dict}')
71
- return c103q.sum_recent_4q('유동자산', nan_to_zero=True)
59
+ return c103q.sum_recent_4q('유동자산')
72
60
  except:
73
- # 금융관련업종...
74
- d1, v1 = c103q.latest_value('현금및예치금', nan_to_zero=True, allow_empty=True)
75
- d2, v2 = c103q.latest_value('단기매매금융자산', nan_to_zero=True, allow_empty=True)
76
- d3, v3 = c103q.latest_value('매도가능금융자산', nan_to_zero=True, allow_empty=True)
77
- d4, v4 = c103q.latest_value('만기보유금융자산', nan_to_zero=True, allow_empty=True)
61
+ logger.warning(f"{code} - 유동자산이 없는 종목. 수동으로 계산합니다(금융관련업종일 가능성있음).")
62
+ d1, v1 = c103q.latest_value_pop2('현금및예치금')
63
+ d2, v2 = c103q.latest_value_pop2('단기매매금융자산')
64
+ d3, v3 = c103q.latest_value_pop2('매도가능금융자산')
65
+ d4, v4 = c103q.latest_value_pop2('만기보유금융자산')
78
66
  logger.debug(f'현금및예치금 : {d1}, {v1}')
79
67
  logger.debug(f'단기매매금융자산 : {d2}, {v2}')
80
68
  logger.debug(f'매도가능금융자산 : {d3}, {v3}')
81
69
  logger.debug(f'만기보유금융자산 : {d4}, {v4}')
82
70
 
83
- date = extract_valid_one(d1, d2, d3, d4)
71
+ date, *_ = set_data(d1, d2, d3, d4)
84
72
  계산된유동자산value = v1 + v2 + v3 + v4
85
73
 
86
74
  return date, 계산된유동자산value
87
75
 
88
76
 
89
- def calc유동부채(client, code: str) -> Tuple[str, float]:
77
+ def calc유동부채(code: str) -> Tuple[str, float]:
90
78
  """유효한 유동부채 계산
91
79
 
92
80
  일반적인 경우로 유동부채를 찾아서 반환한다.\n
@@ -94,29 +82,27 @@ def calc유동부채(client, code: str) -> Tuple[str, float]:
94
82
  Red와 Blue에서 사용한다.\n
95
83
  """
96
84
  logger.debug(f'In the calc유동부채... code:{code}')
97
- c103q = C103(client, code, 'c103재무상태표q')
85
+ c103q = C103(code, 'c103재무상태표q')
98
86
  try:
99
- debt_dict = c103q.find(title='유동부채')
100
- logger.debug(f'유동부채 : {debt_dict}')
101
- return c103q.sum_recent_4q('유동부채', nan_to_zero=True)
87
+ return c103q.sum_recent_4q('유동부채')
102
88
  except:
103
- # 금융관련업종...
104
- d1, v1 = c103q.latest_value('당기손익인식(지정)금융부채', nan_to_zero=True, allow_empty=True)
105
- d2, v2 = c103q.latest_value('당기손익-공정가치측정금융부채', nan_to_zero=True, allow_empty=True)
106
- d3, v3 = c103q.latest_value('매도파생결합증권', nan_to_zero=True, allow_empty=True)
107
- d4, v4 = c103q.latest_value('단기매매금융부채', nan_to_zero=True, allow_empty=True)
89
+ logger.warning(f"{code} - 유동부채가 없는 종목. 수동으로 계산합니다(금융관련업종일 가능성있음).")
90
+ d1, v1 = c103q.latest_value_pop2('당기손익인식(지정)금융부채')
91
+ d2, v2 = c103q.latest_value_pop2('당기손익-공정가치측정금융부채')
92
+ d3, v3 = c103q.latest_value_pop2('매도파생결합증권')
93
+ d4, v4 = c103q.latest_value_pop2('단기매매금융부채')
108
94
  logger.debug(f'당기손익인식(지정)금융부채 : {d1}, {v1}')
109
95
  logger.debug(f'당기손익-공정가치측정금융부채 : {d2}, {v2}')
110
96
  logger.debug(f'매도파생결합증권 : {d3}, {v3}')
111
97
  logger.debug(f'단기매매금융부채 : {d4}, {v4}')
112
98
 
113
- date = extract_valid_one(d1, d2, d3, d4)
99
+ date, *_ = set_data(d1, d2, d3, d4)
114
100
  계산된유동부채value = v1 + v2 + v3 + v4
115
101
 
116
102
  return date, 계산된유동부채value
117
103
 
118
104
 
119
- def calc비유동부채(client, code: str) -> Tuple[str, float]:
105
+ def calc비유동부채(code: str) -> Tuple[str, float]:
120
106
  """유효한 비유동부채 계산
121
107
 
122
108
  일반적인 경우로 비유동부채를 찾아서 반환한다.\n
@@ -124,46 +110,44 @@ def calc비유동부채(client, code: str) -> Tuple[str, float]:
124
110
  Red와 Blue에서 사용한다.\n
125
111
  """
126
112
  logger.debug(f'In the calc비유동부채... code:{code}')
127
- c103q = C103(client, code, 'c103재무상태표q')
113
+ c103q = C103(code, 'c103재무상태표q')
128
114
  try:
129
- debt_dict = c103q.find(title='비유동부채')
130
- logger.debug(f'비유동부채 : {debt_dict}')
131
- return c103q.sum_recent_4q('비유동부채', nan_to_zero=True)
115
+ return c103q.sum_recent_4q('비유동부채')
132
116
  except:
133
- # 금융관련업종...
117
+ logger.warning(f"{code} - 비유동부채가 없는 종목. 수동으로 계산합니다(금융관련업종일 가능성있음).")
134
118
  # 보험관련업종은 예수부채가 없는대신 보험계약부채가 있다...
135
- d1, v1 = c103q.latest_value('예수부채', nan_to_zero=True, allow_empty=True)
136
- d2, v2 = c103q.latest_value('보험계약부채(책임준비금)', nan_to_zero=True, allow_empty=True)
137
- d3, v3 = c103q.latest_value('차입부채', nan_to_zero=True, allow_empty=True)
138
- d4, v4 = c103q.latest_value('기타부채', nan_to_zero=True, allow_empty=True)
119
+ d1, v1 = c103q.latest_value_pop2('예수부채')
120
+ d2, v2 = c103q.latest_value_pop2('보험계약부채(책임준비금)')
121
+ d3, v3 = c103q.latest_value_pop2('차입부채')
122
+ d4, v4 = c103q.latest_value_pop2('기타부채')
139
123
  logger.debug(f'예수부채 : {d1}, {v1}')
140
124
  logger.debug(f'보험계약부채(책임준비금) : {d2}, {v2}')
141
125
  logger.debug(f'차입부채 : {d3}, {v3}')
142
126
  logger.debug(f'기타부채 : {d4}, {v4}')
143
127
 
144
- date = extract_valid_one(d1, d2, d3, d4)
128
+ date, *_ = set_data(d1, d2, d3, d4)
145
129
  계산된비유동부채value = v1 + v2 + v3 + v4
146
130
 
147
131
  return date, 계산된비유동부채value
148
132
 
149
133
 
150
- def calc유동비율(client, code: str, pop_count: int) -> Tuple[str, float]:
134
+ def calc유동비율(code: str, pop_count: int) -> Tuple[str, float]:
151
135
  """유동비율계산 - Blue에서 사용
152
136
 
153
137
  c104q에서 최근유동비율 찾아보고 유효하지 않거나 \n
154
138
  100이하인 경우에는수동으로 계산해서 다시 한번 평가해 본다.\n
155
139
  """
156
140
  logger.debug(f'In the calc유동비율... code:{code}')
157
- c104q = C104(client, code, 'c104q')
158
- 유동비율date, 유동비율value = c104q.latest_value('유동비율', pop_count=pop_count, allow_empty=True)
141
+ c104q = C104(code, 'c104q')
142
+ 유동비율date, 유동비율value = c104q.mymongo_c1034.latest_value('유동비율', pop_count=pop_count)
159
143
  logger.debug(f'{code} 유동비율 : {유동비율value}({유동비율date})')
160
144
 
161
145
  if math.isnan(유동비율value) or 유동비율value < 100:
162
146
  logger.warning('유동비율 is under 100 or nan..so we will recalculate..')
163
- 유동자산date, 유동자산value = calc유동자산(client, code)
164
- 유동부채date, 유동부채value = calc유동부채(client, code)
147
+ 유동자산date, 유동자산value = calc유동자산(code)
148
+ 유동부채date, 유동부채value = calc유동부채(code)
165
149
 
166
- c103q = C103(client, code, 'c103현금흐름표q')
150
+ c103q = C103(code, 'c103현금흐름표q')
167
151
  추정영업현금흐름date, 추정영업현금흐름value = c103q.sum_recent_4q('영업활동으로인한현금흐름')
168
152
  logger.debug(f'{code} 계산전 유동비율 : {유동비율value}({유동비율date})')
169
153
 
@@ -175,17 +159,36 @@ def calc유동비율(client, code: str, pop_count: int) -> Tuple[str, float]:
175
159
  계산된유동비율 = float('inf')
176
160
  finally:
177
161
  logger.debug(f'{code} 계산된 유동비율 : {계산된유동비율}')
178
- return extract_valid_one(유동자산date, 유동부채date, 추정영업현금흐름date), 계산된유동비율
162
+ date, *_ = set_data(유동자산date, 유동부채date, 추정영업현금흐름date)
163
+ return date, 계산된유동비율
179
164
  else:
180
165
  return 유동비율date, 유동비율value
181
166
 
182
167
 
183
- def findFCF(client, code: str) -> dict:
184
- """FCF 계산
168
+ """
169
+ FCF “Free Cash Flow”의 약자로, 한국어로는 “자유 현금 흐름”이라고 합니다. FCF는 기업이 운영 활동을 통해 창출한 현금 중에서 영업 및 자본적 지출을
170
+ 제외하고 남은 현금을 의미합니다. 이는 기업의 재무 건전성을 평가하는 중요한 지표로 사용됩니다. 자유 현금 흐름은 기업이 부채를 상환하고, 배당금을 지급하며,
171
+ 추가적인 투자를 할 수 있는 자금을 나타냅니다.
172
+
173
+ FCF의 중요성
185
174
 
186
- FCF = 영업활동현금흐름 - CAPEX\n
187
- 영업활동현금흐름에서 CAPEX 연도별로 빼주어 fcf 구하고 딕셔너리로 반환한다.\n
175
+ 1. 재무 건전성 평가: FCF 기업이 실제로 얼마나 많은 현금을 창출하고 있는지를 보여줍니다. 이는 기업의 재무 건전성을 평가하는 데 중요한 지표입니다.
176
+ 2. 투자 결정: 투자자들은 FCF통해 기업의 성장 가능성을 평가하고, 투자 결정을 내리는 데 참고합니다.
177
+ 3. 배당 지급 능력: FCF는 기업이 주주들에게 배당금을 지급할 수 있는 능력을 나타냅니다.
178
+ 4. 부채 상환: 기업은 FCF를 이용해 부채를 상환하고, 재무 구조를 개선할 수 있습니다.
188
179
 
180
+ CAPEX는 “Capital Expenditures”의 약자로, 한국어로는 “자본적 지출”이라고 합니다. CAPEX는 기업이 장기 자산을 구입하거나 유지하는 데 사용하는
181
+ 비용을 의미합니다. 이는 기업이 장기적인 성장을 위해 자산을 확장, 업그레이드 또는 유지하는 데 필요한 비용입니다. 이러한 자산에는 부동산, 건물, 기계,
182
+ 장비 등이 포함됩니다.
183
+
184
+ CAPEX가 거의 없거나 아예 없는 업종에서도 자유 현금 흐름(Free Cash Flow, FCF)을 계산할 수 있습니다. CAPEX가 없는 경우,
185
+ 계산식에서 CAPEX 부분을 0으로 처리하면 됩니다.
186
+ """
187
+
188
+
189
+ def findFCF(code: str) -> dict:
190
+ """
191
+ FCF 계산
189
192
  Returns:
190
193
  dict: 계산된 fcf 딕셔너리 또는 영업현금흐름 없는 경우 - {}
191
194
 
@@ -193,10 +196,10 @@ def findFCF(client, code: str) -> dict:
193
196
  CAPEX 가 없는 업종은 영업활동현금흐름을 그대로 사용한다.\n
194
197
 
195
198
  """
196
- c103y = C103(client, code, 'c103현금흐름표y')
197
- 영업활동현금흐름_dict = c103y.find(title='영업활동으로인한현금흐름', allow_empty=True)
199
+ c103y = C103(code, 'c103현금흐름표y')
200
+ _, 영업활동현금흐름_dict = c103y.find_without_yoy('영업활동으로인한현금흐름')
198
201
  c103y.page = 'c103재무상태표y'
199
- capex = c103y.find(title='*CAPEX', allow_empty=True)
202
+ _, capex = c103y.find_without_yoy('*CAPEX')
200
203
 
201
204
  logger.debug(f'영업활동현금흐름 {영업활동현금흐름_dict}')
202
205
  logger.debug(f'CAPEX {capex}')
@@ -206,6 +209,7 @@ def findFCF(client, code: str) -> dict:
206
209
 
207
210
  if len(capex) == 0:
208
211
  # CAPEX 가 없는 업종은 영업활동현금흐름을 그대로 사용한다.
212
+ logger.warning(f"{code} - CAPEX가 없는 업종으로 영업현금흐름을 그대로 사용합니다..")
209
213
  return 영업활동현금흐름_dict
210
214
 
211
215
  # 영업 활동으로 인한 현금 흐름에서 CAPEX 를 각 연도별로 빼주어 fcf 를 구하고 리턴값으로 fcf 딕셔너리를 반환한다.
@@ -223,8 +227,22 @@ def findFCF(client, code: str) -> dict:
223
227
  return dict(sorted(r_dict.items(), reverse=False))
224
228
 
225
229
 
226
- def findPFCF(client, code: str) -> dict:
227
- """Price to Free Cash Flow Ratio 계산
230
+ """
231
+ PFCF의 중요성
232
+ 1. 기업 가치 평가: PFCF는 기업이 창출하는 현금 흐름에 비해 주가가 적정한지 평가하는 데 사용됩니다. 낮은 PFCF는 주가가 상대적으로 저평가되었음을 나타낼
233
+ 수 있고, 높은 PFCF는 주가가 상대적으로 고평가되었음을 나타낼 수 있습니다.
234
+ 2. 투자 결정: 투자자들은 PFCF를 사용하여 현금 흐름 창출 능력 대비 주가가 매력적인지를 판단하고, 투자 결정을 내리는 데 참고합니다.
235
+ 3. 비교 분석: 같은 산업 내 다른 기업들과 비교하여, 어느 기업이 더 효율적으로 현금 흐름을 창출하는지를 평가할 수 있습니다.
236
+
237
+ PFCF의 한계
238
+
239
+ •산업 특성: PFCF는 산업마다 적정한 수준이 다를 수 있습니다. 예를 들어, 기술 산업과 제조 산업의 적정 PFCF는 다를 수 있습니다.
240
+ •일회성 항목: 특정 연도의 일회성 비용이나 수익이 FCF에 영향을 미칠 수 있으며, 이는 PFCF 계산에 왜곡을 가져올 수 있습니다.
241
+ """
242
+
243
+
244
+ def findPFCF(code: str) -> dict:
245
+ """Price to Free Cash Flow Ratio(주가 대비 자유 현금 흐름 비율)계산
228
246
 
229
247
  PFCF = 시가총액 / FCF
230
248
 
@@ -232,12 +250,12 @@ def findPFCF(client, code: str) -> dict:
232
250
  https://www.investopedia.com/terms/p/pricetofreecashflow.asp
233
251
  """
234
252
  # marketcap 계산 (fcf가 억 단위라 시가총액을 억으로 나눠서 단위를 맞춰 준다)
235
- marketcap억 = get_marketcap(client, code) / 100000000
253
+ marketcap억 = get_marketcap(code) / 100000000
236
254
  if math.isnan(marketcap억):
237
255
  return {}
238
256
 
239
257
  # pfcf 계산
240
- fcf_dict = findFCF(client, code)
258
+ fcf_dict = findFCF(code)
241
259
  logger.debug(f'fcf_dict : {fcf_dict}')
242
260
  pfcf_dict = {}
243
261
  for FCFdate, FCFvalue in fcf_dict.items():
@@ -249,9 +267,14 @@ def findPFCF(client, code: str) -> dict:
249
267
  return pfcf_dict
250
268
 
251
269
 
252
- def get_marketcap(client, code: str, nan_to_zero: bool = False) -> int:
253
- c101 = C101(client, code)
270
+ def get_marketcap(code: str) -> float:
271
+ """
272
+ 시가총액(원) 반환
273
+ :param code:
274
+ :return:
275
+ """
276
+ c101 = C101(code)
254
277
  try:
255
278
  return int(c101.get_recent()['시가총액'])
256
279
  except KeyError:
257
- return 0 if nan_to_zero else math.nan
280
+ return math.nan