본문 바로가기
AyoProject/Ayotera-Trade

[AT] 26. 우량주 종목 자동 예측 및 선정 (3-2)

by 청양호박이 2021. 1. 15.

바로 전 시간에는 우량주 종목 선정을 위한 기반 데이터를 전자공시시스템에서 제공하는 OPEN DART를 통해서 재무제표 정보를 받아와서 DB Table에 적재하는 로직을 구현하였습니다.

 

이번시간에는 우량주 종목으로 선정하기 위한 로직을 정의하고, 모아지는 데이터에 대해서 해당 우량주를 추출해 보도록 하겠습니다.

 

  • 우량주 종목 선정을 위한 기반 데이터 수집 방안 (전자공시시스템 활용) - 1개 종목기준
  • 정리된 데이터 수집 방안에 대해서 코스피, 코스닥 전체 종목에 대한 데이터를 DBMS에 적재
  • 우량주 종목 선정 로직을 적용하여 대상 종목 추출
  • 추출된 우량주 종목에 대해서 저평가 종목 추출
  • 추출된 종목에 대해서 실험실 진행

 

자 그렇다면, 우리가 총 7가지 데이터에 대해서, DB Table에 적재를 하고 있습니다. 다시 리마인드를 하자면... 아래의 항목들 입니다.

이름 필드명
종목 stocks_id
년도 bsns_year
분기 bsns_quarter
매출액 revenue
매출액(누적) revenue_add
영업이익 operating_income
영업이익(누적) operating_income_add
영업활동 현금흐름 operating_cashflow
투자활동 현금흐름 investing_cashflow
재무활동 현금흐름 financing_cashflow

종목, 년도, 분기는 구분을 하기위한 구분자이고... 나머지 7개의 데이터가 그것인데, 그렇다면 이 항목들을 어떻게 활용할지 차례차례 기술해 보겠습니다. 

 

 

1. 손익계산서 항목


재무제표 데이터 중 손익계산서를 통해서 구할 수 있는 데이터는 매출액, 영업이익 입니다. 이 데이터를 가지고 해당분기에 대한 결과, 누적에 대한 결과를 가지고 우량주 판단을 위한 1차 데이터를 생성할 것 입니다.

 

우선 매출이 높다는 말은, 해당 종목의 기업은 자신의 제품/서비스 등을 지속적으로 공급/수행을 하고 있다는 말 입니다. 그런 상황에서 영업이익이 높다는 말은, 매출의 활동을 하면서 기업이 이익이 남는다는 것으로 판단할 수 있습니다. 이렇게 매출액과 영업이익의 비율을 가지고 1차적으로 기업을 판단 할 수 있습니다.

 

이를 영업이익율이라고 하는데... 매출액 / 영업이익 (%) 으로 계산할 수 있습니다. 이 수치를 통해서 해당 기업이 단적으로 현재 우량한지 아닌지를 판단할 수 있는 것 입니다.

 

그렇다면, 과연 영업이익율이 도데체 얼마여야 우량하다고 말할 수 있을까요?? 이것은 시뮬레이션을 통해서 판단을 해야 합니다. 물론, 기타 외부적인 요인도 많을테고, 영업이익율만 보고... 우량성을 판단하기란 쉽지 않습니다. 영업이익율이 낮더라도 실제로는 우량한 기업일 수도 있을테니까요.

 

하지만 모든 종목을 내가 다 분석하면서 판단하기란 힘들고 시스템을 통해서 우량주를 보겠다는 것은... 어느정도 일반화하는 알고리즘을 가지고 적용을 해서 특수한 경우는 감내하겠다는 말과 다르지 않다고 생각합니다. 그래서 우선 정의는 아래와 같이 하겠습니다.

 

"영업이익율이 10%를 넘는 기업은 우량주의 조건 중 1가지로 포함한다."

 

이것을 적용하는 방법은 간단합니다. 우선 코드를 먼저보고 자세히 살펴보겠습니다.

 

[소스코드]

