始値、高値、安値、終値、出来高といった株価データを生データでスクリプトや何かのプログラムで処理したいときがあります。
有償であれば生データを提供するサービスがいろいろありますが、無料となると限定的になってきます。 米国/日本の yahoo finance をスクレイピングするのが1つの手です。それ以外にも今回取り上げる 株価データ・株主優待情報・先物データ・ランキングデータ・CSVダウンロード無料 | 株式投資メモ・株価データベース も使えます。
結構あっさりとデータを落とせて、クローラーへのアクセスも許可してくれている(https://kabuoji3.com/robots.txt)ので安心です。
(ただ、残念なのがこの記事を書いている時点で 2019/12/20 までのデータしか取り込んでいないようです・・・残念というより、実際にリアルに投資を行う上では現状データとしては使えませんね。。。)
銘柄コード、年単位でのデータとなっているようですので、銘柄コード、年単位でダウンロードを行います。尚、ヘッダー情報に日本語が入っており、文字コードは ShiftJIS になっているようですので、UTF8 にしておきます。
以下の例は単純化するために、固定で code
に 3048: ビックカメラ を指定し、year
に 2019 年を直接ベタで指定しています。必要な銘柄コード/年を用意し、グルグルまわしてあげれば、無料で必要な株価データが入手できます。
package main import ( "fmt" "golang.org/x/text/encoding/japanese" "golang.org/x/text/transform" "io" "log" "net/http" "net/url" "os" "strings" ) func main() { code := "3048" year := "2019" client := &http.Client{} endpoint := "https://kabuoji3.com/stock/file.php" values := url.Values{} values.Add("code", code) values.Add("year", year) req, err := http.NewRequest(http.MethodPost, endpoint, strings.NewReader(values.Encode())) if err != nil { log.Fatal(err) } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") resp, err := client.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() log.Printf("[%s-%s]: Resp Status: %v\n", code, year, resp.StatusCode) if resp.StatusCode != http.StatusOK { log.Fatalf("[%s-%s]: bad resposne status, %v\n", code, year, resp.StatusCode) } file, err := os.Create(fmt.Sprintf("%s_%s.csv", code, year)) if err != nil { log.Fatal(err) } defer file.Close() if _, err := io.Copy(file, transform.NewReader(resp.Body, japanese.ShiftJIS.NewDecoder())); err != nil { log.Fatal(err) } log.Printf("[%s-%s]: Done\n", code, year) }
例えば、上記のファイルを用意して(get_stock_data.go
とします)、コマンドラインで以下のように叩きます。
$ go run get_stock_data.go
3048_2019.csv
というファイルができていますので、中身を覗いてみます。
$ head 3048_2019.csv 3048 東証1部 (株)ビックカメラ(小売業),,,,, 日付,始値,高値,安値,終値,出来高,終値調整値 "2019-01-04","1354","1377","1351","1366","909300","1366" "2019-01-07","1415","1429","1396","1401","740400","1401" "2019-01-08","1420","1437","1408","1410","880100","1410" "2019-01-09","1422","1455","1420","1438","995700","1438" "2019-01-10","1468","1468","1416","1432","1437300","1432" "2019-01-11","1447","1477","1419","1434","1812900","1434" "2019-01-15","1416","1417","1376","1395","1116700","1395" "2019-01-16","1395","1395","1338","1347","1368700","1347" $ tail 3048_2019.csv "2019-12-06","1255","1260","1242","1255","451100","1255" "2019-12-09","1268","1272","1253","1271","587200","1271" "2019-12-10","1271","1283","1261","1282","565900","1282" "2019-12-11","1280","1283","1267","1278","453800","1278" "2019-12-12","1277","1279","1260","1270","455300","1270" "2019-12-13","1284","1287","1263","1272","615100","1272" "2019-12-16","1267","1271","1241","1242","594100","1242" "2019-12-18","1259","1260","1249","1252","463100","1252" "2019-12-19","1252","1262","1251","1258","259300","1258" "2019-12-20","1263","1267","1256","1259","452000","1259"
OKです。が、2019/12/20 までのデータとなっています・・・
やはり直近のデータがないと実用的ではないですので、今度は別サイトでの取得例を用意します。