メッセージの送受信

API

導入

この記事は、SpotwareのcServerを使用してFIX APIを利用する方法に興味がある人々のための導入を目的としています。

以下の段落では、C#の例を使用して、FIXメッセージを構築し、サーバーに送信し、応答を受信する原則について詳しく説明します。

この例は、決して強固なアプリケーションではなく、FIX APIメッセージの使用の概念をプログラマーが簡単に理解できるようにするために、できるだけシンプルに保たれています。

適切な通信と応答の適切な処理を確立および維持するには、さらなる機能が必要ですが、これらは簡潔さと明確さを保つためにスキップされました。これらの主題については、将来の記事で取り扱います。

コードサンプル

この記事で説明されているコードサンプルは、こちらのGitHubリポジトリで見つけることができます: https://github.com/spotware/FIX-API-Sample

FIX通信の概要

FIXメッセージは、|で区切られた数値タグと値のセットからなる文字列です。各タグは、特定の値のセットが許可されている異なるフィールドを表します。以下は、サーバーから認証を要求するサンプルFIXメッセージです。

8=FIX.4.4|9=126|35=A|49=theBroker.12345|56=CSERVER|34=1|52=20170117- 08:03:04|57=TRADE|50=any_string|98=0|108=30|141=Y|553=12345|554=passw0rd!|10=131|

ご覧の通り、各FIXメッセージで見られる繰り返しパターンは次のとおりです:

Tag=Value|Tag=Value|Tag=Value|...

各メッセージの目的に応じて、異なるタグと値のセットが毎回必要です。各メッセージに必要なタグと値についての詳細は、cTrader FIX Engine Rules of Engagementに記載されています(常に最新のルールを確認してください)。

同様に、サーバーからの応答も送信されます。以下は、上記メッセージのサーバーからの応答です。

8=FIX.4.4|9=106|35=A|34=1|49=CSERVER|50=TRADE|52=20170117- 08:03:04.509|56=theBroker.12345|57=any_string|98=0|108=30|141=Y|10=066|

FIXサーバーとの通信プロセスに関与する手順は次のとおりです:

  1. FIXメッセージの構築

  2. FIXメッセージの送信

  3. FIXメッセージの受信

  4. FIXメッセージの解析

生のFIXメッセージは非常に読み取りにくい形式です。理解可能さよりも効率を重視して設計されています。

したがって、各ソフトウェアアプリケーションには、提供された情報を対応するFIXメッセージに変換するプロセスが常にあります。

私たちのC#のサンプルアプリケーションでは、メッセージの構築を処理するためのクラスと、関連情報に基づいてFIXメッセージを作成するための関数を作成しました。

メッセージが構築された後、それらはネットワークソケットを介してサーバーとクライアント間でインターネット経由で送信されます。メッセージを受信したら、読み取り可能な形式に解析する必要があります。

この記事では、応答の構築、送信、および受信のプロセスをカバーします。解析については、将来の記事で取り扱います。

FIXメッセージの構築

メッセージの構造

サンプルアプリケーションでは、FIXメッセージを作成する責任を持つクラスを作成しました。そのクラスはMessageConstructorと呼ばれ、FIX APIライブラリプロジェクトで見つかります。

MessageConstructorは次のパラメーターで初期化されます:

  1. Host(*): cServerが配置されているアドレス。

  2. Username(*): アカウント番号。

  3. Password(*): パスワード。

  4. SenderCompID(*): cTraderのFIX API形式で提供されます。フォーマットはです。

  5. SenderSubID: SenderCompIDの2番目の部分です。

  6. TargetCompID(*): cTraderのFIX API形式で提供されます。通常、cServerです。

この情報は、cTrader FIX APIフォームで見つけることができます。

MessageConstructorを初期化した後、FIX APIメッセージを構築する準備が整います。

すべてのメッセージは同様の方法で構築されます。以下にログオンメッセージのコードサンプルがあります。

