인플레이션에서 살아남기.

책 리뷰 2022. 10. 14. 09:46 Posted by UnHa Kim

 

FRB의 입장에 빙의해서 고민과 해결책을 고민해 보면서 향후 경제 흐름에 대한 안목을 넓혀주는 책.

 

1970년대 인플레이션 시대와 현재 상황에 대한 비교분석이 탁월하다.

 

나는 이 책을 읽고 나서 섣부른 경제 전망을 모두 내려놨다.

 

FRB의장조차도 인플레이션이 일시적이라는 예측이 틀려서 '겸손하고 재빠른' 모드로 태세 전환한 마당에 누가 향후 경제 흐름을 알 수 있단 말인가?

 

 

'책 리뷰' 카테고리의 다른 글

가상화폐 투자마법 공식  (0) 2022.11.05
행운에 속지 마라.  (0) 2021.10.18
역발상 투자  (0) 2021.10.18
팩터 457개의 미국 증시에서 유효성 검증  (0) 2021.10.18
팩터 148개의 한국 증시에서 유효성 검증  (0) 2021.10.18

댓글을 달아 주세요

야후! 금융 재무 정보 얻기.

GHTS 2022. 10. 8. 13:46 Posted by UnHa Kim

다음 동영상에 '야후! 금융'에서 재무 정보를 추출하는 방법이 잘 설명되어 있다.

https://youtu.be/fw4gK-leExw

 

동영상 내용이 파이썬 기준이지만, 내용만 이해하면 Go언어에서도 구현은 쉽다.

chromedp(https://github.com/chromedp/chromedp) 모듈을 사용하면 자바스크립트를 이용해서 동적으로 생성되는 '야후! 금융' 웹페이지도 문제없이 불러들일 수 있다.

이렇게 읽어온 HTML에서 JSON 데이터 부분만 추출해서 map형태로 저장한 후 적절히 활용하면 된다.

애플의 재무 데이터를 읽어들이는 Go언어 예제 코드는 다음과 같다.

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/chromedp/chromedp"
	"log"
	"regexp"
	"testing"
	"time"
)

// 참고자료 : https://youtu.be/fw4gK-leExw
// 애플 재무 정보 수집 예제
func main() {
	const url템플릿 = `https://finance.yahoo.com/quote/%v/financials`
	종목코드 := "AAPL" // 애플

	// create chrome instance
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	// create a timeout
	ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
	defer cancel()

	var html string
	url := fmt.Sprintf(url템플릿, 종목코드)

	if err := chromedp.Run(ctx,
		chromedp.Navigate(url),
		chromedp.InnerHTML("body", &html, chromedp.ByQuery),
	); err != nil {
		log.Fatal(err)
	}

	// HTML에서 JSON 데이터를 맵 형태로 추출
	html = regexp.MustCompile(`(?s)\s--\sData\s--\s.+?</script>`).FindString(html)
	html = regexp.MustCompile(`(?s)root.App.main.+</script>`).FindString(html)
	html = html[16 : len(html)-21]

	var 맵 map[string]interface{}

	json.Unmarshal([]byte(html), &맵)

	손익계산서_연도 := f2맵_모음(맵, []string{"context", "dispatcher", "stores", "QuoteSummaryStore", "incomeStatementHistory", "incomeStatementHistory"})
	f맵_모음_출력("손익계산서_연도", 손익계산서_연도)

	손익계산서_분기 := f2맵_모음(맵, []string{"context", "dispatcher", "stores", "QuoteSummaryStore", "incomeStatementHistoryQuarterly", "incomeStatementHistory"})
	f맵_모음_출력("손익계산서_분기", 손익계산서_분기)

	재무상태표_연도 := f2맵_모음(맵, []string{"context", "dispatcher", "stores", "QuoteSummaryStore", "balanceSheetHistory", "balanceSheetStatements"})
	f맵_모음_출력("재무상태표_연도", 재무상태표_연도)

	재무상태표_분기 := f2맵_모음(맵, []string{"context", "dispatcher", "stores", "QuoteSummaryStore", "balanceSheetHistoryQuarterly", "balanceSheetStatements"})
	f맵_모음_출력("재무상태표_분기", 재무상태표_분기)

	현금흐름표_연도 := f2맵_모음(맵, []string{"context", "dispatcher", "stores", "QuoteSummaryStore", "cashflowStatementHistory", "cashflowStatements"})
	f맵_모음_출력("현금흐름표_연도", 현금흐름표_연도)

	현금흐름표_분기 := f2맵_모음(맵, []string{"context", "dispatcher", "stores", "QuoteSummaryStore", "cashflowStatementHistoryQuarterly", "cashflowStatements"})
	f맵_모음_출력("현금흐름표_분기", 현금흐름표_분기)
}

