Tana Gone
Tana Gone
1 min read

Categories

東証からは毎日各銘柄の8本値が公表されているが、pdfで記載されているのが困ったところ。しかも時期によって記載内容が異なっている。例えば、2024-07以降は銘柄毎に売買株数、売買代金が記載された日報が公表されている。しかし、2020-01 ~ 2024-07では月報が公表され、そこには売買株数、売買代金の記載がない。

2019-12以前では(2011-01まで)日報がZipアーカイブされて公表されそこにはそこには売買株数、売買代金の記載がある。 もっとも古いデータは1949-05-16であるが非常に読み難いtif画像で入手できる。当時の銘柄数は400位である。銘柄コードは無い。

  • Ruby

    require 'logger'
      
    log_file = File.open('stq2csvExe.log', 'a')
    $logger = Logger.new(log_file)
    $logger.formatter = proc do |severity, datetime, progname, msg|
      "#{datetime}: #{msg}\n"
    end
      
    require 'pdf-reader'
    require 'open-uri'
    require 'sqlite3'
    # puts 'required pdf filename' if ARGV.count.zero?
    # reader = PDF::Reader.new ARGV[0]
    def makeFileObj date
      urlStr = "https://www.jpx.co.jp/markets/statistics-equities/" + 
        "daily/mklp77000000d1sb-att/stq_#{date}.pdf"
      file = nil
      retry_count = 0
      begin
        file = URI.open(urlStr)
      rescue StandardError => e
        if e.is_a?(OpenURI::HTTPError) && e.io.status[0] == '404'
          $logger.error "File not found at #{urlStr}. Not retrying."
          # raise e
        end
        retry_count += 1
        if retry_count < 3
          $logger.warn "URI.open failed, retrying... (#{retry_count}/3). Error: #{e.message}"
          sleep(1)
          retry
        else
          $logger.error "Failed to open URL after 3 attempts."
        end
      end
      return file
    end
    date = '20240731'
    file = makeFileObj(date)
    exit if file.nil?
    reader = PDF::Reader.new file
      
    all_lines = []
    reader.pages.each do |page|
      all_lines.concat(page.text.split("\n"))
    end
      
    lines = []
    all_lines.each do |line|
      break if line.match(/立 会 市 場.* 当 日 決 済 取 引/)
      lines << line
    end
      
    lines.select! { |line| line.match(/^[1-9][A-Z0-9]{3}/) }
    lines.map! { |e| e.gsub /^([1-9][A-Z0-9]{3})[ ]+[A-Z#]/, '\1' }
    lines.map! { |e| e.gsub /[ ][ ]*/, '|' }
      
    2.times do
      lines.map! do |e|
        line = e.split '|'
        if line[2] && line[3] && line[2].match?(/[^a-zA-Z0-9,-\.]/) && line[3].match?(/[^a-zA-Z0-9,-\.]/)
          line[2] = "#{line[2]} #{line[3]}"
          line.delete_at(3)
        end
        line.join '|'
        # line
      end
    end
    db = SQLite3::Database.new 'stock8.db'
      
    lines.each do |line|
      values = line.split '|'
      code = values[0]
      db.execute <<-SQL
        CREATE TABLE IF NOT EXISTS '#{code}' (
          date TEXT,
          unit TEXT,
          company TEXT,
          openam TEXT,
          higham TEXT,
          lowam TEXT,
          closeam TEXT,
          openpm TEXT,
          highpm TEXT,
          lowpm TEXT,
          closepm TEXT,
          finalSpecialQuote TEXT,
          NetChange TEXT,
          vwap TEXT,
          volume TEXT,
          value TEXT
        );
      SQL
      
      db.execute("INSERT INTO '#{code}' VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [date] + values[1..-1])
    end
      
    db.close
      
    __END__
    銘柄コードが1305 D(配当落ち)である場合を考慮。銘柄名にスペースが含む場合を考慮。Openが−である場合にも対応。確認は、Table Tool.appで行った。
      
    R-XXX: REIT 国内投資証券
    P-XXX: Pro Market
    G-XXX: Growth Market
    
    • stock8.db

      sqlite> select * from '1301';
      date|unit|company|openam|higham|lowam|closeam|openpm|highpm|lowpm|closepm|finalSpecialQuote|NetChange|vwap|volume|value
      20240731|100|極洋|3,980.00|4,020.00|3,955.00|4,020.00|4,010.00|4,055.00|4,010.00|4,055.00||60.00|4,021.9018|16.3|65,557
      
    • Gemini CLIへ与えたPrompt

    改良前はstdout経由にCSVへ保存する目的で、文字列格納のlines配列を書き出していた。それをデータベースへ保存するコードをGemini CLIで自動生成してみた。

      puts linesの部分を次のように改良して下さい
        
      1. sqlite3のstock8.dbに値を保存
      2. 文字列linesは銘柄情報が格納された配列の配列です。銘柄情報が格納された配列には次の値が格納されています。すべて文字列型です。
      [code, unit, company, openam, higham, lowam, closeam, openpm, highpm, lowpm, closepm, finalSpecialQuote, NetChange, vwap, volume, value]
      3. 文字列codeのテーブルを作成して下さい。
      4. テーブルには次の情報が格納出来るようにして下さい
      [date, unit, company, openam, higham, lowam, closeam, openpm, highpm, lowpm, closepm, finalSpecialQuote, NetChange, vwap, volume, value]
      5. テーブル作成後、銘柄情報が格納された配列の内容をテーブルへ格納して下さい