コバのシステムトレード構築日記(Dukascopy他)

IB証券/DukascopyとのAPI接続ナレッジや、トレステなど

IB証券:API接続検証その4「クラスオブジェクトの、どこから手をつけるか」

(以下は Java限定。他の言語でも似たようなオブジェクトデザインなので参考程度に。)

 

IB証券へのAPI接続には、"IB Gateway"というプログラムを Windows or Linux/Macの環境で起動すると IDとパスワードを打ち込み "IB Gateway"が、IB証券に繋がるので、自分で作るプログラムはこの "IB Gateway"に接続する形になります。

自作PG(デモプログラムも同じ) → IB Gateway → IB証券

24時間/365日OKみたいです。たまに切れて再接続してます。

 

サンプルソースコードは、この IB Gatewayに、接続して リアルタイムや 履歴データを取得するプログラムそのものになっていました。

 

開発環境への取り込み:

私の環境は eclipseです。

eclipseってなんじゃ?という人はググって使って慣れてください。何でも出来る系の開発環境なので敷居が高く感じますが根性で乗り切りましょう。

D:\TWS API\source\JavaClient\com\ib

ディレクトリパスにある、3つのパスにある javaファイルをパッケージとしてインポートします。

com.ib.client

com.ib.contracts

com.ib.controller

です。ぜんぶで68ファイルぐらいあります。

警告が出たりしたら適当に直すか、エラーでは無い限り放置で良いかと思います。

セッション確立のあたりはサンプルを見ればなんとか解ると思います。

 

結論から先に書くと、com.ib.controller.ApiController クラスを継承して新しいクラスを作成し、履歴データやリアルタイムデータが返ってくるメソッドをオーバーライドして必要な処理を実装すればOKです。

オンラインドキュメントでは、EReaderSignalオブジェクトを EJavaSignalクラスでインスタンス化して、EClientSocketクラスに EWrapperインターフェースを実装して作成したクラスもインスタンス化して渡せば、EWrapperインターフェースクラスの実装メソッドにデータが返ってくるように読めますが、素直にそういうのを作ってやっても返ってきません。(汗)

ApiControllerクラスがすでにその条件のもとに作成されているので、多少使わない機能実装があったとしてもそのまま使うのが吉かと思います。

 

重要なクラスの一つが、ApiControllerです。

履歴データ取得専用の新たなクラスを作るとすると、こんな感じです。

public class ibController extends ApiController {

  /** とりあえずコンストラクタはそのまま上位を呼び出し。 */
    public ibController(IConnectionHandler handler, ILogger inLogger, ILogger outLogger) {
        super(handler, inLogger, outLogger);
    }
    
    /**
     */
    @Override
    public void historicalData(int reqId, String date, double open, double high, double low, double close, int volume, int count, double wap, boolean hasGaps) {
        //上位メソッド呼び出し。
        super.historicalData(reqId, date, open, high, low, close, volume, count, wap, hasGaps);
        //データ処理(上位メソッドの条件判定の一部をそのままコピペ。ApiControllerを修正したくないので)
        if (date.startsWith( "finished")) {

            //ここに指定条件の全てを取得後の処理、たとえばトランザクションのコミットなどを書く。
            System.out.println("IB historical data received end:");
        }
        else {
            long longDate;
            if (date.length() == 8) {
                int year = Integer.parseInt( date.substring( 0, 4) );
                int month = Integer.parseInt( date.substring( 4, 6) );
                int day = Integer.parseInt( date.substring( 6) );
                longDate = new GregorianCalendar( year - 1900, month - 1, day).getTimeInMillis() / 1000;
            }
            else {
                longDate = Long.parseLong( date);
            }

            //Date型への変換用に1000倍して戻す。
            Date dt = new Date(longDate*1000);

            //ここで1件ずつデータがやってくるので persistするか、コミット用にためるなどの処理を書く。
            System.out.println("IB historical data received:" + reqId + ":" + date + ":" + dt + ":" + open + ":" + high  + ":" + low  + ":" + close  + ":" + volume  + ":" + count  + ":" + wap  + ":" + hasGaps);
        }
    }


}