# 전체 종목에 대한 OpenDart의 재무재표 데이터 가져오기 (년도, 분기 별)
sql_dml = '''
    SELECT 
        A.stocks_id,
        A.stocks_type,
        A.stocks_name,
        B.bsns_year,
        B.bsns_quarter,
        B.revenue,
        B.revenue_add,
        B.operating_income,
        B.operating_income_add,
        B.operating_cashflow,
        B.investing_cashflow,
        B.financing_cashflow
    FROM stocks_info AS A
    LEFT JOIN fin_stat_info AS B
    ON A.stocks_id = B.stocks_id
    WHERE B.bsns_year = %s AND B.bsns_quarter = %s
'''

bsns_year = '2015'
bsns_quarter = '4'
sql_data = (bsns_year, bsns_quarter)

mariadb_cur.execute(sql_dml, sql_data)
sList = mariadb_cur.fetchall()

# 결과 확인
print("총 데이터 수 : ", len(sList))
print(sList[0])

# 우량주체크 로직 적용
superior_stocks = []
for i in sList:
    temp = []

    print(i)
    # revenue나 operation_income에 값이 없으면 삭제 다음 종목으로 이동
    if i[5] == '' or i[5] == '0' or i[7] == '' or i[7] == '0':
        continue

    for j in i:
        temp.append(j)
    if i[4] == '4':
        print("this is end")
        operating_income_ratio = 0
        operating_income_ratio_add = (int(i[7]) / int(i[5])) * 100
        print("영업이익율 : ", operating_income_ratio)
        print("영업이익율(누적) : ", operating_income_ratio_add)
    else:
        print("this is not end")
        operating_income_ratio = (int(i[7]) / int(i[5])) * 100
        operating_income_ratio_add = (int(i[8]) / int(i[6])) * 100
        print("영업이익율 : ",operating_income_ratio)
        print("영업이익율(누적) : ",operating_income_ratio_add)
    temp.append(operating_income_ratio)
    temp.append(operating_income_ratio_add)
    print(temp)


    # 영업이익율 10%이상 저장
    if operating_income_ratio >= 10 or operating_income_ratio_add >= 10:
        print(temp)
        superior_stocks.append(temp)

print(superior_stocks)
print(len(superior_stocks))

매출액과 영업이익이 null이거나 0인 값들이 있어서 우선 전처리를 해줍니다. 그리고 나머지는 비율을 구하는 로직이기 때문에 코드로 이해하시면 될 듯 합니다.

 

그리고 정의된 영업이익율이 10%이상인 종목에 대해서는 임시저장소인 superior_stocks에 저장해 줍니다. 그렇다면 2015년 4분기에 결산된 재무재표중 영업이익율이 해당되는 종목은 아래와 같습니다.

 

[결과]

