2014年4月11日金曜日

SBI証券から無料でリアルタイム株価を取得するライブラリ

HFT(もどき)が個人でもできないかと方法を探していたのですが、個人にストリーミングの株価データを配信してくれるところが見つからず。
しかたがないので、SBI証券のリアルタイム更新を利用して、ほぼリアルタイム(3秒ディレイくらい)で株価を取得できるライブラリを作りました。
SBI証券のアカウントは必須です。

まずはインストール

gem install Sbirsp
使い方のサンプル
require "sbirsp"

Sbirsp.configure do |config|
  config.username = "user_id"
  config.password = "password"
end

@client = Sbirsp::Client.new
@client.code = 9984
@client.show_stock_price

loop do
  if @old_price != @client.price
    puts "#{@client.price}"
    @old_price = @client.price
  end
end

複数クライアントを同じプロセス内で起動した時の動作が怪しいので、なんとか調整したい。

 githubにソースコードをアップしています。
  https://github.com/face-do/sbirsp

2013年3月15日金曜日

rubyからr言語を使って、キャンペーン前後で売上に変化があったか判断する

同一期間ではないので、対応のない場合のt検定を行います。
rubyからR言語を使うには、rsrubyというライブラリを使う。

まずはRのインストール
$ brew install R

で、rのpathを設定します。
$ export R_HOME=/Library/Frameworks/R.framework/Resources

次にrsrubyのインストール
$ gem install rsruby -- --with-R-include=/Library/Frameworks/R.framework/Headers --with-R-lib=/Library/Frameworks/R.framework/Libraries

で、準備は完了。

今回はこんな感じの想定です。
・送料無料キャンペーン(今まで送料無料ではなかった部分の売上が増える=平均単価が減少する仮説)
・送料無料キャンペーンをやっていなかった、去年の売上と今年の売上を比較
・月初から今日までの期間を考える


以下がコード

まずはヒストリカルグラフで確認
require 'rsruby'

r = RSRuby::instance
x = Order.where("created_at between ? and ?" , Time.now.beginning_of_month, Time.now).map(&:price).(&:to_f)
y = Order.where("created_at between ? and ?" , Time.now.beginning_of_month - 1.years, Time.now - 1.years).map(&:price).(&:to_f)

r.eval_R(<<-RCOMMAND)

