3 minute read

단일회사 5개년치 재무제표 테이블 병합하기

OpenDartReader 라이브러리를 활용한 재무제표 분석

OpenDartReader/github

project_finance

전체코드 finstate.py/github

  • fstate_all_account: 단일회사의 재무제표를 분기별로 병합한 테이블

    columns_0 = [stock_name, stock_code, corp_code]
    (리스트의 각 원소 자료형: string)

    columns_1 = [sj_div, account_id, account_nm]
    (리스트의 각 원소 자료형: string)

    columns_2 = [thstrm_amount_2021_1, thstrm_amount_2021_2, thstrm_amount_2020_1, thstrm_amount_2020_2, …]
    (리스트의 각 원소 자료형: float32) ⇒ 최근 4개년치 분기별 금액

    병합(join) 기준 key = [“sj_div”, “account_id”, “account_nm”]

code


분기별 재무제표를 병합해서 DataFrame으로 return 해주는 함수
# 분기별 재무제표를 병합해서 DataFrame으로 return 해주는 함수 
def finstate_all_account(stock_name, years, quarters):
    for bsns_year in years:
        quarter = 1
        for reprt_code in quarters:
            # fstate 변수에 할당된 데이터가 없을 때(즉, 해당 연도 분기의 재무제표가 dart에 공시되어 있지 않은 경우) 예외처리
            try:
                fstate = dart.finstate_all(stock_name, bsns_year, reprt_code, fs_div="CFS")
                fstate = finstate_quarter(fstate).rename(columns={"thstrm_amount": f'thstrm_amount_{bsns_year}_{quarter}'})
                # stock_name, stock_code columns 삽입
                if dart.company(stock_name)["corp_cls"] == "Y":
                    stock_code = dart.company(stock_name)["stock_code"] + ".KS"
                elif dart.company(stock_name)["corp_cls"] == "K":
                    stock_code = dart.company(stock_name)["stock_code"] + ".KQ"
                fstate.insert(0, "stock_code", stock_code)
                fstate.insert(1, "stock_name", stock_name)
                # 계정과목 이름이 중복되는 행 삭제
                fstate = fstate.drop_duplicates(["sj_div", "account_id", "account_nm"], keep=False, ignore_index=True)
            except AttributeError:
                quarter += 1
                continue
            # 병합할 이전 분기 재무제표 dataframe이 없는경우 예외처리
            try:
                # 분기별 재무제표 병합
                if quarter == 1:
                    fstate_corp = fstate
                else:
                    fstate_corp = fstate_corp.merge(fstate, how="outer", on=["stock_name", "stock_code", "corp_code", "sj_div", "account_id", "account_nm"], suffixes=("", ""))
            except (ValueError, UnboundLocalError):
                fstate_corp = fstate
            # NULL 데이터를 0으로 바꿈
            fstate_corp = fstate_corp.fillna(0)

            if quarter == 4:
                # 4분기 발생 금액 columns 추가
                i = 0
                for s in fstate_corp["sj_div"]:
                    if s == "BS":
                        fstate_corp.loc[i,  f'thstrm_amount_{bsns_year}_{quarter}'] = fstate_corp.loc[i,  f'thstrm_amount_{bsns_year}_{quarter}']
                    else:
                        fstate_corp.loc[i,  f'thstrm_amount_{bsns_year}_{quarter}'] = fstate_corp.loc[i,  f'thstrm_amount_{bsns_year}_{quarter}'] - fstate_corp.loc[i,  f'thstrm_amount_{bsns_year}_{quarter-1}']
                    i += 1
            quarter += 1
        # 병합할 이전 연도 재무제표 dataframe이 없는경우 예외처리
        try:    
            # 연도별 재무제표 병합
            if bsns_year == years[0]:
                fstate_all_account = fstate_corp
            else:
                fstate_all_account = fstate_all_account.merge(fstate_corp, how="outer", on=["stock_name", "stock_code", "corp_code", "sj_div", "account_id", "account_nm"], suffixes=("", ""))
        except (ValueError, UnboundLocalError):
            fstate_all_account = fstate_corp
    # NULL 데이터를 0으로 바꿈
    fstate_all_account = fstate_all_account.fillna(0)
    # 엑셀파일로 저장
    fstate_all_account.to_excel(f"{stock_code}.xlsx")
    return fstate_all_account
