ks.dgoon.lee log

국민연금 미장 포트폴리오 가져오기 #1


2024/12/15 20:11:42 #dev #sqlite #python #국민연금 #nps #미국주식 #해외주식 #SEC #포트폴리오
Attachments:

해외주식 168% 늘릴때…국내주식은 29%만 늘린 국민연금 - 매일경제

“국민연금도 투자 10배 늘렸다”...주가 25% 가까이 폭등한 美 회사는 어디?

국민연금 '코인 우회투자'로 대박···알트코인 480% 상승장 올라 타

국민연금 투자 수익률 잭팟 국내주식 vs 해외주식


투자천재 국민연금

우리의 노후를 책임지는 국민연금, 해외주식 비중을 높여가면서 MSTR(마이크로스트래티지), AVGO(브로드컴) 등 성공적인 투자를 하며 기금 고갈 시기를 열심히 뒤로 늦춰주는 중이다. 미국주식에 투자좀 해본 사람들이라면 거의다 국민연금의 미국주식 투자 결과를 보고 감탄하는 것을 볼 수 있다.

우리나라에서 투자 제일 잘 하는 사람들이 모여서 기금 운용을 하는 곳이기도 하고(그래야 한다), 성과도 보여주고 있기 때문에 국민연금의 미국주식 포트폴리오가 너무 궁금했다. 그런데 검색을 해봐도 공식 홈페이지에선 2023년 말(그러니까 1년전) 포트폴리오만 있고, 기사로 이런저런 투자를 했다 수익을 냈다 하는 것들을 봐도 데이터 소스에 대한 이야기는 찾기가 힘들었다. 그래서 열심히 검색.

SEC Filing

내가 관심 있는 회사들의 재무보고서를 보기 위해서 종종 SEC 에 들어가서 10-K, 8-K 보고서를 찾곤 하는데, 생각해보니 투자자 정보도 있을것 같았다. 그래서 구글 검색 + AI 질문을 해보니,

13-F Form

Question 2

Q: Who must file Form 13F?

A: Institutional investment managers that use the United States mail (or other means or instrumentality of interstate commerce) in the course of their business and that exercise investment discretion over $100 million or more in Section 13(f) securities must file Form 13F. See Section 13(f)(1) of the Securities Exchange Act.


1억달러(지금 환율 usdkrw 1435 기준 1천4백억원 정도)이상 미국 시장에 투자하는 투자자는 13F 보고서를 제출해야만 한다. 위 링크의 Question 7 를 보면 분기마다 제출하라고도 쓰여 있다. 그리고 SEC 에 제출된 문서들은 누구나 찾고 볼 수 있다!

그러면, 13F 가 무엇인가? 위 링크 Question 1 이 그것이지만, 영어는 어려우니 한글로 보자. 미국 증권거래위원회 공시종류 에서 보면

13-F : 운용자산 1 달러가 넘는 기관 투자자가 매분기 종료 45 이내로 신규 매수/매도 종목을 알리기 위해 제출하는 공시.[17][18] 1975 미국 의회가 투자자 보호와 공정한 시장 거래를 촉진하기 위해 제정한 증권법 개정안의 일부로 도입됐다.

라고 한다. 매수/매도 종목을 확인할 수 있는 공시이다. 국민연금이 올린거 찾아보자!

NPS (National Pension Service) 데이터 찾기

쉽게 찾을 수 있을 줄 알았다. Korea 로 검색해서 나오는거 죽 훑어보면 그중에 국민연금이 있을 줄 알았지. 하지만 암만 봐도 국민연금같은건 안보였다. 그래서 열심히 네이버와 구글검색, chatgpt 질문 등을 통해 종합해본 결과 국민연금은 SEC 에 "KOREA" 가 들어가지 않은 이름으로 등록되어 있었다.

  • National Pension Service
  • CIK: 0001608046

혹시 싶었지만, Korea 가 안 붙어 있길래 미국 연금 기금인가보다 했는데 우리나라꺼였다.

국민연금 SEC Filing 목록

여기서 13F-HR 들을 찾아보면 된다. 참고삼아 가장 최근 report 를 찾아서 열어보면 2024-3Q 내용이 있다. 여러가지 포맷으로 있는데, 브라우저에서 열기 좋은걸 하나 열어보면, 회사 이름과 투자금, 주식 수 등이 있다. 슥 긁어서 AI 한테 던지고 정렬시켜서 보니 맞는 것 같다! 대강 아래같은 모양이다. (4등 뭔가 했는데 잘 검색해보니 PUBS 라는 ETF 였다. 티커를 안주는게 짜증...) LLM 이 멍청해서 뭔가 빠뜨린거 같기도 한데 파싱은 코드짜서 할거니까 큰 상관 없다. IVV 가 10위 안에 있어야 할거 같은데...


규정에 따르면 분기 마감 후 45일 이내에 13F-HR 을 제출해야 한다. 매수/매도를 실시간으로 알 수 있는건 아니지만, 그래도 공시 뜨면 바로 찾아 보고 싶으니까! 자 이제부터 시작이야.

