ruby 株の分析关数群

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ruby 株の分析关数群相关的知识,希望对你有一定的参考价值。

#!/usr/bin/env ruby
# from https://raw.githubusercontent.com/unageanu/jiji/master/base/shared_lib/system/signal.rb
module Signal

  #===一定期間のレートデータを元に値を算出するシグナルの基底クラス
  class RangeSignal
    include Signal
    #====コンストラクタ
    #range:: 集計期間
    def initialize( range=25 )
      @datas = [] # レートを記録するバッファ
      @range = range
    end
    #====次のデータを受け取って指標を返します。
    #data:: 次のデータ
    #戻り値:: 指標。十分なデータが蓄積されていない場合nil
    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 #:nodoc:
     #集計期間
     attr_reader :range
  end

  #===移動平均
  class MovingAverage < RangeSignal
    def calculate(datas) #:nodoc:
      ma( datas )
    end
  end

  #===加重移動平均
  class WeightedMovingAverage < RangeSignal
    def calculate(datas) #:nodoc:
      wma( datas )
    end
  end

  #===指数移動平均
  class ExponentialMovingAverage < RangeSignal
    #====コンストラクタ
    #range:: 集計期間
    #smoothing_coefficient:: 平滑化係数
    def initialize( range=25, smoothing_coefficient=0.1 )
      super(range)
      @sc = smoothing_coefficient
    end
    def calculate(datas) #:nodoc:
      ema( datas, @sc )
    end
  end

  #===ボリンジャーバンド
  class BollingerBands < RangeSignal
    #====コンストラクタ
    #range:: 集計期間
    #pivot:: ピボット
    def initialize( range=25, pivot=[0,1,2], &block )
      super(range)
      @pivot = pivot
      @block = block
    end
    def calculate(datas) #:nodoc:
      bollinger_bands( datas, @pivot, &@block )
    end
  end

  #===傾き
  class Momentum < RangeSignal
    def calculate(datas) #:nodoc:
      momentum( datas )
    end
  end

  #===傾き(最小二乗法を利用)
  class Vector < RangeSignal
    def calculate(datas)
      vector( datas )
    end
  end

  #===MACD
  class MACD < RangeSignal
    #====コンストラクタ
    #short_range:: 短期EMAの集計期間
    #long_range:: 長期EMAの集計期間
    #signal_range:: シグナルの集計期間
    #smoothing_coefficient:: 平滑化係数
    def initialize( short_range=12, long_range=26,
        signal_range=9, smoothing_coefficient=0.1 )
      raise "illegal arguments." if short_range > long_range
      super(long_range)
      @short_range = short_range
      @smoothing_coefficient = smoothing_coefficient
      @signal = ExponentialMovingAverage.new(
        signal_range, smoothing_coefficient )
    end
    def next_data( data ) #:nodoc:
      macd = super
      return nil unless macd
      signal = @signal.next_data( macd )
      return nil unless signal
      return { :macd=>macd, :signal=>signal }
    end
    def calculate(datas) #:nodoc:
      macd( datas, @short_range, range, @smoothing_coefficient )
    end
  end

  #===RSI
  class RSI < RangeSignal
    #====コンストラクタ
    #range:: 集計期間
    def initialize( range=14 )
      super(range)
    end
    def calculate(datas) #:nodoc:
      rsi( datas )
    end
  end

  #===DMI
  class DMI < RangeSignal
    #====コンストラクタ
    #range:: 集計期間
    def initialize( range=14 )
      super(range)
      @dxs = []
    end
    def calculate(datas) #:nodoc:
      dmi = dmi( datas )
      return nil unless dmi
      @dxs.push dmi[:dx]
      @dxs.shift if @dxs.length > range
      return nil if @dxs.length != range
       dmi[:adx] = ma( @dxs )
      return dmi
    end
  end

  #===ROC
  class ROC < RangeSignal
    #====コンストラクタ
    #range:: 集計期間
    def initialize( range=14 )
      super(range)
    end
    def calculate(datas) #:nodoc:
      roc( datas )
    end
  end

