システムトレードが流行りだ。一瞬で動く値動きを追いかけられるのは、GSとか大手の社員だけだ。素人にはシステムトレードのAPIが公開されない。
ミリ秒単位のトレードとかすごいね
東京証券取引所は、ミリ秒単位で注文を捌けるらしいが、一般素人はできない。
なので、大手のヘッジファンドの狩り場になっている気がする。
素人でもできるだけ早く発注できないか。と考えてスクリプト組んでみた。
しかし、株価をチェックできないとミリ秒単位で発注できないので発注スクリプトだけでは大雨できないね。どうしたものか。できるだけ遅延なくリアルタイム株価出す方法ないかな。
SBI証券の注文用のクライアント
SBIのバックアップサイトをベースに作っているのでそれなりに、長期間動くと思います。
gems に登録しようと思ったけど、既に同じようなものがあったんで遠慮しておく。
あと、バックアップサイトは4/3秒つまり、1.333秒/回 を超えるリクエストは弾くので、どうしたものか。どれだけ頑張っても1.5秒以上の発注はできない模様。ふーむ
#coding: utf-8 require 'mechanize' class Mechanize::HTTP::Agent def post_connect uri, response, body_io # :yields: agent, uri, response, body @post_connect_hooks.each do |hook| begin hook.call self, uri, response, body_io ensure body_io.rewind end end end end class Mechanize::HTTP::Agent @@interval = 0.75 alias_method :original_fetch, :fetch def fetch( uri, method = :get, headers = {}, params = [], referer = current_page, redirects = 0) page = nil cnt = 0 page = self.original_fetch( uri, method, headers, params, referer , redirects) until (page.title =~ /error/).nil? do # SBIバックアップサイトは秒間4/3回のリクエスト以上を受け付けてくれない。 puts "接続数エラー..再取得します(#{cnt+1}回目)" page = self.original_fetch( uri, method, headers, params, referer , redirects) sleep 0.8 + 0.1 * cnt cnt = cnt + 1 end return page end end # SBIのバックアップサイトをscraperして、注文を簡単に出す class SBISec attr_accessor :m def initialize( login_name, login_pass,order_pass ) @@login_name, @@login_pass,@@order_pass = login_name, login_pass,order_pass @m = Mechanize.new m.ssl_version = 'SSLv3' @cookie = "saved.sbi_cookie.jar.yml" m.post_connect_hooks << lambda{|ua,uri,res,body_io| body = body_io.read.toutf8 body.gsub! /Shift_JIS/,"utf-8" body_io.truncate body_io.pos body_io.rewind body_io.puts body } self.login end def login m.get "https://k.sbisec.co.jp/" m.page.forms[0].field_with( :name => "password").value= @@login_pass m.page.forms[0].field_with( :name => "username").value= @@login_name m.page.forms[0].submit end def go_to_top begin m.page.link_with( :text => /トップ/).click rescue => e m.get "https://k.sbisec.co.jp/bsite/member/menu.do" end cnt = 0 until (m.page.title =~ /error/).nil? do puts "エラー..再取得#{cnt+1}回目" m.get "https://k.sbisec.co.jp/bsite/member/menu.do" puts m.page.title sleep 1 + 0.1 * cnt cnt = cnt + 1 end end def price_now(stock_id) m.page.link_with( :text => /株価/).click m.page.forms[0].field_with( :name=>"ipm_product_code").value=stock_id m.page.forms[0].click_button(m.page.forms[0].button_with :name => /id/) price = m.page.at("td[text()^='現在']").parent.at("font").text # 現在値 return price end def keep_session self.go_to_top end def orders m.page.link_with( :text =>/注文取消/訂正/).click m.page.search("div//tr//table[cellspacing='0'][cellpadding='0'][width='100%'][border='0']") list = m.page.search('div//table[border="0"][cellspacing="0"][cellpadding="0"][width="100%"][style="margin-top:2px;"]/tr/td/table/tr') list = list.map{|e| e.to_html.gsub(/\r|\n|\t/, "") } orders = list.each_slice(4).map orders = orders.map{|e| e.join } orders = orders.map{|e| "<table>#{e}</table>" } orders = orders.map{|e| Nokogiri::HTML(e) } orders = orders.map{|e| { "銘柄" => e.at("//tr[1]/td/table/tr/td[1]").text, "注文単価" => e.at("//tr[5]/td[4]").text, "株数" => e.at("//tr[5]/td[2]").text, "種類" => e.at("//tr[4]/td[2]").text, "詳細リンク" => e.at("//tr[1]/td/table/tr/td[1]/a").attr("href"), "取消リンク" => e.at("//tr[1]/td/table/tr/td[2]/a[2]").attr("href"), "訂正リンク" => e.at("//tr[1]/td/table/tr/td[2]/a[1]").attr("href"), } } end def cancel_all_order(stock=nil) puts stock.nil? self.orders.select{|e| if stock.nil? then true elsif e["銘柄"] =~ /#{stock}/ then true else false end }.each{|e| puts e["取消リンク"] m.get e["取消リンク"] m.page.forms[0].field_with( :name=>"password").value=@@order_pass m.page.forms[0].submit } self.go_to_top end def force_buy(stock_id,quantity) #成行で買う。 self.buy(stock_id,quantity,nil,"成行:無条件") end def wait_buy(stock_id,quantity,price) #指値で買う。 self.buy(stock_id,quantity,price ) end alias_method :at_market_order, :force_buy alias_method :limit_order , :wait_buy def buy( stock_id, quantity, price=nil, order_type="指値:無条件") #株価ページ m.page.link_with( :text => /株価/).click m.page.forms[0].field_with( :name=>"ipm_product_code").value= stock_id m.page.forms[0].click_button(m.page.forms[0].button_with :name => /id/) m.page.link_with( :text =>/信用新規買/).click self.submit_order( stock_id, quantity, price, order_type) self.go_to_top end def force_sell(stock_id,quantity) #成行で買う。 self.sell(stock_id,quantity,nil,"成行:無条件") end def wait_sell(stock_id,quantity,price) #指値で買う。 self.sell(stock_id,quantity,price ) end alias_method :at_market_order, :force_buy alias_method :limit_order , :wait_buy def sell( stock_id, quantity, price=nil, order_type="指値:無条件") #株価ページ m.page.link_with( :text => /株価/).click m.page.forms[0].field_with( :name=>"ipm_product_code").value= stock_id m.page.forms[0].click_button(m.page.forms[0].button_with :name => /id/) m.page.link_with( :text =>/信用新規売/).click self.submit_order( stock_id, quantity, price, order_type) self.go_to_top end def submit_order( stock_id, quantity, price=nil, order_type) #発注ページ # <select name="sasinari_kbn"> # <option value="DEFAULT_SELECT_VALUE" selected="">選択して下さい</option> # <option value=" ">指値:無条件</option> # <option value="Z">指値:寄指</option> # <option value="I">指値:引指</option> # <option value="F">指値:不成</option> # <option value="P">指値:IOC</option> # <option value="N">成行:無条件</option> # <option value="Y">成行:寄成</option> # <option value="H">成行:引成</option> # <option value="O">成行:IOC</option> # </select> m.page.forms[0].field_with( :name=> "price").value = price m.page.forms[0].field_with( :name=> /quantity/).value = quantity #返済注文のときは sum_quantity m.page.forms[0].field_with( :name=>"sasinari_kbn").option_with( :text=>/#{order_type}/).select m.page.forms[0].field_with( :name=>"password").value=@@order_pass m.page.forms[0].submit m.page.forms[0].submit end def return_sell( stock_id, quantity, price, order_type="指値:無条件") #返済売り m.page.link_with( :text => /株価/).click m.page.forms[0].field_with( :name=>"ipm_product_code").value=stock_id m.page.forms[0].click_button(m.page.forms[0].button_with :name => /id/) m.page.link_with( :text =>/信用返済/現引現渡/).click m.page.link_with( :text =>/返済売/).click self.submit_order( stock_id, quantity, price, order_type) self.go_to_top end end