クリック証券デモ取引プラグインを無効化したjiji-1.1.4をリリース
クリック証券デモ取引のWebサービス提供終了を受けて、クリック証券デモ取引プラグインを無効化したjiji-1.1.4をリリースしました。
変更点
- クリック証券デモ取引プラグインを無効化。
- マニュアルの「サポートしている証券会社」からも除外しました。
更新手順
以下の操作を実行してください。
$ gem update unageanu-jiji
クロスアップ/クロスダウンを判定するユーティリティ
先行指標と遅行指標を受け取って、クロスアップ/クロスダウンを判定するユーティリティです。利用例と挙動の説明は以下。
require 'cross' cross = Cross.new # 先行指標、遅行指標を受け取って状態を返す。 # :cross .. クロスアップ、クロスダウン状態かどうかを返す。 # - クロスアップ(:up) # - クロスダウン(:down) # - どちらでもない(:none) # :trend .. 現在の指標が上向きか下向きかを返す。 # 「先行指標 <=> 遅行指標」した値。 # trend >= 1なら上向き、trned <= -1なら下向き p cross.next_data( 100, 90 ) # {:trend=>1, :cross=>:none} p cross.next_data( 110, 100 ) # {:trend=>1, :cross=>:none} p cross.next_data( 100, 100 ) # {:trend=>0, :cross=>:none} p cross.next_data( 90, 100 ) # {:trend=>-1, :cross=>:down} p cross.next_data( 80, 90 ) # {:trend=>-1, :cross=>:none} p cross.next_data( 90, 90 ) # {:trend=>0, :cross=>:none} p cross.next_data( 100, 100 ) # {:trend=>0, :cross=>:none} p cross.next_data( 110, 100 ) # {:trend=>1, :cross=>:up}
ソースは次の通り。
#===交差状態を判定する class Cross #コンストラクタ def initialize @cross_prev = nil @cross = :none @trend = 0 end # 次の値を渡す #fast:: 先行指標 #lazy:: 遅行指標 def next_data( fast, lazy ) return unless fast && lazy # 交差状態を算出 @trend = fast <=> lazy if @cross_prev && @trend != @cross_prev && @trend != 0 @cross = @trend > @cross_prev ? :up : :down else @cross = :none end @cross_prev = @trend return {:cross=>@cross,:trend=>@trend} end #クロスアップ状態かどうか判定する #「先行指標 < 遅行指標」 から 「先行指標 > 遅行指標」 になったらtrue def cross_up? @cross == :up end #クロスダウン状態かどうか判定する #「先行指標 > 遅行指標」 から 「先行指標 < 遅行指標」 になったらtrue def cross_down? @cross == :down end #上昇トレンド中かどうか判定する #「先行指標 > 遅行指標」 ならtrue def up? @trend > 0 end #下降トレンド中かどうか判定する #「先行指標 < 遅行指標」 ならtrue def down? @trend < 0 end #交差状態( :up, :down, :none ) attr_reader :cross #トレンド ( 直近の falst <=> lazy 値。) attr_reader :trend end
ver1.2で添付する予定です。
プロキシ設定の不具合を改修したjiji-1.1.3をリリース
ey さんよりご報告頂いた(ありがとうございます!)プロキシ設定の不具合を改修し、jiji-1.1.3としてリリースしました。
変更点
- クリック証券のデモ取引に接続する場合に、設定でプロキシを空のまま確定すると接続エラーになる不具合を改修。
- マニュアルの誤記についてもあわせて修正しています。
更新手順
以下の操作を実行してください。
$ gem update unageanu-jiji
jijiにクリック証券プラグインを標準添付しました
メモリリークも改修できたようなので、クリック証券プラグインを標準添付としたものをjiji-1.1.2としてリリースしました。
といっても変更点は、依存モジュールにunageanu-clickclient_scrapを追加しただけです。あと、解説サイトの内容も修正しています。
更新手順
以下の操作を実行してください。
$ gem update unageanu-jiji
追加された依存モジュール「unageanu-clickclient_scrap」もダウンロードされてきます。更新後、
$ jiji setting
で、アクセス先証券会社として「クリック証券」が追加されているはずです。
RSIを算出する
RSIを算出するクラスです。
module Signal #===一定期間のレートデータを元に値を算出するシグナルの基底クラス class RangeSignal include Signal def initialize( range=25 ) @datas = [] # レートを記録するバッファ @range = range end def next_data( data ) # バッファのデータを更新 @datas.push data @datas.shift if @datas.length > @range # バッファサイズが十分でなければ、nilを返す。 return nil if @datas.length != @range # 算出 return calculate(@datas) end def calculate(datas); end attr_reader :range end #===RSI class RSI < RangeSignal def initialize( range=14 ) super(range) end def calculate(datas) rsi( datas ) end end module_function #===RSIを得る。 # #RSI = n日間の値上がり幅合計 / (n日間の値上がり幅合計 + n日間の値下がり幅合計) * 100 #nとして、14や9を使うのが、一般的。30以下では売られすぎ70以上では買われすぎの水準。 # #datas:: 値の配列 #戻り値:: RSI値 def rsi( datas ) prev = nil tmp = datas.inject( [0.0,0.0] ) {|r,i| r[ i > prev ? 0 : 1 ] += (i - prev).abs if prev prev = i r } (tmp[0] + tmp[1] ) == 0 ? 0.0 : tmp[0] / (tmp[0] + tmp[1]) * 100 end end
RSIを表示するエージェントは以下。
#RSIを表示するエージェントのサンプル class RSISampleAgent < JIJI::PeriodicallyAgent def description "RSIを表示するエージェントのサンプルです" end def init @rsi = JIJI::Agent::Shared::Signal::RSI.new(@range) @out = output.get( "RSI", :graph, { :column_count=>1, :lines=>[30,70], :colors=>["#557777"] } ) end # 次のレートを受け取る def next_period_rates( rates ) res =@rsi.next_data( rates[:EURJPY].bid.end ) return unless res @out.put( res ) end # UIから設定可能なプロパティの一覧を返す。 def property_infos super().concat [ Property.new( "range", "集計期間", 25, :number ) ] end end
例によって、デモサイトにおいています。
uuidtools 2.0.0に対応したjiji-1.1.1をリリース
「uuidtools 2.0.0 と組みあわせて使うとバックテスト実行時にエラーになる」というご報告を頂いたので(ありがとうございます!)、それを改修したjiji-1.1.1をリリースしました。
問題の詳細は以下を参照ください。また、これに加えて、クリック証券デモトレードプラグンイでプロキシの指定ができるようにもなっています。(ローカルで実装していたので、ついでにリリース。)
更新手順
以下の操作を実行してください。
$ gem update unageanu-jiji
uuidtools 2.0.0 との組み合わせでエラーになる件
問題
jijiをインストールしてバックテストを実行すると、以下のエラーが発生する。
undefined method `random_create' for UUID:Class : /usr/lib/ruby/gems/1.8/gems/unageanu-jiji-1.1.0/lib/jiji/process_manager.rb:89:in `create_back_test' /usr/lib/ruby/gems/1.8/gems/needle-1.3.0/lib/needle/interceptor-chain.rb:74:in `__send__' /usr/lib/ruby/gems/1.8/gems/needle-1.3.0/lib/needle/interceptor-chain.rb:74:in `process_next' /usr/lib/ruby/gems/1.8/gems/unageanu-jiji-1.1.0/lib/jiji/util/synchronize_interceptor.rb:26:in `process' /usr/lib/ruby/gems/1.8/gems/unageanu-jiji-1.1.0/lib/jiji/util/synchronize_interceptor.rb:25:in `synchronize' /usr/lib/ruby/gems/1.8/gems/unageanu-jiji-1.1.0/lib/jiji/util/synchronize_interceptor.rb:25:in `process' /usr/lib/ruby/gems/1.8/gems/needle-1.3.0/lib/needle/interceptor-chain.rb:58:in `process_next' (eval):3:in `create_back_test' /usr/lib/ruby/gems/1.8/gems/unageanu-jiji-1.1.0/lib/jiji/service/process_service.rb:31:in `new_test' /usr/lib/ruby/gems/1.8/gems/unageanu-jiji-1.1.0/lib/jiji/
原因
uuidtools 2.0.0 より「UUID」クラスが「UUIDTools::UUID」に移動となったことが原因です。(jijiとは関係ありませんが、このサイトに同様の問題が報告されています。)
本来は、gemの依存モジュール設定で互換性のない依存ライブラリが使われないようにしておくべきですが、上位互換は維持されるだろうという楽観論に基づき「'1.0.7'以降のuuidtoolsに依存」としていました。このため、uuidtoolsとjijiが共にインストールされていない環境に新規インストールすると、最新の2.0.0が使われエラーになります。
対応
せっかくなのでuuidtools 2.0.0にあわせてjijiでの呼び出し箇所を修正して対応しました。また、他に同様の問題が発生しないよう、依存モジュールのバージョンは固定としました。
指数移動平均を算出する
指数移動平均を算出するライブラリです。
- ちょっとリファクタして、移動平均や加重移動平均と共通部分を親クラスに移動しています。ファイルも1つに統合して、APIも微妙に修正してます。
- あと、加重移動平均の加重が逆(古いものを重視)だったのも修正してます。orz.
module Signal #===一定期間のレートデータを元に値を算出するシグナルの基底クラス class RangeSignal def initialize( range=25 ) @datas = [] # レートを記録するバッファ @range = range end def next_data( data ) # バッファのデータを更新 @datas.push data @datas.shift if @datas.length > @range # バッファサイズが十分でなければ、nilを返す。 return nil if @datas.length != @range # 算出 return calculate(@datas) end def calculate(datas) end end #===移動平均 class MovingAverage < RangeSignal def calculate(datas) MovingAverage.ma( datas ) end # 移動平均値を計算する。 def self.ma( datas ) total = datas.inject {|t,s| t += s; t } return total / datas.length end end #===加重移動平均 class WeightedMovingAverage < RangeSignal def calculate(datas) WeightedMovingAverage.wma( datas ) end # 加重移動平均値を計算する。 def self.wma( datas ) weight = 1 total = datas.inject(0.0) {|t,s| t += s * weight weight += 1 t } return total / ( datas.length * (datas.length+1) /2 ) end end #===指数移動平均 class ExponentialMovingAverage < RangeSignal def initialize( range=25, smoothing_coefficient=0.1 ) super(range) @sc = smoothing_coefficient end def calculate(datas) ExponentialMovingAverage.ema( datas, @sc ) end # 指数移動平均値を計算する。 def self.ema( datas, smoothing_coefficient ) datas[1..-1].inject( datas[0] ) {|t,s| t + smoothing_coefficient * (s - t) } end end end
移動平均、加重移動平均、指数移動平均のグラフを表示するエージェントのサンプルです。
# # 移動平均をいろいろ試してみるエージェントのサンプル # class MovingAveragesAgent < JIJI::PeriodicallyAgent include JIJI::Agent::Shared::Signal # エージェントの説明 def description "移動平均、加重移動平均、指数移動平均を表示する" end # エージェントを初期化する。 def init @mvs = [ MovingAverage.new(@range), WeightedMovingAverage.new(@range), ExponentialMovingAverage.new(@range) ] @out = output.get( "移動平均,加重移動平均,指数移動平均", :graph, { :column_count=>3, :graph_type=>:rate, :colors=>["#8899aa","#aa8899","#99aa88"] } ) end # 次のレートを受け取る def next_period_rates( rates ) res = @mvs.map{|mv| mv.next_data( rates[:EURJPY].bid.end ) } return if ( !res[0] || !res[1] || !res[2] ) @out.put( *res ) end # UIから設定可能なプロパティの一覧を返す。 def property_infos super().concat [ Property.new( "range", "集計期間", 25, :number ) ] end end