QuickFIX/Jソースコードリーディング

QuickFIX/Jソースコードリーディング

QuickFIX/Jとは

QuickFIX/JはFIXエンジンの実装になります。FIXエンジン自体が聞きなれないと思いますが、FIXエンジンは電子取引で使われるプロトコルであるFIXプロトコルの実装になります。FIXエンジンについては以下のリンクが参考になります。
https://javarevisited.blogspot.com/2012/01/what-is-fix-engine-in-fix-protocol.html

QuickFIX/Jの公式ページによると、もともとC++で実装されたQuickFIXをJavaで実装しなおしたもののようです。

サンプルアプリケーションのリクエスト周りの実装をたどってみる

QuickFIX/Jの実装はこちらから確認できるのですが、quickfixj-examplesがサンプルの実装になりますので動かしながらFIXプロトコルの具体的な流れをつかんでいきたいと思います。examplesのディレクトリにexecutorとbanzaiがあるのですがexecutorは注文を受け付ける方でbanzaiは注文を投げるクライアント側になります。

FIXプロトコルでのリクエストはApplication.javaインターフェースを実装したクラスで実行していてbanzaiとexecutorでもそれぞれ実装したクラスがあり、banzaiこちらになりexecutorはこちらになります。

リクエストを受け取った後はApplicationインターフェースのfromAppやfromAdminのメソッドを実行していて、注文を受ける側のexecutorではfromApp関数内で crack(message, sessionID); を呼び出していますがcrack関数ではリフレクションを使ってリクエスト元のFIXプロトコル毎の関数を呼び出すようにしています。

Applicationの初期化と各種設定の初期化をした後はソケットの初期化を行っていまして、注文を受ける側のexecutorの初期化は以下のようになっていまして

acceptor = new SocketAcceptor(application, messageStoreFactory, settings, logFactory,
 messageFactory);

注文を投げる側のbanzaiは以下のように初期化しています。

initiator = new SocketInitiator(application, messageStoreFactory, settings, logFactory, messageFactory);

それぞれのソケットの初期はでは以下のようにSingleThreadedEventHandlingStrategyを初期化していまして、

eventHandlingStrategy = new SingleThreadedEventHandlingStrategy(this, DEFAULT_QUEUE_CAPACITY);

SingleThreadedEventHandlingStrategyではqueueTrackerというリクエストキューがあり、リクエストが来たらblock関数のwhileループ内にあるevent.processMesssageを呼び出しており、ここからAplicationインターフェース実装クラスの各メソッドが呼び出されるようになっています。

リクエストキューにイベント追加しているのはこちらになるのですが、呼び出し元はAbstractIoHandler.javaのmessageReceivedになっていましてAbstractIoHandlerはApache MINAのIoHandlerAdapterを実装しているので、ソケットの初期化後messageReceivedが呼び出されるようになっています。

Apache MINAはネットワークアプリケーションを作るためのフレームワークApache sshdApache MINAで実装されています。QuickFIX/Jではqucikfix.minaパッケージにネットワーク周りの実装がまとめられています。

サンプルを動かしてFIXプロトコルを追ってみる

サンプルを動かしてFIXプロトコルのやり取りを追ってみたいと思います。注文を投げる側のexecutorをデバックで止めて確認してみました。executorとbanzaiを初期化後executorは以下のようなリクエストを受け取ります。

8=FIX.4.49=6635=A34=4949=BANZAI52=20200216-03:24:47.48756=EXEC98=0108=3010=028

区切り文字は文字コード\01になっていまして、エディタによってスペースや文字化けのように見えているかと思います。8=FIX.4.4はFIXプロトコルの内FIX4.4が使われるのを意味していまして、各キーは以下のようになっています。

8 -> BeginString
9 -> BodyLength
35 -> MsgType
34 -> MsgSeqNum 
49 -> SenderCompID
52 -> SendingTime 
56 -> TargetCompID
98 -> EncryptMethod
108 -> HeartBtInt
10 -> CheckSum

35=AというのはLogonメッセージというのを意味していまして、FIXプロトコルの最初に投げるリクエストになっています。 https://www.onixs.biz/fix-dictionary/4.4/msgs_by_msg_type.html

Logonメッセージ時にのセッション情報はSession.javaのsessionでSessionID毎で保持するようになっています。SessionIDはBeginString,TargetCompID,SenderCompIDを繋げたものになっていまして 8=FIX.4.49=6635=A34=4949=BANZAI52=20200216-03:24:47.48756=EXEC98=0108=3010=028 のLogonメッセージに対するSessionIDは FIX.4.4:EXEC->BANZAI になります。これで注文時のリクエスト元を判別できるようになっています。

それから、注文を投げるときは以下のようなリクエストが投げられており

8=FIX.4.29=12735=D34=34449=BANZAI52=20200216-06:05:41.92956=EXEC11=158183314190421=138=240=154=155=symbol59=060=20200216-06:05:41.92710=172

注文に対する返答として、以下のようなレスポンスを返します。

8=FIX.4.49=9235=86=12.311=158184178116814=117=3631=12.332=137=3638=139=254=155=symbol150=2151=010=167

FIXエンジンの説明ページでFIXエンジンの役割として以下が挙げられていますが、とりあえず4の部分だけであれば実装がしやすそうなのでRustとかで書いてみたら面白いのかと思いました。

1) Establish Fix Connectivity by sending session level messages.
2) manage FIX Session
3) recover if FIX session lost
4) creating, sending, parsing FIX messages for electronic trading.
5) handles replay
6) supports different FIX (Financial information exchange) protocol version and tags.