CFO와 PCR에 대해서는 여기서 읽어보고 오시면 좋을 것 같고,
지난번 미국주식 Ticker(종목코드) 가져오는 것 이후 작업을 시작해 보겠습니다.
며칠 만에 글을 썼는데, 그 이유는...
1. 내가 아직 코딩 초보라서..?
2. 생각보다 작업이 지연돼서... 이유는 아래를 보시면 알 수 있어요.
--- 보시다가 언제든지 피드백 주시면 환영입니다..
미국주식 ticker 가져오기
import FinanceDataReader as fdr
import pandas as pd
def get_ticker():
nasdaq = fdr.StockListing('NASDAQ')
nyse = fdr.StockListing('NYSE')
amex = fdr.StockListing('AMEX')
df = pd.concat([nasdaq, nyse, amex])
df1 = df.copy()
df1 = df1.drop_duplicates('Symbol')
return df1['Symbol']
tickers_all = get_ticker()
간단하게 설명하면서 넘어가 볼게요.
우선, 저는 여기서 지난번에 얘기한 FinanceDataReader를 활용해서 미국 주식 ticker를 가져오는
get_ticker를 만들었어요.
tickers_all = get_ticker()로 불러들이기 위한 작업까지.
from yahooquery import Ticker
from tqdm import tqdm
# 전체 미국시장 ticker
tickers = tickers_all.to_list()
# tickers = ['AAPL', 'TSLA', 'PLTR','NVDA','SOFI','COIN','AMZN']
tickers = tickers[:100]
symbol = Ticker(tickers)
print(symbol)
# CFO : 영업활동현금흐름 == 영업이익 + 감가상각비 - 법인세 (별도항목으로 기재)
cash = symbol.cash_flow(trailing=False)
cashflow = cash['CashFlowFromContinuingOperatingActivities']
date = cash['asOfDate'].dt.strftime('%Y-%m-%d')
# 최근 CFO 구하기
last_cashflows = [] # 최근 1년 CFO
last_cashflows2 = [] # 최근 2년전 CFO
last_cashflows3 = [] # 최근 3년전 CFO
for ticker in tqdm(tickers):
if ticker in cashflow and isinstance(cashflow[ticker], pd.Series) and len(cashflow[ticker]) >= 1:
last_cashflow = cashflow[ticker].iloc[-1]
last_cashflows.append(last_cashflow)
else:
last_cashflows.append(None)
if ticker in cashflow and isinstance(cashflow[ticker], pd.Series) and len(cashflow[ticker]) >= 2:
last_cashflow2 = cashflow[ticker].iloc[-2]
last_cashflows2.append(last_cashflow2)
else:
last_cashflows2.append(None)
if ticker in cashflow and isinstance(cashflow[ticker], pd.Series) and len(cashflow[ticker]) >= 3:
last_cashflow3 = cashflow[ticker].iloc[-3]
last_cashflows3.append(last_cashflow3)
elif ticker in cashflow and isinstance(cashflow[ticker], pd.Series) and len(cashflow[ticker]) >= 2:
last_cashflows3.append(None)
else:
last_cashflows3.append(None)
yahooquery를 활용해서 가져온 ticker를 넣어서 데이터를 가져오는 방식을 선택했어요.
tickers = tickers_all.to_list()
# tickers = ['AAPL', 'TSLA', 'PLTR','NVDA','SOFI','COIN','AMZN']
# tickers = tickers[:1000]
이 부분에는 많은 이유가 있습니다.
tickers = ticekrs[:100]으로 했을 때는 무난하고 빠르게 돌아갔거든요...?
약 3~40초 정도?
근데 tickers[:1000]으로 하니까 미친 듯이 처리속도가 느려지더라고요....?
10시간이 넘어가도 안 끝나고.... 원인을 모르겠음..
이유가 뭘까 해서 코드를 분리해서 쪼개서 실행해 보면서 찾았습니다.
# 시가총액
market_caps = []
for ticker in tqdm(tickers):
sym_detail = symbol.summary_detail[ticker]
if isinstance(sym_detail, dict):
market_cap = sym_detail.get('marketCap')
market_caps.append(market_cap)
else:
market_caps.append(None)
print("시가총액:", market_caps)
여기!! 시가총액 marketcap을 가져오는 코드가 엄청 오래 걸리더라고요.
(ticker 100개는 괜찮음... 본인이 궁금한 ticker만 리스트로 해서 해도 금방 됩니다.)
1개 가져오는데 대략 20~30초 정도 소요...
근데 위에서 리스트로 만든 7개 가져올 때는, 3초 걸림.. (??????)
dictionary를 ticker별로 들어가서 찾아서 가져와서 오래 걸리는 건지...
제 코드가 문제인 건지 너무 오래 걸려서 우선 빼놓고 돌릴게요.
(도움을 주실 수 있는 분이 있다면 꼭 찾아주세요... 제발)
PCR 비율 = 시가총액 / 최근 CFO
아래와 같이 코드를 작성했습니다.
# PCR 비율 구하기
pcr_ratios = []
for market_cap, last_cashflow in tqdm(zip(market_caps, last_cashflows)):
if market_cap is None or last_cashflow is None:
pcr_ratio = None
else:
pcr_ratio = market_cap / last_cashflow
pcr_ratios.append(pcr_ratio)
print("PCR 비율:", pcr_ratios)
그리고 CFO가 연속적으로 증가를 했는지 체크하기 위해서는 다음과 같이!
con_increase = []
for ticker in tickers:
cfo_current = last_cashflows[tickers.index(ticker)]
cfo_prev = last_cashflows2[tickers.index(ticker)]
cfo_prev2 = last_cashflows3[tickers.index(ticker)]
if (cfo_current is not None and
cfo_prev is not None and
cfo_prev2 is not None and
cfo_current > cfo_prev and
cfo_prev > cfo_prev2):
con_increase.append('Y')
else:
con_increase.append('N')
최종적으로 출력되는 결과물을 보시면 아실 텐데,
숫자단위가 커서 백만단위로 포맷을 정리하는 걸로 작성했고,
데이터프레임을 생성해서 깔끔하게 볼 수 있도록 작성했어요.
# 숫자 형식 설정
pd.options.display.float_format = '{:,.0f}'.format
# 값을 백만 단위로 변환하는 함수
def format_millions(value):
if isinstance(value, list):
return [f"{v / 1_000_000:,.0f} M" if v else None for v in value]
else:
return f"{value / 1_000_000:,.0f} M" if value else None
# 데이터프레임 생성
df = pd.DataFrame({
'US Stock': tickers,
'PCR': pcr_ratios,
'Continuous Increase': con_increase
})
# CFO 데이터를 백만 단위로 변환하고 데이터프레임에 추가
for i, cf_data in enumerate(tqdm([last_cashflows, last_cashflows2, last_cashflows3], desc="Formatting Data")):
df[f'{date[3-i]}'] = [format_millions(cf) for cf in cf_data]
df.head(10)
이렇게까지 실행하고 나면 아래와 같은 결과가 나옵니다..
(시가총액의 늪을 해결하지 못해서 며칠 동안 머리 싸맨 시간이 더 길었어요..)
무한루프에 빠진 줄 알고 뭐가 문제인지... 헤매는 시간도 있었고
위에서 날짜 옆에 시간이 거슬려서... 이것도 코드 수정 추가
yahooquery의 구조가 데이터를 가져올 때, 시간이 좀 많이 걸리는 구조인 건지
제가 코드를 효율적으로 못 짜는 건지 몰라서 그게 너무 답답하네요..
이것 때문에 tqdm도 추가해서 progress bar로 진행되는 상황도 확인하고,
중간중간 print문도 넣어서 진행상태 체크할 수 있게 하고 이런 사소하지만 중요한 것들을 익히게 되었습니다.
하지만 우선 하고자 하는 목표까지는 달성해서..
여기서 다음 업그레이드는 어떤 걸 해야 할지 고민입니다.
단순히 필터링만 해서 보면 될지?
이걸 투자에 반영하기 위해서는 실제 기업의 보고서나 이런 부분들도 반영해야 되나...?라는 여러 가지 생각이 드는데
이건 금융공부를 좀 해야겠죠...?
그래서 당장은 이 코드를 속도개선이 된다면
텔레그램 봇과 연결해서 사용할 수 있는 방법을 생각해보려고 합니다.
관심 있으시거나 아이디어가 있으신 분들은 편하게 제안해 주시면 감사하겠습니다.
'주식' 카테고리의 다른 글
ARK 인베스트먼트 ETF 알아보기 - PRNT, IZRL (0) | 2023.07.15 |
---|---|
미국 부채한도 합의안 상원도 가결 (0) | 2023.06.02 |
캐시 우드의 아크인베스트, 코인베이스 매수 지속 (0) | 2023.05.03 |
댓글