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.
- analyser_hj3415/.DS_Store +0 -0
- analyser_hj3415/analysers/eval.py +289 -0
- analyser_hj3415/{report.py → analysers/report.py} +23 -59
- analyser_hj3415/{score.py → analysers/score.py} +57 -61
- analyser_hj3415/myredis.py +175 -0
- analyser_hj3415/{db/evaltools.py → tools.py} +102 -79
- analyser_hj3415/trash.py +210 -0
- {analyser_hj3415-2.0.2.dist-info → analyser_hj3415-2.2.0.dist-info}/METADATA +5 -9
- analyser_hj3415-2.2.0.dist-info/RECORD +15 -0
- analyser_hj3415/db/.DS_Store +0 -0
- analyser_hj3415/db/chk_db.py +0 -240
- analyser_hj3415/db/mongo.py +0 -934
- analyser_hj3415/eval.py +0 -382
- analyser_hj3415-2.0.2.dist-info/RECORD +0 -16
- /analyser_hj3415/{db/__init__.py → run.py} +0 -0
- {analyser_hj3415-2.0.2.dist-info → analyser_hj3415-2.2.0.dist-info}/LICENSE +0 -0
- {analyser_hj3415-2.0.2.dist-info → analyser_hj3415-2.2.0.dist-info}/WHEEL +0 -0
- {analyser_hj3415-2.0.2.dist-info → analyser_hj3415-2.2.0.dist-info}/entry_points.txt +0 -0
@@ -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
|
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
|
15
|
+
def set_data(*args) -> list:
|
17
16
|
"""
|
18
|
-
|
19
|
-
|
17
|
+
비유효한 내용 제거(None,nan)하고 중복된 항목 제거하고 리스트로 반환한다.
|
18
|
+
:param args:
|
19
|
+
:return:
|
20
20
|
"""
|
21
|
-
|
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당기순이익(
|
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(
|
32
|
+
c103q = C103(code, 'c103재무상태표q')
|
42
33
|
try:
|
43
|
-
|
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('당기순이익'
|
38
|
+
최근당기순이익date, 최근당기순이익value = c103q.sum_recent_4q('당기순이익')
|
50
39
|
c103q.page = 'c103재무상태표q'
|
51
|
-
비지배당기순이익date, 비지배당기순이익value= c103q.
|
40
|
+
비지배당기순이익date, 비지배당기순이익value = c103q.latest_value_pop2('*(비지배)당기순이익')
|
52
41
|
|
53
|
-
|
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유동자산(
|
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(
|
57
|
+
c103q = C103(code, 'c103재무상태표q')
|
68
58
|
try:
|
69
|
-
|
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.
|
75
|
-
d2, v2 = c103q.
|
76
|
-
d3, v3 = c103q.
|
77
|
-
d4, v4 = c103q.
|
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 =
|
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유동부채(
|
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(
|
85
|
+
c103q = C103(code, 'c103재무상태표q')
|
98
86
|
try:
|
99
|
-
|
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.
|
105
|
-
d2, v2 = c103q.
|
106
|
-
d3, v3 = c103q.
|
107
|
-
d4, v4 = c103q.
|
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 =
|
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비유동부채(
|
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(
|
113
|
+
c103q = C103(code, 'c103재무상태표q')
|
128
114
|
try:
|
129
|
-
|
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.
|
136
|
-
d2, v2 = c103q.
|
137
|
-
d3, v3 = c103q.
|
138
|
-
d4, v4 = c103q.
|
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 =
|
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유동비율(
|
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(
|
158
|
-
유동비율date, 유동비율value = c104q.latest_value('유동비율', pop_count=pop_count
|
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유동자산(
|
164
|
-
유동부채date, 유동부채value = calc유동부채(
|
147
|
+
유동자산date, 유동자산value = calc유동자산(code)
|
148
|
+
유동부채date, 유동부채value = calc유동부채(code)
|
165
149
|
|
166
|
-
c103q = C103(
|
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
|
-
|
162
|
+
date, *_ = set_data(유동자산date, 유동부채date, 추정영업현금흐름date)
|
163
|
+
return date, 계산된유동비율
|
179
164
|
else:
|
180
165
|
return 유동비율date, 유동비율value
|
181
166
|
|
182
167
|
|
183
|
-
|
184
|
-
|
168
|
+
"""
|
169
|
+
FCF는 “Free Cash Flow”의 약자로, 한국어로는 “자유 현금 흐름”이라고 합니다. FCF는 기업이 운영 활동을 통해 창출한 현금 중에서 영업 및 자본적 지출을
|
170
|
+
제외하고 남은 현금을 의미합니다. 이는 기업의 재무 건전성을 평가하는 중요한 지표로 사용됩니다. 자유 현금 흐름은 기업이 부채를 상환하고, 배당금을 지급하며,
|
171
|
+
추가적인 투자를 할 수 있는 자금을 나타냅니다.
|
172
|
+
|
173
|
+
FCF의 중요성
|
185
174
|
|
186
|
-
|
187
|
-
|
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(
|
197
|
-
영업활동현금흐름_dict = c103y.
|
199
|
+
c103y = C103(code, 'c103현금흐름표y')
|
200
|
+
_, 영업활동현금흐름_dict = c103y.find_without_yoy('영업활동으로인한현금흐름')
|
198
201
|
c103y.page = 'c103재무상태표y'
|
199
|
-
capex = c103y.
|
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
|
-
|
227
|
-
|
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(
|
253
|
+
marketcap억 = get_marketcap(code) / 100000000
|
236
254
|
if math.isnan(marketcap억):
|
237
255
|
return {}
|
238
256
|
|
239
257
|
# pfcf 계산
|
240
|
-
fcf_dict = findFCF(
|
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(
|
253
|
-
|
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
|
280
|
+
return math.nan
|