『Rubyではじめるシステムトレード』第7章~第8章 学習記録

Rubyではじめるシステムトレード (現代の錬金術師シリーズ)

Rubyではじめるシステムトレード (現代の錬金術師シリーズ)

序文

Rubyではじめるシステムトレード』3日目。

平成最後のディナーは日本ハムの業務用レトルトカレー
f:id:yjkym:20190430224227j:plain:w150

と勘違いしてまとめ買いしたトップバリュのカレー(30%OFF)でした。
f:id:yjkym:20190430224243j:plain:w150
わりとうまかった。

進捗

  • 第2部 データ編
    • 第7章 ネットから株価データをダウンロードする
    • 第8章 ダウンロードした株価データから株オブジェクトを作る

(学習時間:6時間)

GitHub

github.com

コード実装部分(一部)

RubySystemTrade\trade_simulator\lib\text_to_stock.rb

# coding: Windows-31J

require "./lib/stock_list_loader"
require "Date"

class TextToStock
    attr_writer :from, :to

    def initialize(params)
        @data_dir = params[:data_dir] || "data"
        @stock_list = params[:stock_list] || raise {"銘柄リストを指定してください"}       
        @market_section = params[:market_section]
        @list_loader = StockListLoader.new("#{@data_dir}/#{@stock_list}")
    end

    def generate_stock(code)
        index = @list_loader.codes.index(code)
        stock = Stock.new(code,
                          market(index),
                          @list_loader.units[index])
        add_prices_from_data_file(stock)
        stock
    end

    # 銘柄リストにある銘柄について
    # データディレクトリ内にある株価データから
    # 順番に株オブジェクトを返すイテレータ
    def each_stock
        @list_loader.filter_by_market_section(*@market_section)
                    .codes.each do |code|
                        if File.exist?("#{@data_dir}/#{code}.csv")
                            yield generate_stock(code)
                        end
                    end
    end

    private
    def market(index)
        section = @list_loader.market_sections[index]
        case section            
        when /[12]|JQ/
            :t
        end
    end

    def add_prices_from_data_file(stock)
        lines = File.readlines("#{@data_dir}/#{stock.code}.csv")
        fi = from_index(lines)
        ti = to_index(lines)
        return if fi.nil? || ti.nil?
        lines[fi..ti].each do |line|
            data = line.split(",")
            date = data[0]
            prices_and_volume = data[1..5].map {|d| d.to_i}
            stock.add_price(date, *prices_and_volume)
        end
    end

    def from_index(lines)
        return 0 unless @from
        @formatted_from ||= Date.parse(@from).to_s.gsub("-","/")
        # Array#index ブロック内の評価が最初に真になった要素のインデックスを返す
        lines.index{|line|
            line[0..9] >= @formatted_from
        }
    end

    def to_index(lines)
        return lines.size unless @to
        @formatted_to ||= Date.parse(@to).to_s.gsub("-","/")
        lines.rindex{|line|
            line[0..9] <= @formatted_to
        }
    end
end

実行結果

割愛

感想

第7章はやはりヤフーファイナンススクレイピングして個別の株価データを取得してくる。
あんまりスクレイピングはやりたくないので、別の方法で株価データを取得する。

スクレイピングよりはまっとうなやり方なのだけど、スクレイピングのように全自動でということがなかなか難しい。
ここらへんは実際に運用するときにまた方法を考えなければいけなさそうだ。

第8章では取得した株価データをオブジェクトに変換していく。

そんなに難しくなさそうに見えるのだが、コードを個別指定して株価オブジェクトを取得したり、期間を指定した株価オブジェクトを取得できるようにしたり、ちょっとしたAPIを作っているような感じ。

文法もギリギリ理解できそうな感じではあるのだが、yieldを駆使したイテレータ(each_stockメソッド)を自作していたり、なかなか歯ごたえがある。

each_stockメソッドの書き方…中間変数とか使わずにどんどんチェーンして処理を書いていくのとか、すごくプログラミング素養のある人っぽい書き方ですねー…。
つらい…。

あと最後の方のline[0..9]ってなんのこっちゃって思ったんですが、ある日の株価データがline変数に

2014/04/10,1638.0,1642.0,1604.0,1604.0,176400

みたいな形式で入ってるんで、つまり日付の部分を取り出してるんですねー。

…いやー…つらい。笑

カロリーメイトいらない。

参考サイト

qiita.com

[http://chartnavi.com/brand/market/%E6%9D%B1%E8%A8%BC1%E9%83%A8/1/:embed:cite]