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

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

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

RubyクラスをJSONでアクセスできるWebサービス化するJSONBrokerJava版クライアントを書いてみました。

サンプル

以下はクライアントを使ってjijiにアクセスし、レート情報を取得するサンプルです。

/**
 * レート情報を提供するサービス
 */
static interface RateService {
    
    /**
     * 指定期間のレート一覧を取得する
     * @param pair 通貨ペア
     * @param scale 4本値
     * @param start 開始日時
     * @param end 終了日時
     * @return レート一覧
     */
    List<List<Double>> list( String pair, String scale, long start, long end );

}
....
// サービスを作る。
RateService service = JsonRpcClient.create(RateService.class, 
        new URL( "http://unageanu.homeip.net/jiji-demo/json/rate" ));

// サービスのAPIを実行。
Calendar c = Calendar.getInstance( TimeZone.getTimeZone("JST") );
c.set(2009, 3, 1, 0, 0, 0);
long start = c.getTimeInMillis()/1000;
List<List<Double>> rates = service.list("EURJPY", "1h",  start, start+24*60*60 );
for ( List<Double> rate : rates ) {
    System.out.println( rate );
}

実行結果です。何をやっているのかの詳細はこちらを参照

[131.34, 131.07, 131.34, 130.69, 1238508000, 1238511600]
[131.12, 131.44, 131.67, 130.85, 1238511600, 1238515200]
[131.45, 131.43, 131.51, 131.21, 1238515200, 1238518800]
[131.42, 131.27, 131.55, 131.26, 1238518800, 1238522400]
[131.28, 131.61, 131.67, 131.26, 1238522400, 1238526000]
[131.64, 131.48, 131.85, 131.39, 1238526000, 1238529600]
[131.48, 131.13, 131.51, 131.07, 1238529600, 1238533200]
[131.12, 130.96, 131.13, 130.83, 1238533200, 1238536800]
[130.93, 131.16, 131.32, 130.93, 1238536800, 1238540400]
[131.11, 131.67, 131.81, 131.0, 1238540400, 1238544000]
[131.64, 130.18, 131.64, 129.99, 1238544000, 1238547600]
[130.22, 130.85, 131.22, 130.22, 1238547600, 1238551200]
[130.8, 130.65, 130.8, 130.4, 1238551200, 1238554800]
[130.65, 130.36, 130.65, 130.19, 1238554800, 1238558400]
[130.36, 130.13, 130.37, 129.89, 1238558400, 1238562000]
[130.15, 130.31, 130.42, 129.97, 1238562000, 1238565600]
[130.24, 130.38, 130.63, 130.05, 1238565600, 1238569200]
[130.42, 130.12, 130.68, 129.93, 1238569200, 1238572800]
[130.16, 130.56, 130.61, 130.0, 1238572800, 1238576400]
[130.54, 131.09, 131.12, 130.46, 1238576400, 1238580000]
[131.06, 131.24, 131.24, 130.96, 1238580000, 1238583600]
[131.22, 130.93, 131.31, 130.89, 1238583600, 1238587200]
[130.94, 130.69, 131.04, 130.61, 1238587200, 1238590800]
[130.69, 130.7, 130.77, 130.5, 1238590800, 1238594400]
[130.86, 130.7, 131.31, 130.7, 1238594400, 1238598000]

実装

ライブラリの実装は以下。タイプセーフ具合とか、いろいろ適当ですが。あとJSONICに依存しています。

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;

import net.arnx.jsonic.JSON;

/**
 * JSON-RPC クライアント
 */
public class JsonRpcClient {

    /**
     * アクセスクライアントを作成する
     * @param <X> クライアントの型
     * @param service クライアントインターフェイス
     * @param endpoint エンドポイントURL
     * @return アクセスクライアント
     */
    @SuppressWarnings("unchecked")
    public static <X> X create( Class<X> service, URL endpoint ) {
        return (X) Proxy.newProxyInstance( Thread.currentThread().getContextClassLoader(),
            new Class[] {service}, new JsonRpcInvocationHandler(endpoint) );
    }

    private static final class JsonRpcInvocationHandler
    implements InvocationHandler {
        private URL endpoint;
        private JsonRpcInvocationHandler( URL endpoint ) {
            this.endpoint = endpoint;
        }
        @Override @SuppressWarnings("unchecked")
        public Object invoke ( Object proxy, Method method, Object[] args )
        throws Throwable {
            StringBuilder sb = new StringBuilder("{");
            sb.append( "\"method\":").append( method.getName() ).append( "," );
            sb.append( "\"params\":").append( JSON.encode(args) ).append( "}" );
            HttpURLConnection c = null;
            try {
                c = (HttpURLConnection) endpoint.openConnection();
                c.setRequestMethod( "POST" );
                c.setDoOutput(true);
                c.connect();
                OutputStream out = null;
                try {
                    out = c.getOutputStream();
                    OutputStreamWriter osw = new OutputStreamWriter( out, "UTF-8" );
                    osw.write( sb.toString() );
                    osw.flush();
                } finally {
                    if ( out != null ) out.close();
                }
                InputStream in = null;
                try {
                    in = c.getInputStream();
                    List<Object> list = (List<Object>) JSON.decode( in ) ;
                    Map<String, Object> res = (Map<String, Object>) list.get(0);
                    if ( res.get( "error" ) != null )  {
                        throw new RuntimeException( String.valueOf( res.get( "error" ) ) );
                    } else {
                        return res.get( "result" );
                    }
                } finally {
                    if ( in != null ) in.close();
                }
            } catch ( IOException e ) {
                throw e;
            } finally {
                if ( c != null ) c.disconnect();
            }
        }
    }
}

ちなみに、JavaScript版クライアントはこちらActionScript版クライアントはこちらにあります。