본문 바로가기

코딩분석활용

무상증자 결정 공시한 회사의 주가는 어떻게 변동할까(파이썬)

반응형

전자공시 Dart API를 이용해서 무상증자 결정 공시를 실시한 회사의 주가가 어떻게 변하는지 확인해보겠습니다.

무상증자 결정 공시 접수일자에 주식을 산후 당일 매도, 1개월 후 매도, 3개월 후 매도를 했을때의 수익률을 알아보고 

어느 시점에 매도 했을때의 수익률이 가장 높았는지에 대해 확인해보겠습니다.

 

2016년 1월~2021년 12월 기간에 대한 결과 Summary 입니다.

 

count는 해당 기간의 무상증자 결정 공시 개수로 328개로 집계됩니다.

 

mean은 328개의 회사에 대한 주가 변동 평균값으로

   공시접수일다음날변동량 : 공시접수일 다음날의 시작가~종가 변동량

   공시접수후약한달후변동량 : 공시접수일 한달후의 시작가~종가 변동량

   공시접수후약3달후변동량 : 공시접수일 3달후의 시작가~종가 변동량

의 의미로 다음날에는 0.000519%로 거의 변동이 없었고, 한달후에는 5.09%로 평균주가가 상승했습니다.

3달 후에는  -1.37%로 오히려 평균 주가가 하락했습니다.

 

 

min은 최대하락한 주식의 주가, max는 최대 상승한 주식의 주가인데

한 달후에 -73%의 주식과 158%의 주식이 확인됩니다.

 

50%는 중위값의 평균주가를 나타내는데 총 328개의 주식 중에서 164~165번째의 주가의 평균이 되겠습니다.

 

평균, 최대, 최소, 중위값을 그래프로 확인해보겠습니다.

 

평균값과 중위값이 한 달째의 주가는 상승했고 3달에서 주가가 하락했는데요.

공시 접수일 후 한 달째의 주가가 가장 높을까요.

공시 접수일자 기준으로 시간이 경과했을때 주가 변동의 특징이 있는지 확인해보겠습니다.

 

평균 주가는 공시 한 달후 정도가 되었을때 가장 높았는데 거의 6%정도 상승한 것을 알수있습니다.

 

최대값, 최소값 변동도 확인해볼까요

최대값은 120영업일(약 5~6개월) 정도되니 400% 상승한 주식이 있는것도 확인이 되는데,

반대로 최소값은 -90%정도된 주식이 있는데 기간이 길어질수록 변동성이 커집니다.

경과에 따른 평균주가가 년도별로는 차이가 있을까요. 보도록 하겠습니다.

 

공시 일자 한달이내(22영업일)의 데이터는 평균 주가가 상승하는 모습이 보이고,

한달 이내에 단기 고점이 있는 것을 알 수 있습니다.

한달 이후는 년도별로 다른 분포를 보이고 있습니다.

 

마지막으로 공시접수일의 주가 변동량을 보도록 하겠습니다.

당일의 평균 주가가 5.4% 상승했네요.

공시 접수일 3달후의 평균 주가가 5.09% 였으니 당일의 주가의 변동폭이 크다는 것을 알 수있습니다.

 

 

아래에는 파이썬으로 확인한 코드들을 남겨드립니다.

관심있으신분들은 확인 및 수정해보셔도 좋을것 같습니다.

 

블로그내 참고할만한 포스팅입니다.

https://yenpa.tistory.com/28

 

[전자공시 Dart API] 무상증자 결정 공시 낸 회사의 주가 정보 확인

전자공시 Dart API의 주요사항보고서 개발가이드 > 공시정보 > 공시검색 데이터에서 무상증자 결정 공시정보를 가져와 주가 정보랑 비교해 보도록 하겠습니다. 본인의 인증키(API Key)가 필요하니

yenpa.tistory.com

 

 

전체 데이터를 가져오는 코드입니다.

crtfc_key는 본인의 데이터가 필요합니다.

import requests
import pandas as pd
from IPython.display import display
import warnings
import matplotlib.pyplot as plt
import FinanceDataReader as fdr
import numpy as np
warnings.filterwarnings("ignore")
plt.rc('font', family='NanumGothic') 

crtfc_key='YOUR_APIKEY'

#===========================================================================================
#공시정보 > 공시검색 > 주요사항보고서(무상증자결정) 리스트가져오기
print('무상증자결정 리스트가져오기')