func f2맵_모음(맵 map[string]interface{}, 키_모음 []string) (맵_모음 []map[string]interface{}) {
	for _, 키 := range 키_모음 {
		if 맵2, ok := 맵[키].(map[string]interface{}); ok {
			맵 = 맵2
			continue
		} else if 값_모음, ok := 맵[키].([]interface{}); ok {
			맵_모음 = make([]map[string]interface{}, len(값_모음))

			for i, 값 := range 값_모음 {
				맵_모음[i] = 값.(map[string]interface{})
			}

			return 맵_모음
		} else {
			panic(fmt.Errorf("예상하지 못한 자료형 %T\n", 맵[키]))
		}
	}

	return
}

func f맵_모음_출력(제목 string, 맵_모음 []map[string]interface{}) {
	for i, 맵 := range 맵_모음 {
		for 키, 값 := range 맵 {
			fmt.Printf("%v %v %v %v\n", 제목, i, 키, 값)
		}
	}
}

 

 

 

 

댓글을 달아 주세요

네이버에서 상당히 많은 국가의 주식 정보를 얻을 수 있다는 것을 알았으나,

좀 더 많은 국가의 정보를 수집하고 능력을 키우고 싶어서,

인베스팅닷컴에서 종목 정보를 수집을 시도해 봤다.

 

다음 URL에서 베트남 종목 목록 수집하는 것을 출발점으로 잡았다.

(https://www.investing.com/equities/vietnam)

 

해당 페이지는 기본적으로 'HNX 30'에 포함된 종목만을 보여준다.

모든 종목의 목록을 얻고 싶다면, 선택 상자에서 'Vietnam all stocks' 항목을 선택해야 하는 데, 이것을 프로그래밍적으로 자동으로 수행하도록 구현하는 방법을 찾느라 한참 헤맸다.

 

시행착오를 거듭한 결과, Go언어 기준으로 chromedp(https://github.com/chromedp/chromedp) 라는 모듈을 이용해서 다음과 같이 하면 모든 종목의 식별 데이터가 포함된 HTML을 추출할 수 있다.

// create chrome instance
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()

// create a timeout
ctx, cancel = context.WithTimeout(ctx, lib.P1분)
defer cancel()

const url = `https://www.investing.com/equities/vietnam`

var html string

if 에러 := chromedp.Run(ctx,
   chromedp.Navigate(url),
   chromedp.SetAttributeValue(`#all`, "value", "ALL"),
   chromedp.SetValue(`//select[@id="stocksFilter"]`, "ALL", chromedp.BySearch),      
   chromedp.WaitVisible("cross_rate_markets_stocks_1", chromedp.ByID),
   chromedp.InnerHTML("marketInnerContent", &html, chromedp.ByID),
); 에러 != nil {
   log.Fatal(에러)
}

이렇게 추출해 낸 HTML을 GoQuery(https://github.com/PuerkitoBio/goquery)등의 모듈을 이용해서 내용을 분석하면, pare_id(인베스팅닷컴 독자적인 일종의 종목 구분 코드), 종목 이름, 추가 정보 URL등의 정보를 추출할 수 있다.

 

문서 := lib.F확인2(goquery.NewDocumentFromReader(strings.NewReader(html)))
문서.Find("tbody tr").Each(func(i int, s *goquery.Selection) {
    pair_id, _ := s.Attr("id")
    href, _ := s.Find("a").Attr("href")

    <... 중략 ...>    
})

 

여기서부터 문제가 시작되는 데, 인베스팅닷컴에서 사용하는 종목 구분 코드인 Pair ID는 인베스팅닷컴 사이트 내에서만 의미가 있고, 다른 곳에서는 통하지 않는다.

Pair ID와 연결된 범용적인 '종목 코드(ticker, symbol)'을 알아내려면 모든 종목에 대해서 추가 정보 URL을 일일이 질의해야 한다.

즉, 인베스팅닷컴은 전세계 주식 종목에 대한 정보를 가장 광범위하게 제공하지만, 대신에 인베스팅닷컴 고유의 독자적인분류 코드로만 제공해서 범용성이 떨어지고, 일반적으로 사용되는 종목 코드로 변환하려면, 상당히 많은 추가 웹 질의를 해야한다.

 

이러한 범용성 문제가 없는 '야후! 금융'의 경우 제공하는 종목의 범위가 훨씬 좁은 문제가 있다.

광범위한 정보를 쉽게 수집하는 방법은 아직 못 찾았고, 편리성과 광범위함은 트레이드오프 선택 관계에 있는 것 같다.

 

댓글을 달아 주세요