Lewati ke isi

Mengirim dan menerima pesan

Pendahuluan

Artikel ini berfungsi sebagai pengantar untuk menggunakan FIX API bagi siapa pun yang tertarik untuk berinteraksi dengan Spotware cServer menggunakan FIX.

Dalam artikel ini, kita akan menggunakan contoh C# untuk menjelaskan secara rinci prinsip-prinsip bagaimana cara membuat pesan FIX, mengirimkannya ke server, dan menerima responsnya. Contoh ini sama sekali bukan aplikasi yang sempurna dan dibuat sesederhana mungkin agar programmer dapat dengan mudah memahami konsep penggunaan pesan FIX API.

Untuk membangun dan mempertahankan komunikasi yang tepat dengan server dan penanganan respons yang benar, diperlukan fungsionalitas tambahan, yang dilewatkan demi kesederhanaan dan kejelasan. Kita akan membahas subjek-subjek ini dalam artikel-artikel mendatang.

Contoh kode

Anda dapat menemukan contoh kode yang dibahas dalam artikel ini di repositori GitHub kami

Ikhtisar komunikasi FIX

Pesan FIX hanyalah sebuah string yang terdiri dari kumpulan tag numerik dan nilai yang dipisahkan oleh garis vertikal (|). Setiap tag mewakili bidang yang berbeda di mana serangkaian nilai tertentu diizinkan. Di bawah ini Anda dapat melihat contoh pesan FIX yang meminta otentikasi dari server.

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|

Seperti yang Anda lihat, pola yang berulang ditemukan dalam setiap pesan FIX adalah:

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

Tergantung pada tujuan masing-masing pesan, serangkaian tag dan nilai yang berbeda diperlukan setiap kali. Tag dan nilai yang diperlukan untuk setiap pesan dijelaskan secara rinci dalam Rules of Engagement mesin FIX cTrader (selalu periksa rules of engagement terbaru).

Dengan cara yang sama, respons dikirim kembali dari server. Di bawah ini Anda dapat melihat respons server untuk pesan di atas.

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|

Langkah-langkah yang terlibat dalam proses komunikasi dengan server FIX adalah sebagai berikut:

  1. Membuat pesan FIX

  2. Mengirimkan pesan FIX

  3. Menerima pesan FIX

  4. Mengurai pesan FIX

Pesan FIX mentah bukanlah format yang sangat mudah dibaca karena dirancang dengan mempertimbangkan efisiensi daripada kemudahan pemahaman. Oleh karena itu, untuk setiap aplikasi perangkat lunak akan selalu ada proses penerjemahan informasi yang disediakan ke dalam pesan FIX masing-masing.

Dalam aplikasi sampel C# kami, kami telah membuat kelas untuk menangani konstruksi pesan serta fungsi-fungsi untuk membuat pesan FIX berdasarkan informasi yang relevan.

Setelah pesan-pesan dibuat, mereka ditransmisikan antara server dan klien melalui internet melalui soket jaringan. Ketika pesan-pesan diterima, mereka perlu diurai untuk disajikan dalam format yang dapat dibaca.

Dalam artikel ini kita akan membahas proses konstruksi, transmisi, dan penerimaan balasan. Kita akan membahas penguraian dalam artikel mendatang.

Membuat pesan FIX

Struktur pesan

Dalam aplikasi sampel kami, kami telah membuat kelas yang bertanggung jawab untuk membuat pesan FIX. Kelas tersebut disebut MessageConstructor dan dapat ditemukan dalam proyek FIX API Library.

MessageConstructor diinisialisasi dengan parameter-parameter berikut:

  1. Host(*) – alamat di mana cServer kami berada.

  2. Username(*) – nomor akun

  3. Password(*) – kata sandi

  4. SenderCompID(*) – disediakan dalam formulir FIX API cTrader. Formatnya adalah

  5. SenderSubID* – bagian kedua dari SenderCompID

  6. TargetCompID(*) – disediakan dalam formulir FIX API cTrader (biasanya cServer)

Anda dapat menemukan informasi ini di formulir FIX API cTrader Anda.

Setelah kita menginisialisasi MessageConstructor, maka kita siap untuk membuat pesan FIX API.

Semua pesan dibuat dengan cara yang serupa. Di bawah ini ada contoh kode untuk membuat pesan Logon.

 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");

       }

Anda dapat melihat bahwa kita pertama-tama membuat bagian body, kemudian kita meneruskannya ke fungsi header dan terakhir kita meneruskan kedua bagian tersebut ke fungsi trailer. Ketiga bagian ini dijelaskan secara rinci di bawah ini.

Proses konstruksi pesan hanyalah penambahan tag, nilai, dan pemisah yang diperlukan ke dalam sebuah string.

Body

Pertama-tama kita akan mulai dengan menjelaskan konstruksi body, karena body pesan perlu dibuat terlebih dahulu. Kita dapat melihat contoh di atas (membuat pesan Logon).

Kita mulai dengan menginisialisasi kelas StringBuilder dan kita menambahkan tag satu per satu berdasarkan input fungsi. Berdasarkan jenis pesan, body harus terdiri dari kumpulan tag yang berbeda, beberapa di antaranya wajib dan yang lainnya opsional.

Anda dapat menemukan struktur setiap pesan dalam Rules of Engagement (/FIX) kami.