startyear=2016
endyear=2022

results_all=pd.DataFrame()

years=list(range(startyear,endyear))
monthdays=[]
monthdays.append({'startdate' : '0101', 'enddate' : '0331'})
monthdays.append({'startdate' : '0401', 'enddate' : '0630'})
monthdays.append({'startdate' : '0701', 'enddate' : '0930'})
monthdays.append({'startdate' : '1001', 'enddate' : '1231'})

for year in years:
    for monthday in monthdays:
        print('yearmonth : ' + str(year) + monthday['startdate'])
        page_no=1
        page_count=100
        bgn_de=str(year) + monthday['startdate']
        end_de=str(year) + monthday['enddate']
        pblntf_detail_ty='B001'       

        keyword='주요사항보고서(무상증자결정)'

        while(True):
            url = 'https://opendart.fss.or.kr/api/list.json'
            params = {
                'crtfc_key': crtfc_key,
                'page_no' : str(page_no),
                'page_count' : str(page_count),
                'bgn_de' : bgn_de,
                'end_de' : end_de,
                'pblntf_detail_ty' : pblntf_detail_ty,
            }

            #결과를 json형태로 저장
            results = requests.get(url, params=params).json()
            #결과중 실제 공시정보가 있는부분만 DataFrame으로 저장
            results_df = pd.DataFrame(results['list'])
            #하나의 DataFrame으로 만듬
            results_all = pd.concat([results_all,results_df])

            total_page=results['total_page']

            # total_page와 page_no이 같으면 while문 종료
            if page_no==total_page:
                break

            page_no=page_no+1
            
    
dflist = results_all.loc[(results_all['report_nm']==keyword) & 
                     ((results_all['corp_cls']=='K') | (results_all['corp_cls']=='Y'))]
dflist['rcept_date'] = pd.to_datetime(dflist['rcept_dt'], format='%Y%m%d')
dflist['rcept_year'] = dflist['rcept_date'].dt.strftime('%Y')

dflist=dflist.set_index('rcept_no')


#===========================================================================================
# 주요사항보고서 주요정보 > 무상증자 결정 상세데이터 확인
print('무상증자결정 상세데이터')

detail = pd.DataFrame()
exec_check = [] #회사별 중복실행 방지
for i, r in dflist.iterrows():
    #주요사항보고서 무상증가결정 상세 요청인자
    crtfc_key=crtfc_key
    corp_code=r['corp_code']
    bgn_de=bgn_de
    end_de=end_de

    if corp_code in exec_check:
        continue

    exec_check.append(corp_code)

    url = 'https://opendart.fss.or.kr/api/fricDecsn.json'
    params = {
        'crtfc_key': crtfc_key,
        'corp_code' : corp_code,
        'bgn_de' : str(startyear)+'0101',
        'end_de' : str(endyear)+'1231',
    }

    #결과를 json형태로 저장
    results = requests.get(url, params=params).json()

    if results['status']!='000':
        continue    
    
    #결과중 실제 공시정보가 있는부분만 DataFrame으로 저장
    results_df_detail = pd.DataFrame(results['list'])
    #하나의 DataFrame으로 만듬
    detail = pd.concat([detail,results_df_detail])

# 필요한 column만 따로 저장
detail=detail[['rcept_no','nstk_ostk_cnt','bfic_tisstk_ostk',
         'nstk_ascnt_ps_ostk']]
#report no를 index로
detail=detail.set_index('rcept_no')

#===========================================================================================
#dflist detail 병합
df_all = pd.concat([dflist,detail], axis=1, join='inner')

cols=['nstk_ostk_cnt','bfic_tisstk_ostk', 'nstk_ascnt_ps_ostk']

#object -> int로 변환하기 위한 전처리 및 변환
for col in cols:
    df_all[col] = df_all[col].str.replace(',','').replace('-','0').replace('','0')  
    
df_all['nstk_ostk_cnt']=df_all['nstk_ostk_cnt'].astype('int64')
df_all['bfic_tisstk_ostk']=df_all['bfic_tisstk_ostk'].astype('int64')
df_all['nstk_ascnt_ps_ostk']=df_all['nstk_ascnt_ps_ostk'].astype('float64')

df_all['rcept_date'] = pd.to_datetime(df_all['rcept_dt'], format='%Y%m%d')