Listing History

SEC 관련 API 를 유료로 제공하는 업체들도 있긴 하지만, 고맙게도 SEC는 나같은 험블한 개발자를 위해 데이터를 무료로 열어두셨다. 너무 과도하게 요청을 보내지만 않으면 모두에게 열려있는 투명성! 아래 페이지에서 CIK 로 Filing history 를 가져올 수 있는 endpoint url 을 얻을 수 있다.

EDGAR Application Programming Interfaces

# data.sec.gov/submissions/

Each entity’s current filing history is available at the following URL:

https://data.sec.gov/submissions/CIK##########.json

Where the ########## is the entity’s 10-digit Central Index Key (CIK), including leading zeros.

This JSON data structure contains metadata such as current name, former name, and stock exchanges and ticker symbols of publicly-traded companies. The object’s property path contains at least one year’s of filing or to 1,000 (whichever is more) of the most recent filings in a compact columnar data array. If the entity has additional filings, files will contain an array of additional JSON files and the date range for the filings each one contains.

국민연금 CIK 는 0001608046 니까, 위 패턴에 대입하면 filing history 를 가져오는 url 은 아래와 같다.

https://data.sec.gov/submissions/CIK0001608046.json

이걸 가져오면 된다. 브라우저에서 보인다고 코드로 바로 wget, curl, requests.get 같은걸 하면 하면 403 forbidden 을 만날 수 있다. RTFM. 위 페이지 아래쪽에,

data.sec.gov does not support Cross Origin Resource Scripting (CORS). Automated access must comply with SEC.gov’s Privacy and Security Policy, as described in the   Developer FAQ.

여기서 Developer FAQ 를 따라가 보면, 이 페이지에서 아래 정보를 찾을 수 있다. 문서는 항상 꼼꼼하게 읽도록 하자.


헤더에 User-Agent 를 잘 설정해 주고 요청하면 데이터가 뙇! 내려온다.

Fetch report

제출 목록을 가져왔으니, 이제 각 아이템별 제출 리포트를 가져와야 한다. 잠시 브라우저로 이것저것 열어보니, URL 패턴을 찾을 수 있었다. 제출 목록에서 각 아이템들은 Accession number 라는 ID 를 하나씩 가지고 있었는데, CIK 와 accession number 를 적당히 조합하면 "Complete submission text file" URL 을 바로 만들 수 있었다.

가장 최근 제출한 2024-09-30 일 기준 13F-HR(제출 날짜는 2024-10-30) 의 accession number 는 0001608046-24-000012 이다. 이 리포트의 complete submission text file URL 은,

https://www.sec.gov/Archives/edgar/data/1608046/000160804624000012/0001608046-24-000012.txt

이렇다. CIK, accession number 넣어서 url 생성하는 함수 하나 만들어 주고 나서, listing 각각에 대해서 쭉 다운로드 받으면 된다. 저장을 어디에 할까 고민하다가 그냥 파일시스템에 적당한 디렉토리 계층 만들어서 받아두기로 했다.

13F-HR Registration Noti

여기까지 하고 나서 생각해보니, 리포트 다운로드 받는건 신규 13F-HR 등록 알림에 필요 없긴 했다.

10분마다 한번씩 Filing history를 점검해서 못보던 애가 생기면 나에게 알림을 보내도록 세팅했다. 이런 류의 노티를 보내는 도구로는 텔레그램 봇이나 이메일 등 여러가지가 있는데, 가장 빠르고 쉽고 내가 잘 볼 수 있을 것 같은 방법으로 Pushover 를 가져다가 세팅했다. 이제 국민연금의 13F-HR 이 등록되면 10분 내에 아래와 같은 푸시가 온다. 봇한테 내가 커맨드를 주고 싶어지면 텔레그램 봇으로 업그레이드 하자. 안할것 같지만. 푸시에 URL 도 달 수 있는데, SEC 공식 페이지로 보내봤자 보기 어렵기 때문에 내가 직접 만들 페이지로 나중에 링크를 걸기로 하자.


Parsing 13F-HR

13F-HR 을 그냥 가서 열어도 되지만, 투자금액순 정렬도 안되어 있고, 이름도 뭔지 알기가 어렵고 해서 다운로드 받은 파일을 파싱&가공해서 내가 직접 페이지를 만들어 띄워보기로 했다. 그럴려면 일단 다운로드 받아둔 파일을 파싱해서 포트폴리오 데이터를 얻어내야 한다.

Complete submission text file 은 제출한 데이터를 그냥 모두 더해놓은 파일이다. 제출 파일 중 하나가 information table 이고 여기에 포트폴리오 정보가 있다. 이 파일을 직접 가져올까도 했지만 전체 내용을 다 저장한거 하나만 가지고 있는게 편하니까, 다운로드 받은 txt 파일에서 위 information table 만 떼어내기로 했다. 어렵지 않다.

  • Start: <?xml version="1.0" encoding="UTF-8"?><ns1:informationTable
  • End: </XML>