Kemudian kita membuat header untuk pesan Logon dan menambahkan body pesan ke dalamnya. Akhirnya, menggunakan string headerAndBody kita menghasilkan trailer. Selanjutnya, kita akan melihat bagaimana kita membuat header dan trailer.

Header adalah bagian pertama dari pesan FIX dan terdiri dari bidang-bidang berikut (sama untuk semua pesan):

  1. BeginString – begin string mendefinisikan versi protokol FIX dan dalam kasus kita tetap FIX4.4.
  2. BodyLength – body length menyatakan panjang pesan dalam karakter, tidak termasuk bidang BeginString, BodyLength, dan trailer.
  3. MsgType – di bidang ini kita mendefinisikan jenis pesan, sehingga penerima tahu bagaimana mengurai body.
  4. SenderCompID – di sini kita mengatur SenderCompID.
  5. TargetCompID – ini adalah target pesan kita. Dalam kasus kita, akan selalu cServer.
  6. SenderSubID – login trader.
  7. MsgSeqNum – ini adalah nomor urut pesan. Perlu ditingkatkan untuk setiap pesan yang dikirim dalam sesi yang sama.
  8. Sending Time – waktu transmisi pesan.

Di bawah ini Anda dapat melihat fungsi ConstructHeader, yang bertanggung jawab untuk membuat header.

 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();

    }

Trailer

Trailer hanyalah tag yang berisi checksum dari sisa pesan.

 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;

       }

Pesan sistem

Sampel kami berisi fungsi-fungsi yang mengembalikan pesan sistem berikut:

  • Detak jantung: MessageConstructor.HeartbeatMessage()
  • Permintaan uji: MessageConstructor.TestRequestMessage()
  • Masuk: MessageConstructor.LogonMessage()
  • Keluar: MessageConstructor.LogoutMessage()
  • Permintaan kirim ulang: MessageConstructor.ResendMessage()
  • Tolak: MessageConstructor.RejectMessage()
  • Atur ulang urutan: MessageConstructor.SequenceResetMessage()

Pesan aplikasi

Sampel kami berisi fungsi-fungsi yang mengembalikan pesan sistem berikut:

  • Permintaan data pasar: MessageConstructor.HeartbeatMessage()
  • Snapshot pasar/penyegaran penuh: MessageConstructor.MarketDataSnapshotMessage()
  • Penyegaran bertahap data pasar: MessageConstructor.MarketDataIncrementalRefreshMessage()
  • Order tunggal baru: MessageConstructor.NewOrderSingleMessage()
  • Permintaan status order: MessageConstructor.OrderStatusRequest()
  • Laporan eksekusi: MessageConstructor.ExecutionReport()
  • Penolakan pesan bisnis: MessageConstructor.BusinessMessageReject()
  • Permintaan posisi: MessageConstructor.RequestForPositions()
  • Laporan posisi: MessageConstructor.PositionReport()

Mengirim pesan dan menerima respons

Untuk mengirim pesan FIX ke cServer, Anda pertama-tama perlu membangun koneksi dengan server. Anda dapat melakukan ini dengan membuat TcpClient. Dalam kasus kami, kami membuat dua klien, karena pesan kuotasi harga dan pesan perdagangan ditangani oleh port yang berbeda di server.

Kemudian, kita perlu mendapatkan dua stream di mana pesan-pesan akan dikirim. Proses ini terjadi dalam konstruktor form seperti yang ditunjukkan di bawah ini:

 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);

}

Dalam konstruktor, kita juga menginisialisasi kelas MessageConstructor yang akan digunakan untuk menghasilkan pesan-pesan.

Selanjutnya, untuk mengirim pesan-pesan, kami membuat dua fungsi yang berbeda, SendPriceMessage() dan SendTradeMessage(). Masing-masing mengambil pesan FIX sebagai input dan kemudian memanggil fungsi SendMessage() dengan pesan dan stream masing-masing sebagai input.

Fungsi SendMessage() bekerja sebagai berikut:

 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;
}

Langkah-langkah detailnya adalah sebagai berikut:

  1. Mengkodekan pesan menjadi array byte.
  2. Menulis array byte pada stream.
  3. Membaca balasan dari stream.
  4. Meningkatkan nomor urut pesan.
  5. Mengkodekan pesan menjadi string.

Fungsi tersebut harus mengembalikan pesan FIX yang dikirim oleh server.

Seperti yang Anda duga, Anda tidak dapat menampilkan pesan FIX mentah kepada pengguna, jadi langkah tambahan untuk mengurai pesan yang masuk harus dikembangkan.

Kesimpulan

Aplikasi ini adalah demonstrasi singkat tentang cara berkomunikasi dengan cServer menggunakan pesan FIX. Ini hanyalah contoh yang mengilustrasikan konsep Protokol FIX dan sama sekali bukan mesin FIX lengkap. Jika Anda ingin menghindari membangun mesin FIX sendiri, Anda mungkin mempertimbangkan untuk menggunakan salah satu mesin FIX pihak ketiga yang tersedia.

Catatan

Artikel ini diperbarui pada tanggal 03/02/2017 dan dikembangkan dengan mempertimbangkan mesin FIX cTrader, Rules of Engagement v2.9.1.