#===========================================================================================
#주가데이터 검색, 공시 접수일자주가와 공시 접수일자 + 22일후, +66일후의 주가와 경과일별 주가를 저장
print('주가데이터 검색')

startdate=str(startyear) + '-01-01'
enddate=str(endyear+1) + '-12-31'

stock_day_all = pd.DataFrame() # 회사별 공시날 주가
stock_df_all = pd.DataFrame() # 회사별 공시다음날, 1달후, 3달후의 변동량을 보기위한 데이터
stock_change_all = pd.DataFrame() # 회사별 1일~6개월의 매일의 주가 변동량을 보기위한 데이터
for i, r in df_all.iterrows():    
    rcept_no=i
    stock_code=r['stock_code']
    rcept_date=r['rcept_date']
    
    stock=fdr.DataReader(stock_code,startdate)
    if stock.shape[0] < 23:
        continue
    elif stock.shape[0] < 67:
        continue
    elif stock.shape[0] < 133:
        continue
    
    
    stock_rcept_dt=stock.loc[stock.index==rcept_date,:]
    
    # 공시접수일 당일 휴장일 회사는 skip
    if stock_rcept_dt.shape[0] == 0:
        continue
        
    #rcept_dt 공시접수일자 기준 다음날주가
    stock_day=stock_rcept_dt.copy()
    stock_day['rcept_no']=rcept_no
    stock_day['Change']=stock_rcept_dt['Change']*100    
    stock_day=stock_day.reset_index().set_index('rcept_no')
    stock_day=stock_day[['Close','Change']].rename(columns={'Change':'Change_rcept_dt','Close':'Close_rcept_dt'})
    stock_day_all=pd.concat([stock_day_all,stock_day])
    
    #rcept_dt 공시접수일자 기준 다음날주가
    stock_rcept_dt['rcept_no']=rcept_no
    #stock_rcept_dt['Change']=stock_rcept_dt['Change']*100    
    stock_rcept_dt['Change']=stock.loc[stock.index>rcept_date,'Change'].iloc[1]
    stock_rcept_dt=stock_rcept_dt.reset_index().set_index('rcept_no')
    stock_rcept_dt=stock_rcept_dt[['Close','Change']].rename(columns={'Change':'Change_rcept_dt','Close':'Close_rcept_dt'})
    
    #rcept_dt 공시접수일자 기준 22일후(대략한달)의 주가와 접수일자의 주가와 계산후 저장
    stock_after=stock.loc[stock.index>rcept_date,'Close'].iloc[0:22]
    change_after22=stock_after.iloc[-1]/stock_after.iloc[0]-1
    stock_after22=stock.loc[stock.index>rcept_date,:].iloc[[22],:]
    stock_after22['rcept_no']=rcept_no
    stock_after22['Change']=change_after22*100   
    stock_after22=stock_after22.reset_index().set_index('rcept_no')
    stock_after22=stock_after22[['Close','Change']].rename(columns={'Change':'Change_after22','Close':'Close_after22'})
    
    #rcept_dt 공시접수일자 기준 66일후(대략3달)의 주가와 접수일자의 주가와 계산후 저장
    stock_after=stock.loc[stock.index>rcept_date,'Close'].iloc[0:66]
    change_after66=stock_after.iloc[-1]/stock_after.iloc[0]-1
    stock_after66=stock.loc[stock.index>rcept_date,:].iloc[[66],:]
    stock_after66['rcept_no']=rcept_no
    stock_after66['Change']=change_after66*100   
    stock_after66=stock_after66.reset_index().set_index('rcept_no')
    stock_after66=stock_after66[['Close','Change']].rename(columns={'Change':'Change_after66','Close':'Close_after66'})
    
    stock_df=pd.concat([stock_rcept_dt,stock_after22],axis=1)    
    stock_df=pd.concat([stock_df,stock_after66],axis=1)  
    stock_df_all=pd.concat([stock_df_all,stock_df])
    

    stock_change=stock.loc[stock.index>rcept_date,['Close','Change']].iloc[0:132] #회사의 6개월치 주가
    #stock_change.loc[rcept_date,'Change']=0
    stock_change.iloc[0,1]=0
    stock_change['corp_name']=r['corp_name']
    stock_change['rcept_dt']=r['rcept_dt']
    stock_change['rcept_year']=r['rcept_year']
    stock_change['rcept_no']=rcept_no
    stock_change['누적변동량']=((stock_change['Change']+1).cumprod()-1)*100
    stock_change['경과일']=np.arange(len(stock_change))+1
    stock_change_all=pd.concat([stock_change_all,stock_change])

    