hist(#{y.join(",")}, breaks = 5 ,col = "#0000ff40", border = "#0000ff", freq = TRUE)
hist(#{x.join(",")}, breaks = 5 ,col = "#ff00ff40", border = "#ff00ff", freq = TRUE, add = TRUE)

RCOMMAND
一応F検定
r.var_test(x, y)

t検定
r.t_test(x, y, altenative="two.sided")

するとこんな感じの結果がでます。

 {"statistic"=>{"t"=>1.8121550934930575}, "parameter"=>{"df"=>4.0}, "p.value"=>0.1441855869309796, "conf.int"=>[-14560.490812856453, 69286.49081285646], "estimate"=>{"mean of x"=>32613.0, "mean of y"=>5250.0}, "null.value"=>{"difference in means"=>0.0}, "alternative"=>"two.sided", "method"=>"Welch Two Sample t-test", "data.name"=>"c(63210L, 14385L, 74970L, 5250L, 5250L) and c(5250L, 5250L)"}

2013年3月4日月曜日

ruby2.0 on Rails4.0でABテストができる短縮URLサービスを作った

先日ruby2.0が公開され、Rails4.0がついにbetaとしてgem化されていたので、早速使ってみた。

作ったサービスは、こちら http://url-s.herokuapp.com/

ソースはgithubにあげてあります。

これは2種類以上のURLを登録できる短縮URLサービスです。
外部サービスを利用していてABテストができないときに、2種類のランディングページを用意しておいて、短縮URLでランダムに飛んでもらいテストするという用途を想定しています。

以下ruby2.0とRails4.0を使ってみた感想。

  • 起動早い。2.0のおかげだと思うけど、前の環境には戻りたくない
  • マジックコメントいちいち書かなくていいの最高!
  • strong paramerterでちょいはまり。特にネストしたモデルのを扱うなら、attributesの方のidを許可しないと、updateした時に、新規で作成されてしまうので注意。
  • find_byメソッドのほうが直感的でよい。というかなんでそうじゃなかったの?

結論。 新規でアプリ作る場合、特に躊躇する理由もないので、この組み合わせで積極的に使っていきたい。

2013年1月19日土曜日

railsでorder時に特定IDのデータだけ、前に持ってくる方法

例えば、IDが1〜10のデータがある時に、IDの降順にしようとした時には
Model.order("id desc").all
などとするが、時々この中の一部(例えばID:3)は先頭に、それ以外はIDの降順にしたいときなどがある。
そんなときは、
Model.order("'id' = CASE WHEN id = 3 THEN 0 ELSE 'id' END").order("id desc").all
などとすると、できる。

2013年1月10日木曜日

vanityとchankoを使ってRailsで簡単安全にABテストをする

vanityはRailsのABテスト用ライブラリ。導入が一番簡単っぽい。
 元々はテキストとか画像をのABテストを行うためのもののようだが、 chankoという限定公開用のライブラリを使って、機能単位でもABテストができるようにしてみる。

まずはGemfileに
gem 'chanko', :git => 'git://github.com/cookpad/chanko.git'
gem "vanity"
を記述して、
# bundle install

それぞれに必要な初期設定をする。
# rails generate chanko:install
# rails generate vanity
# rake db:migrate

config/vanity.ymlを作成
development:
  adapter: active_record
  active_record_adapter: mysql2
  host: localhost
  database: DBNAME
  user: USERNAME
  password: PASSWORD

development.rbに以下を記述
 Vanity.playground.collecting = true

vanityのDashboard用コントローラを作成
class VanityController < ApplicationController
  include Vanity::Rails::Dashboard
end 

ルーティングを設定
match '/vanity(/:action(/:id(.:format)))', :controller=>:vanity

測定用のユーザアイデンティティを設定。
class ApplicationController < ActionController::Base
  use_vanity :current_user
end

Railsのルートディレクトリ下にテストと測定用のファイルを作成
#mkdir -p experiments/metrics

postした回数測定用のファイルを作成
experiments/metrics/post.rb
metric "Post" do
  description "Postした回数"
end

コントローラの好きな場所に、 track! :post を入力すれば、その場所がよばれた回数を測定できるようになります。
class PostController < ApplicationController
  def create
     track! :post
       # ...投稿する処理
     end
  end
end

テスト用ファイルを作成
experiments/post_labels.rb
ab_test "Post labels" do
  description "テスト"
  alternatives true, false
  metrics :post
end

次にchanko用設定
# rails generate chanko sample
module Sample
  include Chanko::Unit

  active_if do |context, options|
    ab_test(:price_options) 
  end
  scope(:controller) do
    function(:controller_show) do
      # controller code here
    end
  end
  scope(:view) do
    function(:view_show) do
      render :partial => "/show"
    end
  end
end
で、好きな場所にinvoke(:sample, :controller_show) をおいたり、
invoke(:sample, :show) を置けばOK。
chankoの詳しい使い方はこちらを参考に。

どちらが優位かなんてのは、Vanityが表示してくるので、 評価しやすいはず。

production環境でうまく動かなかったので、
そのときはredisによる接続をためしてみるといいかも。
production:
  adapter: redis
  host: localhost



 参考:
http://eccyan.hatenablog.com/entry/2011/12/08/223603
https://github.com/assaf/vanity
http://webandy.com/articles/a-b-testing-with-vanity

2012年12月5日水曜日

rubymotionとrailsの連携を試行錯誤した話

この記事はRubyMotion Advent Calendar 2012の5日目記事です。

rubymotionメリットのひとつに、サーバサイド(Rails)とクライアントサイドが同じ言語でかけることがあると思いますが、
思いの外Railsとどう連携していくかの情報が少ないような気がします。
なので他の人の参考になればと、個人的に試行錯誤したことを残しておこうと思います。

ちなみに、one minutesというアプリを、rubymotionで作りましたので、よければダウンロードしてください。

試行錯誤1、babble-wrapで都度処理を書く

先述のone minutesでは、表示させるニュース情報をサーバからjsonで取得するだけの単純作業なので、以下の様な感じで実装しました。

BW::HTTP.get(SERVER_URL) do |response|
  if response.ok?
    @data = BW::JSON.parse(response.body.to_str)
  else
    App.alert(response.error_message)
  end
end

実装はかなり楽でしたが、複数情報を取得したい先がある場合や、postを行うときには、かなり面倒なことになってしまいました。
それが↓です。

試行錯誤2、babble-wrapで都度処理を書く(その2)

ソーシャルアプリを作ろうとした際の実装です。
アプリ概要は、facebookみたいなものなので、記事の投稿、投稿に対するコメント、投稿に対するいいね、それぞれを表示させるタイムラインの実装が必要でした。
それが下記コード群です。

#記事読み込み
BubbleWrap::HTTP.get("#{SERVER_URL}/entries.json?page=#{@page}") do |response|
  if response.ok?
    json = BubbleWrap::JSON.parse(response.body.to_str)
    unless json.count == 0
      @table_dates << json
      self.tableView.reloadData
      @page += 1
      @readMoreButton.enabled = true
      @readMoreButton.hidden = false if @page
    else
      @page = nil
      @readMoreButton.hidden = true
    end
  else
    App.alert(response.error_message)
   end
end
#記事投稿
  BubbleWrap::HTTP.post("#{SERVER_URL}/entries.json", {payload: data})
#コメント
 BubbleWrap::HTTP.post("#{SERVER_URL}/comments.json", {payload: data}) do |response|
    if response.ok?
      App.alert("コメントしました")
    elsif response.status_code.to_s =~ /40\d/
     App.alert("comment failed")
    else
     App.alert(response.error_message)
   end
 end
#いいね
BubbleWrap::HTTP.post("#{SERVER_URL}/likes.json", {payload: data}) do |response|
   if response.ok?
      App.alert("likeしました")
    else
     App.alert(response.error_message)
   end
 end

企画自体が没になったため、コレ以上コードは書いていないのですが、
重複が多く、メンテナンス性も非常に悪いものができてしまいました。

で、このあとECアプリを作ることになりました。
これまでの経験を踏まえ、もう少しRailsライクに実装したいと感じるように。

具体的には、
1.new、find、save、allなどで情報が取得や保存ができるように
2.バリデーションエラーは、その内容までも分かるように
3.ネットワークエラーなどがでたら、バリデーションエラーなどとは別に判別できるように

という理想を掲げ、作ってみた現実(ライブラリ)はこちら。
https://github.com/face-do/motion-rails-model

初めて作ったライブラリでもあり、非常にできはよくないのですが、それでも一応の理想は実現できました。
(といっても、babble-wrapのさらにwrapperライブラリだったりしますが。。。)

使い方としては、最初にアクセスしたいURLやbasic認証の情報を入力


    RM::Model.set_url("#{URL}/api/")
    RM::Model.set_username("username")
    RM::Model.set_password("password")

その後モデル用のクラスを作り、ライブラリを継承。

class Orders < RM::Model
  attr_accessor :name
 
  def attributes_update(json)
    @name = json['name']
    super
  end
end

これで、

order = Orders.new
order.name = "hogehoge"
order.save do |x|
  if x.ok?
    App.alert("保存しました。")
  end
end

とかすると、
railsに対して
/api/orders.json?name=hogehoge
のpostメソッドを実行するし、

Orders.find(1) do |x|
  if x.ok?
    @order = x.body
  end
end

で、
/api/orders/1.json
のgetをしたりします。

またgetしてきた、Objectに対してsaveをすると、
/api/orders/1.json
に対してputをするようになってます。

これを作った後、メタプログラミングrubyを読みまして、
もう少し抽象化ができそうな気がしているので、機会を見て修正していく予定です。

2012年10月29日月曜日

今ウェブサイトを作るなら必須のアイコン画像サイズ一覧


漏れがないようにまとめてみました。

サイト全体
favicon
16×16

facebook(OGP)対策
200x200

ウェブクリップアイコン(ios、android)対策
114×114(iPhone、iPod touchのRetina)
57×57(iPhone、iPod touchの非Retina)
144×144(iPadのRetina)
72×72(iPadの非Retina)

一括作成サービスができてくれるといいなあ。