[['900120', '10', '씨케이에이치', '2015', '4', '1825725000', '', '579012000', '', '527550000', '-170119000', '-10246000', 0,
  31.71408618494023],
 ['900110', '10', '이스트아시아홀딩스', '2015', '4', '662148883', '', '89874095', '', '-51967203', '30610897', '104042595', 0,
  13.573094708369387],
 ['109740', '10', '디에스케이', '2015', '4', '56461731276', '', '10491514134', '', '1045365125', '-1055540565', '427506750',
  0, 18.5816373265543],
 ['051900', '0', 'LG생활건강', '2015', '4', '5328492268366', '', '684095164351', '', '637804646876', '-347006566398',
  '-231512593429', 0, 12.838437777461204],
 ['010130', '0', '고려아연', '2015', '4', '4771442958357', '', '672218933053', '', '944860095270', '-650784624251',
  '-236269636445', 0, 14.088378272984157],
 ['010780', '0', '아이에스동서', '2015', '4', '945846998061', '', '114507234731', '', '-180769156556', '-64310533039',
  '349186889510', 0, 12.106316874266291],
 ['047810', '0', '한국항공우주', '2015', '4', '3039737000000', '', '379703000000', '', '59852000000', '-123235000000',
  '61341000000', 0, 12.49131092591234],
 ['003550', '0', 'LG', '2015', '4', '5250038000000', '', '1137986000000', '', '886292000000', '-368266000000',
  '-145194000000', 0, 21.675766918258496],
 ['130580', '10', '나이스디앤비', '2015', '4', '25675100676', '', '4943228840', '', '5256602640', '-451210120', '-1093400000',
  0, 19.253006647879367],
 ['137940', '10', '넥스트아이', '2015', '4', '26565766452', '', '2741035455', '', '3539237541', '-1096649828', '-1802780360',
  0, 10.31792348228538],
  
  .....
  .....
  .....

 

 

2. 현금흐름표 항목


다시 기존에 살짝 의미만 알아 봤었던, 영업활동 현금흐름 / 투자활동 현금흐름 / 재무활동 현금흐름에 대해서 각 수치에 대한 더 세부적인 내용을 포함해서 생각해 보겠습니다. 

 

[영업활동 현금흐름]

 

회사의 상품을 파는 과정에서 생기는 현금에 대한 흐름정의

 

라고 지난 시간에 정의를 알아봤습니다. 그렇다면 DB에 저장된 해당 항목에 대한 수치는 어떤것을 의미할까요?? 영업활동 현금흐름이 (+)값을 가지게 되면, 이는 해당 기업이 자신의 상품(서비스)를 팔수록 현금이 남는다는 것을 의미합니다. 그리고, (-)값을 가지게 되면, 이는 그 반대로 팔수록 현금이 줄어든 다는 것을 의미하겠죠. 따라서 우리는 (+)수치를 가지는 기업이 우량한 기업이라고 유추할 수 있습니다.

 

 

[투자활동 현금흐름]

 

회사의 기반시설, 기술개발 등에 대한 투자 과정에서 생기는 현금에 대한 흐름정의

 

라고 지난 시간에 정의를 알아봤습니다. 그렇다면 DB에 저장된 해당 항목에 대한 수치는 어떤것을 의미할까요?? 투자활동 현금흐름이 (+)값을 가지게 되면, 이는 해당 기업이 생산설비 / 기술설비 등 다양한 투자자산에 대한 매각을 의미합니다. 결국 팔아버렸다는 것이죠. 따라서, 무언가 장기적으로 봤을때 성장가능성이 적어진다고 유추할 수 있습니다. 그리고, (-)값을 가지게 되면, 이는 그 반대로 다양한 투자를 수행했다고 볼 수 있습니다. 모든 조건에서는 그렇지 않겠지만 현재의 혹은 미래의 발전을 위해서 이익을 일부 투자로 전환하고 있으며, 점점 더 발전을 위한 준비를 하고있는 기업이라고 유추할 수 있습니다.

 

 

[재무활동 현금흐름]

 

회사가 금융기관에서 돈을 빌리고 갚는 등에 대한 현금 흐름정의

 

라고 지난 시간에 정의를 알아봤습니다. 그렇다면 DB에 저장된 해당 항목에 대한 수치는 어떤것을 의미할까요?? 재무활동 현금흐름이 (+)값을 가지게 되면, 이는 금융적으로 뭔가 외부에서 가져왔다... 즉 금융권에서 돈을 빌렸다 라고 추정할 수 있습니다.  그리고, (-)값을 가지게 되면, 이는 그 반대로 기존에 빌렸던 돈을 갚았다 라고 볼 수 있습니다. 해당 항목도 동일하게 모든 조건에서는 그렇지 않겠지만 (-)값을 가지는 기업이 우량한 기억이라고 유추할 수 있습니다.

 

자... 이렇게 3가지 현금흐름 지표에 대해서 의미를 알아보았습니다. 그렇다면, 각 조건별로 매핑이 가능해집니다. 경우의 수는 총 8가지가 되겠지만... 의미가 있는항목은 몇가지 되지 않습니다.

판단 영업활동 투자활동 재무활동 점수
우량주 + - - 10
| + - + 5
| + + - -
| + + + -
| - - - -
| - - + -
- + - -
비 우량주 - + + 0

오랜기간 고민해 봤는데... 모든 조건에 대해서 점수를 부여해야하나 라는 생각이 들곤합니다. 그래서 저는 아래와 같이 정의를 하여 구현하였습니다.

 

우량기업은 팔면 이익이 생겨야하고,

그 일부분을 미래를 위해 지속적인 투자를 하며,

부채가 있더라도 갚도록 노력하는 기업이다.

 

하지만, 부채에 대해서는 약간 회의적이라서 재무활동에 대해서는 나머지 경우가 조건에 부합할 경우, (+)인 경우에 한해서 점수를 반영하기로 하였습니다.

 

자 그렇다면 해당 소스코드를 살펴보겠습니다. 역시나 구현하는데는 어렵지 않아요~

 

[소스코드]

    # cashflow에 값이 없으면 삭제 다음 종목으로 이동
    if i[9] == '' or i[9] == '0' or i[10] == '' or i[10] == '0' or i[11] == '' or i[11] == '0':
        continue
        
    # 현금흐름표 기준 점수를 산정하여 필드 추가
    if int(i[9]) > 0 and int(i[10]) < 0 and int(i[11]) < 0:
        flow_point = 10
    elif int(i[9]) > 0 and int(i[10]) < 0 and int(i[11]) > 0:
        flow_point = 5
    else:
        flow_point = 0
    temp.append(flow_point)
    print(temp)


    # 우량주 추출 로직 적용
    if operating_income_ratio >= 10 or operating_income_ratio_add >= 10:
        if flow_point >= 10:
            superior_stocks.append(temp)

[결과]

[['900120', '10', '씨케이에이치', '2015', '4', '1825725000', '', '579012000', '', '527550000', '-170119000', '-10246000', 0,
  31.71408618494023, 10],
 ['051900', '0', 'LG생활건강', '2015', '4', '5328492268366', '', '684095164351', '', '637804646876', '-347006566398',
  '-231512593429', 0, 12.838437777461204, 10],
 ['010130', '0', '고려아연', '2015', '4', '4771442958357', '', '672218933053', '', '944860095270', '-650784624251',
  '-236269636445', 0, 14.088378272984157, 10],
 ['003550', '0', 'LG', '2015', '4', '5250038000000', '', '1137986000000', '', '886292000000', '-368266000000',
  '-145194000000', 0, 21.675766918258496, 10],
 ['130580', '10', '나이스디앤비', '2015', '4', '25675100676', '', '4943228840', '', '5256602640', '-451210120', '-1093400000',
  0, 19.253006647879367, 10],
 ['137940', '10', '넥스트아이', '2015', '4', '26565766452', '', '2741035455', '', '3539237541', '-1096649828', '-1802780360',
  0, 10.31792348228538, 10],
 ['000050', '0', '경방', '2015', '4', '357628146446', '', '38961511221', '', '39920579766', '-36713624695', '-4572001673',
  0, 10.894419694922695, 10],
 ['126880', '10', '제이엔케이히터', '2015', '4', '937000000', '', '9181695673', '', '21927521549', '-11074625968',
  '-4586661600', 0, 979.9034869797225, 10],
  
  .....
  .....
  .....

 

 

3. 적용결과


그럼 지금까지 알아본 항목들에 대해서 모두 적용된 결과를 살펴보도록 하겠습니다. 

 

"영업이익율이 10%를 넘는 기업 중에서 현금흐름표가 (+) (-) (-) 인 기업"

 

위의 조건을 만족하는 기업을 찾아내면 되는 것 입니다. 돌려보니 꽤많은 기업이 해당됩니다. 

 

Result : 131

무려 131개에 해당하는 기업이 적용되네요... 그럼 다음시간에 이어서 진행해 보겠습니다.

 

- Ayotera Lab -

댓글