#===========================================================================================
#무상증자 관련 dataframe과 주가 dataframe을 병합
df_all1=pd.merge(left=df_all,right=stock_df_all,how='left',left_index=True,right_index=True)
df_all1=df_all1.dropna()

df_day=pd.merge(left=df_all,right=stock_day_all,how='left',left_index=True,right_index=True)
df_day=df_day.dropna()
df_all2=df_all1.rename(columns={'Change_rcept_dt':'공시접수다음날변동량','Change_after22':'공시접수후약한달후변동량',
          'Change_after66':'공시접수후약3달후변동량','nstk_ascnt_ps_ostk':'1주당신주배정주식수'})
summary=df_all2[['공시접수다음날변동량','공시접수후약한달후변동량','공시접수후약3달후변동량']].describe()
summary

plt.figure(figsize=(10,2))
plt.bar(summary.loc['mean'].index,summary.loc['mean'].values)
plt.title('평균값 변화')
plt.show()

plt.figure(figsize=(10,2))
plt.bar(summary.loc['50%'].index,summary.loc['50%'].values)
plt.title('중위값 변화')
plt.show()

plt.figure(figsize=(10,2))
plt.bar(summary.loc['max'].index,summary.loc['max'].values)
plt.title('최대값 변화')
plt.show()

plt.figure(figsize=(10,2))
plt.bar(summary.loc['min'].index,summary.loc['min'].values)
plt.title('최소값 변화')
plt.show()

changeday_mean=stock_change_all[['경과일','누적변동량']].groupby('경과일').mean()
changeday_median=stock_change_all[['경과일','누적변동량']].groupby('경과일').median()
changeday_max=stock_change_all[['경과일','누적변동량']].groupby('경과일').max()
changeday_min=stock_change_all[['경과일','누적변동량']].groupby('경과일').min()

plt.figure(figsize=(6,2))
plt.plot(changeday_mean.index, changeday_mean['누적변동량'])
plt.axvline(x = 1, color = 'red')
plt.axvline(x = 22, color = 'green')
plt.axvline(x = 44, color = 'yellow')
plt.title('공시접수일이후 경과일에 따른 평균 주가변화')
plt.show()

plt.figure(figsize=(6,2))
plt.plot(changeday_median.index, changeday_median['누적변동량'])
plt.axvline(x = 1, color = 'red')
plt.axvline(x = 22, color = 'green')
plt.axvline(x = 44, color = 'yellow')
plt.title('공시접수일이후 경과일에 따른 중위값 주가변화')
plt.show()

plt.figure(figsize=(6,2))
plt.plot(changeday_max.index, changeday_max['누적변동량'])
plt.title('공시접수일이후 경과일에 따른 최대값의 변화')
plt.show()

plt.figure(figsize=(6,2))
plt.plot(changeday_min.index, changeday_min['누적변동량'])
plt.title('공시접수일이후 경과일에 따른 최소값의 변화')
plt.show()

changeyear_mean=stock_change_all[['경과일','누적변동량','rcept_year']].groupby(['rcept_year','경과일']).mean().reset_index()
years=changeyear_mean['rcept_year'].unique()

for year in years:
    change_mean=changeyear_mean.loc[changeyear_mean['rcept_year']==year]
    plt.figure(figsize=(6,2))
    plt.plot(change_mean['경과일'], change_mean['누적변동량'])
    plt.axvline(x = 1, color = 'red')
    plt.axvline(x = 22, color = 'green')
    plt.axvline(x = 44, color = 'yellow')
    plt.title(str(year) + '년 공시접수일이후 경과일에 따른 평균 주가변화')
    plt.show()

df_day1=df_day.rename(columns={'Change_rcept_dt':'공시접수일당일변동량'})
summary=df_day1[['공시접수일당일변동량']].describe()
summary

 

이상으로 무상증자 결정 공시를 실시한 회사의 주가가 어떻게 변하는지 확인해 봤습니다.

 

이 글은 개인적으로 투자에 참고를 위해 분석한 내용으로 오류가 있을수 있으며, 투자 추천글이 아닙니다.

참고용으로만 사용을 부탁드리며 투자 책임은 100퍼센트 본인에게 있음을 알려드립니다.

반응형