stock_name = "삼성전자"
years = ["2021", "2020", "2019", "2018", "2017"]
quarters = ["11013", "11012", "11014", "11011"]
fstate_samsung = finstate_all_account(stock_name, years, quarters)
병합 이후 단일회사 5개년치 재무제표 테이블 (fstate_samsung)
stock_code stock_name corp_code sj_div account_id account_nm thstrm_amount_2021_1 thstrm_amount_2021_2 thstrm_amount_2020_1 thstrm_amount_2020_2 ... thstrm_amount_2019_3 thstrm_amount_2019_4 thstrm_amount_2018_1 thstrm_amount_2018_2 thstrm_amount_2018_3 thstrm_amount_2018_4 thstrm_amount_2017_1 thstrm_amount_2017_2 thstrm_amount_2017_3 thstrm_amount_2017_4
0 005930.KS 삼성전자 00126380 BS ifrs-full_CurrentAssets 유동자산 2.091554e+14 1.911185e+14 1.867397e+14 1.861369e+14 ... 1.860421e+14 1.813853e+14 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.0 0.0 0.000000e+00 0.000000e+00
1 005930.KS 삼성전자 00126380 BS ifrs-full_CashAndCashEquivalents 현금및현금성자산 4.103959e+13 3.068379e+13 2.791668e+13 3.610961e+13 ... 2.660499e+13 2.688600e+13 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.0 0.0 0.000000e+00 0.000000e+00
2 005930.KS 삼성전자 00126380 BS dart_ShortTermDepositsNotClassifiedAsCashEquiv... 단기금융상품 8.715927e+13 7.777703e+13 7.863802e+13 7.512761e+13 ... 6.947697e+13 7.625205e+13 4.602770e+13 4.871714e+13 5.868142e+13 6.589380e+13 0.0 0.0 4.128067e+13 4.944769e+13
3 005930.KS 삼성전자 00126380 BS -표준계정코드 미사용- 단기상각후원가금융자산 3.526888e+12 2.350399e+12 3.037379e+12 1.224565e+12 ... 4.021901e+12 3.914216e+12 3.733160e+12 3.896630e+12 3.446114e+12 2.703693e+12 0.0 0.0 0.000000e+00 0.000000e+00
4 005930.KS 삼성전자 00126380 BS ifrs-full_CurrentFinancialAssetsAtFairValueThr... 단기당기손익-공정가치금융자산 5.949500e+10 4.972000e+10 1.238759e+12 5.826410e+11 ... 1.842611e+12 1.727436e+12 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.0 0.0 0.000000e+00 0.000000e+00
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
270 005930.KS 삼성전자 00126380 CF dart_PurchaseOfAvailableForSaleFinancialAssets 매도가능금융자산의 취득 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 ... 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.0 0.0 1.447670e+11 -1.447670e+11
271 005930.KS 삼성전자 00126380 CF ifrs_IncreaseDecreaseInCashAndCashEquivalentsB... 환율변동효과 반영전 현금및현금성자산의 순증가(감소) 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 ... 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.0 0.0 -1.031843e+12 1.247801e+12
272 005930.KS 삼성전자 00126380 CF ifrs_IncreaseDecreaseInCashAndCashEquivalents 현금및현금성자산의 순증가(감소) 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 ... 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.0 0.0 -1.323216e+12 1.323216e+12
273 005930.KS 삼성전자 00126380 CF dart_CashAndCashEquivalentsAtBeginningOfPeriodCf 기초 현금및현금성자산 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 ... 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.0 0.0 3.211144e+13 -3.211144e+13
274 005930.KS 삼성전자 00126380 CF dart_CashAndCashEquivalentsAtEndOfPeriodCf 기말 현금및현금성자산 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 ... 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.0 0.0 3.078823e+13 -3.078823e+13

275 rows × 24 columns

병합 이후 문제점

각 분기별 재무제표에서 같은 계정과목에 대해서
(“account_id”, “account_nm”)이 다르게 명시되어있는 경우가 많다.

예를들면 “지배기업 소유주에 귀속되는 당기순이익” 계정과목에 대해서
(“ifrs_ProfitLossAttributableToOwnersOfParent”, “지배기업 소유주 지분”)도 존재하고,
(“ifrs-full_ProfitLossAttributableToOwnersOfParent”, “지배기업 귀속 당기순이익”)도 존재한다.

즉, 회사별 재무제표 table에서 일반키 지정이 불가능한 상황이 된다.

이를 해결하기 위해 병합한 회사별 재무제표 table 자체를 수정하기 보단
계정과목의 “account_id”를 기준으로 row데이터를 추출하여
새로운 계정과목별 table을 만들어보기로 했다.