module_function

  #===移動平均値を計算します。
  #datas:: 値の配列。
  #戻り値:: 移動平均値
  def ma( datas )
    total = datas.inject {|t,s|
      t += s; t
    }
    return total / datas.length
  end

  #===加重移動平均値を計算します。
  #datas:: 値の配列。
  #戻り値:: 加重移動平均値
  def 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

  #===指数移動平均値を計算します。
  #datas:: 値の配列。
  #smoothing_coefficient:: 平滑化係数
  #戻り値:: 加重移動平均値
  def ema( datas, smoothing_coefficient=0.1 )
    datas[1..-1].inject( datas[0] ) {|t,s|
      t + smoothing_coefficient * (s - t)
    }
  end

  #
  #===ボリンジャーバンドを計算します。
  #
  # +2σ=移動平均+標準偏差×2
  # +σ=移動平均+標準偏差
  # -σ=移動平均-標準偏差
  # -2σ=移動平均-標準偏差×2
  # 標準偏差=√((各値-値の期間中平均値)の2乗を期間分全部加えたもの)/ 期間
  # (√は式全体にかかる)
  #
  #datas:: 値の配列
  #pivot:: 標準偏差の倍数。初期値[0,1,2]
  #block:: 移動平均を算出するロジック。指定がなければ移動平均を使う。
  #戻り値:: ボリンジャーバンドの各値の配列。例)  [+2σ, +1σ, TP, -1σ, -2σ]
  #
  def bollinger_bands( datas, pivot=[0,1,2], &block )
    ma = block_given? ? yield( datas ) : ma( datas )
    total = datas.inject(0.0) {|t,s|
      t+= ( s - ma ) ** 2
      t
    }
    sd = Math.sqrt(total / datas.length)
    res = []
    pivot.each { |r|
      res.unshift( ma + sd * r )
      res.push( ma + sd * r * -1 ) if r != 0
    }
    return res
  end

  #===一定期間の値の傾きを計算します。
  #datas::  値の配列
  #戻り値:: 傾き。0より大きければ上向き。小さければ下向き。
  def momentum( datas )
      (datas.last - datas.first) / datas.length
  end

  #===最小二乗法で、一定期間の値の傾きを計算します。
  #datas::  値の配列
  #戻り値:: 傾き。0より大きければ上向き。小さければ下向き。
  def vector( datas )
    # 最小二乗法を使う。
    total = {:x=>0.0,:y=>0.0,:xx=>0.0,:xy=>0.0,:yy=>0.0}
    datas.each_index {|i|
      total[:x] += i
      total[:y] += datas[i]
      total[:xx] += i*i
      total[:xy] += i*datas[i]
      total[:yy] += datas[i] * datas[i]
    }
    n = datas.length
    d = total[:xy]
    c = total[:y]
    e = total[:x]
    b = total[:xx]
    return (n*d - c*e) / (n*b - e*e)
  end

  #===MACDを計算します。
  #MACD = 短期(short_range日)の指数移動平均 - 長期(long_range日)の指数移動平均
  #datas::  値の配列
  #smoothing_coefficient:: 平滑化係数
  #戻り値:: macd値
  def macd( datas, short_range, long_range, smoothing_coefficient )
    ema( datas[ short_range*-1 .. -1], smoothing_coefficient ) \
      - ema( datas[ long_range*-1 .. -1], smoothing_coefficient )
  end

  #===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

  #===DMIを計算します。
  #
  # 高値更新  ...  前日高値より当日高値が高かった時その差
  # 安値更新  ...  前日安値より当日安値が安かった時その差
  # DM        ...  高値更新が安値更新より大きかった時高値更新の値。逆の場合は0
  # DM        ...  安値更新が高値更新より大きかった時安値更新の値。逆の場合は0
  # TR        ...  次の3つの中で一番大きいもの
  #                  当日高値-当日安値
  #                  当日高値-前日終値
  #                  前日終値-当日安値
  # AV(+DM)   ...  +DMのn日間移動平均値
  # AV(-DM)   ...  -DMのn日間移動平均値
  # AV(TR)    ...  TRのn日間移動平均値
  # +DI       ...  AV(+DM)/AV(TR)
  # -DI       ...  AV(-DM)/AV(TR)
  # DX        ...  (+DIと-DIの差額) / (+DIと-DIの合計)
  # ADX       ...  DXのn日平均値
  #
  #datas::  値の配列(4本値を指定すること!)
  #戻り値:: {:pdi=pdi, :mdi=mdi, :dx=dx }
  def dmi( datas )
    prev = nil
    tmp = datas.inject( [[],[],[]] ) {|r,i|
      if prev
        dm = _dmi( i, prev )
        r[0] << dm[0] # TR
        r[1] << dm[1] # +DM
        r[2] << dm[2] # -DM
      end
      prev = i
      r
    }
    atr = ma( tmp[0] )
    pdi = ma( tmp[1] ) / atr * 100
    mdi = ma( tmp[2] ) / atr * 100
    dx  = ( pdi-mdi ).abs / ( pdi+mdi )  * 100
    return {:pdi=>pdi, :mdi=>mdi, :dx=>dx }
  end

  #TR,+DM,-DMを計算します。
  #戻り値:: [ tr, +DM, -DM ]
  def _dmi( rate, rate_prev ) #:nodoc:
    pdm = rate.max > rate_prev.max ? rate.max - rate_prev.max : 0
    mdm = rate.min < rate_prev.min ? rate_prev.min - rate.min : 0

    if ( pdm > mdm )
      mdm = 0
    elsif ( pdm < mdm )
      pdm = 0
    end

    a = rate.max - rate.min
    b = rate.max - rate_prev.end
    c = rate_prev.end - rate.min
    tr = [a,b,c].max

    return [tr, pdm, mdm]
  end

  #===ROCを計算します。
  #Rate of Change。変化率。正なら上げトレンド、負なら下げトレンド。
  #
  #datas::  値の配列
  #戻り値:: 値
  def roc( datas )
    (datas.first - datas.last) / datas.last * 100
  end
end

以上是关于ruby 株の分析关数群的主要内容,如果未能解决你的问题,请参考以下文章

ruby 再帰处理で再试行してみる。データ取得は他の关数にやらせるといいかも。

php 配列操作关数

markdown SQL关数など

markdown 关数の生成

markdown 高阶关数

markdown 再帰关数の书き方