Tana Gone
Tana Gone
1 min read

Categories

株価分析ソフトを作る際に利用されるTA-LibをRubyから活用する方法を説明する。この記事では移動平均を算出するTA_MA関数を例にまずはC言語から呼出すコードを掲載し、更にRubyからも呼出すコードも示す。

C/C++ API - TA-Lib - Technical Analysis Library

C言語から読み出すコード。

#include "ta-lib/ta_func"
TA_Initialize()
TA_Real    closePrice[400];
TA_Real    out[400];
TA_Integer outBeg;
TA_Integer outNbElement;
/* ... initialize your closing price here... */
retCode = TA_MA( 0, 399,
                 &closePrice[0],
                 30,TA_MAType_SMA,
                 &outBeg, &outNbElement, &out[0] );
/* The output is displayed here */
for( i=0; i < outNbElement; i++ )
   printf( "Day %d = %f\n", outBeg+i, out[i] );

同じ事をRubyで行うコード

配列へのPointerを受け取るC言語関数(ta-lib)をRubyから呼出す方法の要点

  1. PointerはRubyのオブジェクトFiddle::Pointer.mallocメソッドにサイズを与えて取得
  2. PointerはRubyではバイト列(String)のオブジェクト
  3. String.unpackメソッドで配列が取得できる
  require 'fiddle'
  require 'fiddle/import'
  
  # TA-Libの関数を扱うモジュールを定義
  module TALib
    extend Fiddle::Importer
  
    # 共有ライブラリをロード(環境に応じてパスを調整)
    dlload 'libta_lib.dylib' # Linux/macOSの場合。Windowsなら 'ta_lib.dll'
  
    # TA-Libの型定義
    TA_Real = Fiddle::TYPE_DOUBLE
    TA_Integer = Fiddle::TYPE_INT
  
    # TA_MA関数のシグネチャを定義
    extern 'int TA_Initialize()'
    extern 'int TA_MA(int startIdx, int endIdx, double *inReal, int optInTimePeriod, int optInMAType, int *outBegIdx, int *outNbElement, double *outReal)'
  end
  
  # サンプルデータと計算
  def calculate_moving_average
    # TA-Libの初期化
    ret = TALib.TA_Initialize()
    raise "TA_Initialize failed with code #{ret}" unless ret == 0
  
    # クローズ価格データの準備(仮のデータ)
    # close_prices = Array.new(10) { |i| rand(100.0..200.0) } # 400個のダミーデータ
    close_prices = Array.new(10) { |i| i * 10.0 } # 10個のダミーデータ
    in_real = Fiddle::Pointer[close_prices.pack('d*')] # double型の配列に変換
  
    # 出力用の配列と変数を準備
    out_real = Fiddle::Pointer.malloc(10 * Fiddle::SIZEOF_DOUBLE) # 出力配列
    out_beg_idx = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT) # 開始インデックス
    out_nb_element = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT) # 出力要素数
  
    # TA_MA関数の呼び出し
    ret = TALib.TA_MA(
      0,              # startIdx
      9,            # endIdx
      in_real,        # inReal (入力データ)
      4,             # optInTimePeriod (期間)
      0,              # optInMAType (0 = SMA)
      out_beg_idx,    # outBegIdx (出力開始インデックス)
      out_nb_element, # outNbElement (出力要素数)
      out_real        # outReal (出力データ)
    )
  
    raise "TA_MA failed with code #{ret}" unless ret == 0
  
    # 結果の取得
    out_beg = out_beg_idx[0, Fiddle::SIZEOF_INT].unpack('i')[0]
    nb_element = out_nb_element[0, Fiddle::SIZEOF_INT].unpack('i')[0]
    out = out_real[0, nb_element * Fiddle::SIZEOF_DOUBLE].unpack('d*')
    # unpackメソッドはバイト列をオブジェクト配列へ変換する。out_beg_idx, out_nb_elementは
    # Fiddle::Ponterオブジェクト
    
    # 結果を表示
    nb_element.times do |i|
      puts "Day #{out_beg + i} = #{out[i]}"
    end
  end

# メモリ解放
  out_real.free
  out_beg_idx.free
  out_nb_element.free

  # 実行
  begin
    calculate_moving_average
  rescue => e
    puts "エラー: #{e.message}"
  end

see source of import.rb and struct.rb, then search Example. fiddle/lib/fiddle at master · ruby/fiddle