All the messages are constructed in a similar manner. Below there is a code sample of constructing a logon message.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public  string LogonMessage(SessionQualifier qualifier, int messageSequenceNumber,

            int  heartBeatSeconds,  bool  resetSeqNum)

       {

            var  body = new  StringBuilder ();

        //Defines a message encryption scheme.Currently, only transportlevel security

       //is supported.Valid value is "0"(zero) = NONE_OTHER (encryption is not used).

           body.Append( "98=0|");

            //Heartbeat interval in seconds. 

           //Value is set in the 'config.properties' file (client side) as 

         // 'SERVER.POLLING.INTERVAL' . 

           //30 seconds is default interval value. If HeartBtInt is set to 0, 

         no heartbeat message  

           //is required.

           body.Append( "108="  + heartBeatSeconds +  "|");

           // All sides of FIX session should have

           //sequence numbers reset. Valid value

            //is "Y" = Yes(reset). 

            if  (resetSeqNum)

               body.Append( "141=Y|");

            //The numeric User ID.  User is linked to SenderCompID (#49) value (the

            //user's organization). 

           body.Append( "553=" + _username + "|");

           //USer Password

           body.Append( "554=" + _password + "|");

            var  header = ConstructHeader(qualifier, 

         SessionMessageCode( SessionMessageType.Logon), messageSequenceNumber,

          body.ToString());

            var  headerAndBody = header + body;            

            var  trailer = ConstructTrailer(headerAndBody);

            var  headerAndMessageAndTrailer = header + body + trailer;

            return  headerAndMessageAndTrailer.Replace("|", "\u0001");

       }

 

上記のように、まず本文部分を構築し、それをヘッダー関数に渡し、最後に両方の部分をトレーラー関数に渡します。次の段落でこれらの三つの部分を詳細に見ていきます。

メッセージ構築プロセスは、必要なタグ、値、および区切り記号を文字列に追加するだけです。

ボディ

まず、メッセージの本文構築について説明します。メッセージの本文は最初に作成する必要があるためです。上記の例、つまりログオンメッセージの作成を見てみましょう。

StringBuilderクラスを初期化し、関数の入力に基づいてタグを1つずつ追加します。メッセージの種類に応じて、本文は異なるタグのセットで構成される必要があり、そのうちのいくつかは必須であり、他のいくつかはオプションです。

各メッセージの構造は、エンゲージメントルール(/FIX)で見つけることができます。

次に、ログオンメッセージのヘッダーを作成し、そのメッセージの本文を追加します。最後に、headerAndBody文字列を使用してトレーラーを生成します。次に、ヘッダーとトレーラーの構築方法を見ていきます。

ヘッダーはFIXメッセージの最初の部分であり、次のフィールドで構成されています(すべてのメッセージに共通です):

  1. BeginString: BeginStringはFIXプロトコルバージョンを定義し、私たちの場合はFIX4.4に固定されています
  2. BodyLength: BodyLengthは、BeginString、BodyLength、およびTrailerフィールドを除いたメッセージの長さを文字数で指定します。
  3. MsgType: このフィールドでは、メッセージの種類を定義し、受信者が本文を解析する方法を知ることができます。
  4. SenderCompID: ここではSenderCompIDを設定します
  5. TargetCompID: これがメッセージのターゲットです。私たちの場合、常にCSERVERになります。
  6. SenderSubID: トレーダーのログインです。
  7. MsgSeqNum: これはメッセージのシーケンス番号です。同じセッションで送信される各メッセージごとに増加する必要があります。
  8. Sending Time: メッセージの送信時刻。

