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

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

プラグインローダー

プラグインローダーを試作しました。

方針

  • プラグインはGemで。
    • せっかくなのでrubygemsを使って、プラグインを簡単に追加/削除できるようにしたい。
    • なので、gemの形式でプラグインを提供できるようにする。
      • gemにしておけばjijiへの組み込みも容易。jijiのgemspecで依存関係を設定すればよい。
      • プラグイン自体の依存モジュールもrubygemsで解決してインストール可能。
  • 拡張可能な機能は、必要に応じて順次追加できるようにしておく。
    • とりあえずは、「証券会社アクセスプラグイン」だけでいいかな。

プラグインロードの流れ

ということで、プラグインローダーでは以下のロジックでプラグインを検出しロードします。

  1. rubyのロードパス($LOAD_PATH)、およびインストールされている最新のgemのロードパス以下を探索し、
  2. "jiji_plugin.rb"を検出・ロード。
  3. "jiji_plugin.rb"内では、jijiのAPIを実行することで機能をjijiに登録します。

RubyGemsのプラグインの仕組みと似ていますが、「旧バージョンのgemのプラグインもロードされる」といろいろ問題が起きそうなので「最新のGemに含まれるプラグインのみロードする」仕組みにします。

実装

以下のとおり。

require 'rubygems'

module JIJI
  module Plugin
    
    @@registry = {}
    
    #プラグインを登録する。
    #future:: 機能の識別子
    #instance:: 機能を提供するプラグインインスタンス
    def self.register( future, instance )
      if @@registry.key? future 
        @@registry[future] << instance
      else
        @@registry[future] = [instance]
      end
    end
    
    #プラグインを取得する。
    #future:: 機能の識別子
    #return:: 機能を提供するプラグインの配列
    def self.get( future )
      @@registry.key?(future) ? @@registry[future] : []
    end
    
    # プラグインローダー
    class Loader 
      # プラグインをロードする。
      def load
        ($: + Gem.latest_load_paths).each {|dir|
          plugin = "#{dir}/jiji_plugin.rb"
          next unless File.exist? plugin
          begin 
            Kernel.load plugin
            server_logger.info( "plugin loaded. plugin_path=(#{plugin})" )
          rescue Exception
            server_logger.error( "plugin load failed. plugin_path=(#{plugin})" )
            server_logger.error($!)
          end
        }
      end
      attr :server_logger, true
    end
    
  end
end

以下のような内容の"jiji_plugin.rb"を含む適当なgemを作って、

JIJI::Plugin.register( :test, "aaa" )

「gem install」しておけば、「JIJI::Plugin::Loader#load」時に実行され、「:test」機能を提供するプラグインとして「"aaa"」が登録されます。