-> [Start, End)

Start 부터 시작해서 End 바로 앞까지 잘라내면 xml 파일이 나온다. 파이썬 기본 xml 모듈로 이 부분을 파싱해서 필요한 데이터를 끄집어내면 포트폴리오 목록이 만들어진다. Ticker 가 직접적으로 있진 않은데, CUSIP(Committee on Uniform Securities Identification Procedures) 정보가 있으므로 이걸로 찾을 수 있다. 잘 변환해 보자.

CUSIP: 미국과 캐나다의 주식, 채권 등 금융상품에 할당된 고유 식별 번호

Make DB

이제 목록 가져오고, 분기별 포트폴리오 데이터도 파싱했고 CUSIP → Ticker 변화도 마쳤다. 이제 이걸 활용할 수 있게 DB 에 넣을 때가 되었다. 목적은,

  1. Export to Spreadsheet 도 편하게 할 수 있고,
  2. API 로 감싸서 가져갈 수 있게 해서,
  3. 내가 보기 좋은 간단한 웹 사이트 만들어 띄우기

를 하는 것. 분기에 한번씩만 insert 가 발생하니까 사실 거의 readonly 라고 보면 된다. postgresql 인스턴스가 있긴 하지만 계정설정이랑 귀찮기 때문에, 그냥 sqlite 에 저장하기로 했다. 분기명으로 테이블 생성해서 포트폴리오 데이터를 넣고 (ex: nps_2022Q3), nps_history 테이블에 filing history 를 저장했다. 코드 다 돌리고 나서 확인해보니 지금까지 국민연금은 지금까지 약 44Q 동안(마지막 13F-HR 이 지난분기니까 43개 +1) 미국 주식 투자를 하고 있었다. 정확히는 미국 시장에 넣은 자금이 1억달러가 넘은지 11년이다. 2024Q3 기준일에 가지고 있었던 포지션 수는 511개.

SQLite version 3.45.3 2024-04-15 13:34:05
Enter ".help" for usage hints.
sqlite> .tables
nps_2014Q3   nps_2016Q2   nps_2018Q1   nps_2019Q4   nps_2021Q3   nps_2023Q2 
nps_2014Q4   nps_2016Q3   nps_2018Q2   nps_2020Q1   nps_2021Q4   nps_2023Q3 
nps_2015Q1   nps_2016Q4   nps_2018Q3   nps_2020Q2   nps_2022Q1   nps_2023Q4 
nps_2015Q2   nps_2017Q1   nps_2018Q4   nps_2020Q3   nps_2022Q2   nps_2024Q1 
nps_2015Q3   nps_2017Q2   nps_2019Q1   nps_2020Q4   nps_2022Q3   nps_2024Q2 
nps_2015Q4   nps_2017Q3   nps_2019Q2   nps_2021Q1   nps_2022Q4   nps_2024Q3 
nps_2016Q1   nps_2017Q4   nps_2019Q3   nps_2021Q2   nps_2023Q1   nps_history
sqlite> .schema nps_2024Q3
CREATE TABLE nps_2024Q3 (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                company_name TEXT,
                title_of_class TEXT,
                ticker TEXT,
                value_usd INTEGER,
                n_shares INTEGER,
                ratio REAL
            );
sqlite> .schema nps_history
CREATE TABLE nps_history (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                accession_number TEXT UNIQUE,
                form_type TEXT,
                filing_quarter TEXT,
                filing_date TEXT,  -- YYYY-MM-DD 형식으로 저장
                url TEXT
            );
sqlite> select count(*) from nps_2024Q3;
511
sqlite> select count(*) from nps_history ;
43
sqlite>

여기까지 하루 작업한 내용. 짬날때 하루 더 해서 아래 항목들 완료하면 생각한건 다 만드는 것.

  1. FastAPI 로 a. history 가져오기, b. 각 분기 포트폴리오 가져오기 API 작성
  2. 만든 API 로 국민연금 미장 포트폴리오 보기 페이지 만들기
    1. 현재 포폴 상태
    2. 지난 분기 대비 변화 - 신규진입, 편출, 비중이나 금액변화 등등
  3. 국민연금 알리미 노티에 위에서 만든 페이지 링크 넣기

이쯤 만들고 보니 CIK 별로 죽 긁으면 되니까, 일주일(or less?)쯤 하면 13F 기반 포트폴리오 뷰어 웹사이트 하나 만들수 있겠다. 어라 이거 그럼 whalewisd....



    항상 우리의 노후를 위해 노력하시는 국민연금 기금 운용자분들 너무너무 감사합니다. 화이팅!



    저는 개발이 취미라 야크쉐이빙을 했지만, 혹시 이런 데이터를 바로 보고 싶다면,


    https://whalewisdom.com/filer/national-pension-service


    여기서 보면 됩니다. 워렌버핏도 있고...


    댓글 0개