以下に、ヘッダーを構築する責任を持つConstructHeader関数を示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
private  string ConstructHeader(SessionQualifier qualifier, string type,

         int  messageSequenceNumber, string bodyMessage)

    {

         var  header = new  StringBuilder ();

        // Protocol version. FIX.4.4 (Always unencrypted, must be first field 

        // in message.

        header.Append( "8=FIX.4.4|");

         var  message = new  StringBuilder ();

        // Message type. Always unencrypted, must be third field in message.

        message.Append( "35=" + type + "|");

        // ID of the trading party in following format: <BrokerUID>.<Trader Login> 

        // where BrokerUID is provided by cTrader and Trader Login is numeric 

        // identifier of the trader account.

        message.Append( "49="  + _senderCompID +  "|");  

        // Message target. Valid value is "CSERVER"

        message.Append( "56="  + _targetCompID +  "|");  

        // Additional session qualifier. Possible values are: "QUOTE", "TRADE".

        message.Append( "57="  + qualifier.ToString() +  "|");  

        // Assigned value used to identify specific message originator.

        message.Append( "50="  + _senderSubID +  "|");

        // Message Sequence Number

        message.Append( "34="  + messageSequenceNumber +  "|");

         // Time of message transmission (always expressed in UTC(Universal Time  

        // Coordinated, also known as 'GMT').

        message.Append("52=" + DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss") + "|");

         var  length = message.Length + bodyMessage.Length;

        // Message body length. Always unencrypted, must be second field in message.

        header.Append( "9=" + length + "|");

        header.Append(message);      

         return  header.ToString();

    }

トレーラー

トレーラーは、メッセージの残り部分のチェックサムを含むタグです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
private  string ConstructTrailer(string message)

       {

            //Three byte, simple checksum.  Always last field in message; i.e. serves,

           //with the trailing<SOH>, 

           //as the end - of - message delimiter. Always defined as three characters

           //(and always unencrypted).

            var  trailer = "10=" + CalculateChecksum(message.Replace("|", "\u0001").ToString()).ToString().PadLeft(3, '0') + "|";

            return  trailer;

       }

システムメッセージ

当サンプルには、以下のシステムメッセージを返す関数が含まれています:

  • Heartbeat: MessageConstructor.HeartbeatMessage()
  • Test Request: MessageConstructor.TestRequestMessage()
  • Logon: MessageConstructor.LogonMessage()
  • Logout: MessageConstructor.LogoutMessage()
  • Resend Request: MessageConstructor.ResendMessage()
  • Reject: MessageConstructor.RejectMessage()
  • Sequence Reset: MessageConstructor.SequenceResetMessage()

アプリケーションメッセージ

当サンプルには、以下のアプリケーションメッセージを返す関数が含まれています:

  • Market Data Request: MessageConstructor.HeartbeatMessage()
  • Market Data Snapshot/Full Refresh: MessageConstructor.MarketDataSnapshotMessage()
  • Market Data Incremental Refresh: MessageConstructor.MarketDataIncrementalRefreshMessage()
  • New Order Single: MessageConstructor.NewOrderSingleMessage()
  • Order Status Request: MessageConstructor.OrderStatusRequest()
  • Execution Report: MessageConstructor.ExecutionReport()
  • Business Message Reject: MessageConstructor.BusinessMessageReject()
  • RequestForPositions: MessageConstructor.RequestForPositions()
  • Position Report: MessageConstructor.PositionReport()

メッセージの送信と応答の受信

cServerにFIXメッセージを送信するには、まずサーバーとの接続を確立する必要があります。これはTcpClientを作成することで行うことができます。私たちの場合、価格引用メッセージと取引メッセージはサーバー上の異なるポートで処理されるため、2つのクライアントを作成します。

次に、メッセージが送信される2つのストリームを取得する必要があります。このプロセスは、以下に示すようにフォームのコンストラクタで行われます:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public  frmFIXAPISample()
{

   InitializeComponent();

    _priceClient = new  TcpClient( _host, _pricePort);           

   _priceStream = _ priceClient.GetStream ();            

   _tradeClient =  new  TcpClient ( _host, _tradePort);

   _tradeStream = _ tradeClient.GetStream ();

   _messageConstructor = new  MessageConstructor( _host, _username,

       _password, _senderCompID, _senderSubID, _targetCompID);
}

コンストラクターでは、メッセージを生成するために使用されるMessageConstructorクラスも初期化します。

次に、メッセージを送信するために、SendPriceMessage() とSendTradeMessage() の2つの異なる関数を作成しました。それぞれがFIXメッセージを入力として受け取り、その後、メッセージと対応するストリームを入力としてSendMessage() 関数を呼び出します。

SendMessage() 関数は以下のように動作します:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private  string SendMessage(string message,  NetworkStream  stream)
{
    var  byteArray =  Encoding.ASCII.GetBytes (message);

    stream.Write(byteArray, 0, byteArray.Length);

    var  buffer = new byte[1024];

    int  i = 0;

    while  (!stream.DataAvailable && i < 100)
    {
         Thread.Sleep ( 100);
         i++;
    }

    if( stream.DataAvailable )
        stream.Read(buffer, 0, 1024);

    _messageSequenceNumber++;

    var  returnMessage = Encoding.ASCII.GetString(buffer);

    return  returnMessage;
}

In detail the steps are the following

  1. Encode the message to a byte array.
  2. Write the byte array on the stream.
  3. Read the reply from the stream.
  4. Increase the message sequence number.
  5. Encode the message into string.

詳細な手順は次のとおりです:

  1. メッセージをバイト配列にエンコードします。
  2. ストリームにバイト配列を書き込みます。
  3. ストリームから返信を読み取ります。
  4. メッセージのシーケンス番号を増加させます。
  5. メッセージを文字列にエンコードします。

この関数はサーバーから送信されたFIXメッセージを返す必要があります。

推測されるように、生のFIXメッセージをユーザーに表示することはできないため、受信メッセージを解析するための追加のステップを開発する必要があります。

結論

このアプリケーションは、FIXメッセージを使用してcServerと通信する方法を簡単に示すものです。これはFIXプロトコルの概念を説明するための例であり、完全なFIXエンジンではありません。独自のFIXエンジンを構築するのを避けたい場合は、市販の3rdパーティのFIXエンジンの利用を検討することもできます。

注記

この記事は2017年2月3日時点で最新であり、cTrader FIX Engine, Rules of Engagement v2.9.1を念頭に置いて開発されています。

このページについて