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

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

JSONBrokerのJavaScriptクライアントを書いた

だいぶ前のエントリ、「RubyクラスをJSONでアクセスできるWebサービス化する」で作ったJSONBrokerのJavaScriptクライアントを書きました。

  • (前置き)JSONBrokerは任意のRubyクラスのAPIJSONでアクセスできるWebサービスとして公開するための簡易ユーテイリティです。
  • JavaScriptクライアントを使うと、JavaScriptAPIから対応するサーバーサービスのAPIを呼び出す、クライアントスタブを生成できます。
    • スタブは、公開されているサービス情報を元に生成されます。(サーバー側のオブジェクトのpublic_methodsを呼び出して、メソッド一覧を取得して作成。)
    • 引数のJSON化などの処理が内部に隠蔽されます。ちょっと楽。

サンプル

まずはサーバー側です。JSONBrokerで、KittenAnalysisServiceのAPIWebサービスとして公開します。

require "json-broker"

class KittenAnalysisService
  def analysis( kitten )
    kitten["type"] = kitten["name"] =~ /mii/ ? "Mike" : "Egyptian"
    return kitten
  end
end

JSONBroker::Cgi.invoke KittenAnalysisService.new

これで、メソッドと引数をJSONで指定してURLにアクセスすると、KittenAnalysisServiceが実行され、結果がJSONで返されるようになります。

http://unageanu.sakura.ne.jp/blog-samples/071210/service.cgi?request={"method":"analysis", "params":[{"name":"mii", "age":2}]}

↑の実行結果です。

[{"error":null, "result":{"name":"mii","type":"Mike","age":2}}]

このサービスに、クライアントスタブを使ってアクセスしてみます。「JSONBrokerClientFactory.create」でスタブが生成されコールバックされるので、それのAPIを呼び出すだけ。

// スタブを生成
// スタブはハンドラにコールバックされる。
JSONBrokerClientFactory.create( "./service.cgi", function( stub ){

    // スタブのAPI呼び出し。
    // 呼び出しは非同期。Ruby側のAPIの引数+コールバックハンドラを指定する。
    stub.analysis( {name:"mii", age:1}, function( result ) {
        stdout.innerHTML += result["name"] + "/" + result["type"] + "/" +result["age"] + "<br/>";
    }, onError );
    

}, onError);

API呼び出しに応じて内部で送信するデータの作成と送付が行われ、結果がコールバックされてきます。
確認はこちらから。

所感

  • スタブの生成とか、スタブのメソッド呼び出しがいちいち非同期処理なのがめんどくさい感じ。せめてスタブの生成くらいは同期化したい。
    • 公開メソッド一覧を得るためにサーバーに接続していて、そのために非同期になっている。
    • rubyの「method_missing」みたいなのがあれば何とかなるんだけど。

クライアントのソース

一応、公開。サーバー側は「RubyクラスをJSONでアクセスできるWebサービス化する」を参照ください。

JSONBrokerClientFactory = {
    /**
     * JSONBrokerのクライアントスタブを生成する。
     * @param {String} url JSONBrokerのURL
     * @param {Object} successCallback 成功時のコールバック先
     * @param {Object} errorCallBack エラー時のコールバック先
     */
    create: function( url, successCallback, errorCallBack ) {
        JSONBrokerClientFactory._call( url, "public_methods", [], function( list ) {
            var stub = {};
            for ( var i=0; i<list.length; i++ ) {
                stub[list[i]] = JSONBrokerClientFactory._createFunction( url, list[i] );
            }
            if ( successCallback ) { successCallback( stub );}
        }, errorCallBack );
    },
    _createFunction: function( url, method ) {
      return function( ) {
          var errorCallBack   = Array.prototype.pop.apply( arguments, [] );
          var successCallback = Array.prototype.pop.apply( arguments, [] );
          var args = [];
          for ( var i=0; i<arguments.length; i++ ) {
              args.push( arguments[i] );
          }
          JSONBrokerClientFactory._call( url, method,
              args, successCallback, errorCallBack );
      };
    },
    _call: function( url, method, args, successCallback, errorCallBack ) {
        var sendData = 'request='
            +  '{ "method":"' + method + '", "params":' + YAHOO.lang.JSON.stringify(args) + '}';
        var callback = {
          success: function( response ) {
            var data = YAHOO.lang.JSON.parse(response.responseText);
            if ( !data[0] || data[0]["error"] ) {
                if ( errorCallBack ) {
                    errorCallBack( data );
                }
            } else {
                if ( successCallback ) {
                    successCallback(data[0]["result"]);
                }
            }
          },
          failure: errorCallBack
        };
        // リクエストの送付
        var ajax = YAHOO.util.Connect.asyncRequest('POST', url, callback, sendData );
    }
}