無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

指数移動平均を算出する

指数移動平均を算出するライブラリです。

  • ちょっとリファクタして、移動平均加重移動平均と共通部分を親クラスに移動しています。ファイルも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