Crashed in OnTick with IOException

Created at 29 Oct 2018, 02:15
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
NE

netread2004

Joined 26.12.2017

Crashed in OnTick with IOException
29 Oct 2018, 02:15


I am using FIX API Sample program to implement FIX engine in cTrader.

I am getting this crash quite often with following message:

29/10/2018 00:07:56.238 | Crashed in OnTick with IOException: Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.

 

I am using HeartBeat every 10 second. Still I am not able to get rid of this error. This makes my FIX engine program unsuable. 

Could you please give me some idea why this is happening and any work-around you have to fix this issue.

 

Thanks,


@netread2004
Replies

PanagiotisCharalampous
29 Oct 2018, 11:37

Hi netread2004,

Can you share the cBot code so that we can reproduce the issue?

Best Regards,

Panagiotis


@PanagiotisCharalampous

netread2004
05 Nov 2018, 02:34

RE:

Panagiotis Charalampous said:

Hi netread2004,

Can you share the cBot code so that we can reproduce the issue?

Best Regards,

Panagiotis

Here is the error messages I am getting now when I run this code.

 

05/11/2018 00:27:49.254 | cBot "FIXengine_iCMarkets_test" was started successfully for GBPUSD, m1.
05/11/2018 00:28:09.613 | Crashed in OnTimer with IOException: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.
05/11/2018 00:28:09.613 | Crashed in OnStop with IOException: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.
05/11/2018 00:28:09.629 | cBot "FIXengine_iCMarkets_test" was stopped for GBPUSD, m1.

 

Please change FIX credential appropriatly to match with your server while testing it in your environment.

//using FIX_API_Library;
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;


namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public partial class frmFIXAPISample : Robot
    {

        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("Stop Loss (pips)", DefaultValue = 1.3, MinValue = 1)]
        public double StopLossInPips { get; set; }

        [Parameter("Take Profit (pips)", DefaultValue = 100.0, MinValue = 1)]
        public double TakeProfitInPips { get; set; }

        [Parameter("Quantity (Lots)", DefaultValue = 0.01, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }

        [Parameter("Bollinger Bands Deviations", DefaultValue = 0.5)]
        public double Deviations { get; set; }

        [Parameter("Bollinger Bands Periods", DefaultValue = 2)]
        public int Periods { get; set; }

        [Parameter("Bollinger Bands MA Type")]
        public MovingAverageType MAType { get; set; }

        [Parameter("BarHeight Thresh", DefaultValue = 16)]
        public int BarHeightThresh { get; set; }

        [Parameter("pipUpDn Thresh", DefaultValue = 180)]
        public double pipUpDnThresh { get; set; }

        [Parameter("Tralling Stop (pips)", DefaultValue = 1.3)]
        public double StopLoss { get; set; }

        [Parameter("Inital Stop Loss (pips)", DefaultValue = 1.3)]
        public double init_StopLoss { get; set; }

        [Parameter("RiskPC", DefaultValue = 10.0)]
        public double risk { get; set; }

        [Parameter("AllowedSpread", DefaultValue = 2.0)]
        public double allowedSpread { get; set; }

        [Parameter("toDisp", DefaultValue = true)]
        public bool toDisp { get; set; }

        [Parameter("ordNumDisp", DefaultValue = false)]
        public bool ordNumDisp { get; set; }

        [Parameter("printWholeFixMsg", DefaultValue = false)]
        public bool printWholeFixMsg { get; set; }


        [Parameter("symbolID", DefaultValue = 1)]
        public int symbolID { get; set; }


        public const int EURUSD = 1;
        public const int GBPUSD = 2;

        string txtMessageSend_Text = "";
        string txtMessageReceived_Text = "";

        bool deCryptEn = true;
        bool deCryptNoPrint = false;

        bool stopLossPlaced = false;
        bool lookForPrice = false;

        bool filledDueToSLHit = false;

        string initPriceForSL;

        string randomNum = "";

        string[] filledPosiitonID = 
        {
            ""
        };
        string filPosID;
        string avePricePosition;

        string clOrdNumGlob;

        bool origStopOrdFilled = false;

        int totalPosGlob = 0;


        //Ctrader
        private int _pricePort = 5211;
        private int _tradePort = 5212;
        private string _host = "h1.p.ctrader.cn";
        private string _username = "3388140";
        private string _password = "qwerty12";
        private string _senderCompID = "icmarkets.3388140";
        private string _targetCompID = "cServer";
        private string _senderSubID = "TRADE";

        private int _messageSequenceNumber = 1;
        private int _testRequestID = 1;
        private TcpClient _priceClient;
        private SslStream _priceStreamSSL;
        private TcpClient _tradeClient;
        private SslStream _tradeStreamSSL;
        private MessageConstructor _messageConstructor;


        private double High;
        private double Low;

        double spread;

        string globIDForCheckOrder = "";
        string globIdForSLCheckStat = "";




        protected override void OnStart()
        {


            btnLogonT_Click();
            Timer.TimerTick += OnTimerTick;
            Timer.Start(10);

            Positions.Closed += PositionsOnClosed;
        }
        protected override void OnStop()
        {
            btnLogoutT_Click();
        }
        private void OnTimerTick()
        {
            btnHeartbeatT_Click();

        }
        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            var position = args.Position;
            Print("Position closed with {0} profit", position.GrossProfit);

            filledDueToSLHit = false;

            stopLossPlaced = false;
            clOrdNumGlob = "";

            origStopOrdFilled = false;

            initPriceForSL = "";

            Print("Order Closed Successfully!!!!    -------------");
            filPosID = "";


            globIDForCheckOrder = "";
            globIdForSLCheckStat = "";
        }
        protected override void OnTick()
        {

            High = MarketSeries.High.Last(0);
            Low = MarketSeries.Low.Last(0);
            int totalPositions = Positions.Count;
            var totalPendOrders = PendingOrders.Count;

            var barHeight = High - Low;

            totalPosGlob = totalPositions;


            if (origStopOrdFilled && totalPositions == 0)
            {

            }
            spread = (Symbol.Ask - Symbol.Bid) / Symbol.PipSize;
        }

        private string getRandomNumber(string coment)
        {
            Random random = new Random();
            int randomNumber = random.Next();
            randomNum = randomNumber.ToString();
            if (ordNumDisp)
                Print(coment + " ClOrdeID : ", randomNum);
            return (randomNum);
        }

        private void printSendReceive()
        {

            Print("SendText : ", txtMessageSend_Text.Replace("\u0001", " "));
            Print("ReceivedText : ", txtMessageReceived_Text.Replace("\u0001", " "));
        }
        private void deCryptMessage(string sentMssg, string recvdMessg)
        {
        }

        //End of my routines
        public frmFIXAPISample()
        {
            //InitializeComponent();

            _priceClient = new TcpClient(_host, _pricePort);
            _priceStreamSSL = new SslStream(_priceClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
            _priceStreamSSL.AuthenticateAsClient(_host);
            _tradeClient = new TcpClient(_host, _tradePort);
            _tradeStreamSSL = new SslStream(_tradeClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
            _tradeStreamSSL.AuthenticateAsClient(_host);
            _messageConstructor = new MessageConstructor(_host, _username, _password, _senderCompID, _senderSubID, _targetCompID);
        }

        private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.None)
                return true;
            Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
            return false;
        }

        private void ClearText()
        {
            txtMessageSend_Text = "";
            txtMessageReceived_Text = "";
        }

        private string SendPriceMessage(string message, bool readResponse = true)
        {
            return SendMessage(message, _priceStreamSSL, readResponse);
        }

        private string SendTradeMessage(string message, bool readResponse = true)
        {
            return SendMessage(message, _tradeStreamSSL, readResponse);
        }

        private string SendMessage(string message, SslStream stream, bool readResponse = true)
        {
            var byteArray = Encoding.ASCII.GetBytes(message);
            System.Net.ServicePointManager.Expect100Continue = false;
            //I inserted Above line to see if it fixes crash issue
            stream.Write(byteArray, 0, byteArray.Length);
            var buffer = new byte[1024];
            if (readResponse)
            {
                Thread.Sleep(100);
                stream.Read(buffer, 0, 1024);
            }
            _messageSequenceNumber++;
            var returnMessage = Encoding.ASCII.GetString(buffer);
            return returnMessage;
        }

        private void btnLogon_Click()
        {
            ClearText();
            var message = _messageConstructor.LogonMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, 30, false);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
            if (printWholeFixMsg)
                printSendReceive();

        }

        private void btnTestRequest_Click(object sender, EventArgs e)
        {
            ClearText();
            var message = _messageConstructor.TestRequestMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, _testRequestID);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
        }

        private void btnLogout_Click()
        {
            ClearText();
            var message = _messageConstructor.LogoutMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
            _messageSequenceNumber = 1;
            if (printWholeFixMsg)
                printSendReceive();
        }

        private void btnMarketDataRequest_Click(object sender, EventArgs e)
        {
            ClearText();
            var message = _messageConstructor.MarketDataRequestMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, "EURUSD:WDqsoT", 1, 0, 0, 1, 1);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
        }

        private void btnHeartbeat_Click()
        {
            ClearText();
            var message = _messageConstructor.HeartbeatMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message, false);
            if (printWholeFixMsg)
                printSendReceive();
        }

        private void btnResendRequest_Click(object sender, EventArgs e)
        {
            ClearText();
            var message = _messageConstructor.ResendMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, _messageSequenceNumber - 1);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
        }

        private void btnReject_Click(object sender, EventArgs e)
        {
            ClearText();
            var message = _messageConstructor.RejectMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, 0);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
        }

        private void btnSequenceReset_Click(object sender, EventArgs e)
        {
            ClearText();
            var message = _messageConstructor.SequenceResetMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, 0);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
        }

        private void btnNewOrderSingle_Click(object sender, EventArgs e)
        {
            ClearText();
            var message = _messageConstructor.NewOrderSingleMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, "1408471", 1, 1, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss"), 1000, 1, "1");
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message);
        }

        private void btnOrderStatusRequest_Click(string orderId, int symbl, int ordtyp)
        {
            ClearText();
            var message = _messageConstructor.OrderStatusRequest(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, orderId, symbl, ordtyp);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

        private string Timestamp()
        {
            return (DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds.ToString();
        }

        private void btnRequestForPositions_Click(string posID)
        {
            ClearText();
            var message = _messageConstructor.RequestForPositions(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, posID);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

        private void btnLogonT_Click()
        {
            ClearText();
            var message = _messageConstructor.LogonMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, 30, false);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

        private void btnHeartbeatT_Click()
        {
            ClearText();
            var message = _messageConstructor.HeartbeatMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message, false);
            if (printWholeFixMsg)
                printSendReceive();
        }

        private void btnTestRequestT_Click(object sender, EventArgs e)
        {
            ClearText();
            var message = _messageConstructor.TestRequestMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, _testRequestID);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message);
        }

        private void btnLogoutT_Click()
        {
            ClearText();
            var message = _messageConstructor.LogoutMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message);
            _messageSequenceNumber = 1;
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

        private void btnResendRequestT_Click(object sender, EventArgs e)
        {
            ClearText();
            var message = _messageConstructor.ResendMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, _messageSequenceNumber - 1);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message);
        }

        private void btnSpotMarketData_Click(object sender, EventArgs e)
        {
            ClearText();
            var message = _messageConstructor.MarketDataRequestMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, "EURUSD:WDqsoT", 1, 1, 0, 1, 1);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
        }

        private void btnStopOrder_Click(int symb, int vol, double stpPrice, string ClOrdID, int side, string posiID)
        {
            ClearText();
            var message = _messageConstructor.NewOrderSingleMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, ClOrdID, symb, side, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss"), vol, 3, "3", 0,
            (decimal)stpPrice, "", posiID);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }
        private void btnCancelOrder_Click(string ClOrdID, string oldOrdID)
        {
            ClearText();
            var message = _messageConstructor.CancelOrderSingleMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, ClOrdID, oldOrdID, 1, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss"), 3, "3", 0);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }
        private void btnLimitOrder_Click()
        {
            ClearText();
            var message = _messageConstructor.NewOrderSingleMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, "10", 1, 1, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss"), 1000, 2, "3", (decimal)1.08);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
        }
    }



    public class MessageConstructor
    {
        public enum SessionMessageType
        {
            Logon,
            Logout,
            Heartbeat,
            TestRequest,
            Resend,
            Reject,
            SequenceReset
        }

        public enum ApplicationMessageType
        {
            MarketDataRequest,
            MarketDataIncrementalRefresh,
            NewOrderSingle,
            CancelOrderSingle,
            OrderStatusRequest,
            ExecutionReport,
            BusinessMessageReject,
            RequestForPosition,
            PositionReport
        }

        public enum SessionQualifier
        {
            QUOTE,
            TRADE
        }

        private string _host;
        private string _username;
        private string _password;
        private string _senderCompID;
        private string _senderSubID;
        private string _targetCompID;

        public MessageConstructor(string host, string username, string password, string senderCompID, string senderSubID, string targetCompID)
        {
            _host = host;
            _username = username;
            _password = password;
            _senderCompID = senderCompID;
            _senderSubID = senderSubID;
            _targetCompID = targetCompID;
        }

        /// <summary>
        /// Logons the message.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="messageSequenceNumber">The message sequence number.</param>
        /// <param name="heartBeatSeconds">The heart beat seconds.</param>
        /// <param name="resetSeqNum">All sides of FIX session should have sequence numbers reset. Valid value
        ///is "Y" = Yes(reset)..</param>
        /// <returns></returns>
        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 heart beat 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");
        }

        public string HeartbeatMessage(SessionQualifier qualifier, int messageSequenceNumber)
        {
            var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.Heartbeat), messageSequenceNumber, string.Empty);
            var trailer = ConstructTrailer(header);
            var headerAndMessageAndTrailer = header + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        public string TestRequestMessage(SessionQualifier qualifier, int messageSequenceNumber, int testRequestID)
        {
            var body = new StringBuilder();
            //Heartbeat message ID. TestReqID should be incremental.
            body.Append("112=" + testRequestID + "|");
            var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.TestRequest), messageSequenceNumber, body.ToString());
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        public string LogoutMessage(SessionQualifier qualifier, int messageSequenceNumber)
        {
            var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.Logout), messageSequenceNumber, string.Empty);
            var trailer = ConstructTrailer(header);
            var headerAndMessageAndTrailer = header + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        /// <summary>
        /// Resends the message.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="messageSequenceNumber">Message sequence number of last record in range to be resent.</param>
        /// <param name="endSequenceNo">The end sequence no.</param>
        /// <returns></returns>
        public string ResendMessage(SessionQualifier qualifier, int messageSequenceNumber, int endSequenceNo)
        {
            var body = new StringBuilder();
            //Message sequence number of last record in range to be resent.
            body.Append("16=" + endSequenceNo + "|");
            var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.Resend), messageSequenceNumber, body.ToString());
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        public string RejectMessage(SessionQualifier qualifier, int messageSequenceNumber, int rejectSequenceNumber)
        {
            var body = new StringBuilder();
            //Referenced message sequence number.
            body.Append("45=" + rejectSequenceNumber + "|");
            var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.Reject), messageSequenceNumber, string.Empty);
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        public string SequenceResetMessage(SessionQualifier qualifier, int messageSequenceNumber, int rejectSequenceNumber)
        {
            var body = new StringBuilder();
            //New Sequence Number
            body.Append("36=" + rejectSequenceNumber + "|");
            var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.SequenceReset), messageSequenceNumber, string.Empty);
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        /// <summary>
        /// Constructs a message for requesting market data.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="messageSequenceNumber">The message sequence number.</param>
        /// <param name="marketDataRequestID">Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal.</param>
        /// <param name="subscriptionRequestType">1 = Snapshot plus updates (subscribe) 2 = Disable previous snapshot plus update request (unsubscribe).</param>
        /// <param name="marketDepth">Full book will be provided, 0 = Depth subscription, 1 = Spot subscription.</param>
        /// <param name="marketDataEntryType">Always set to 2 (both bid and ask will be sent).</param>
        /// <param name="noRelatedSymbol">Number of symbols requested.</param>
        /// <param name="symbol">Instrument identificators are provided by Spotware.</param>
        /// <returns></returns>
        public string MarketDataRequestMessage(SessionQualifier qualifier, int messageSequenceNumber, string marketDataRequestID, int subscriptionRequestType, int marketDepth, int marketDataEntryType, int noRelatedSymbol, long symbol = 0)
        {
            var body = new StringBuilder();
            //Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal.
            body.Append("262=" + marketDataRequestID + "|");
            //1 = Snapshot plus updates (subscribe) 2 = Disable previous snapshot plus update request (unsubscribe)
            body.Append("263=" + subscriptionRequestType + "|");
            //Full book will be provided, 0 = Depth subscription, 1 = Spot subscription
            body.Append("264=" + marketDepth + "|");
            //Only Incremental refresh is supported.
            body.Append("265=1|");
            //Always set to 2 (both bid and ask will be sent).
            body.Append("267=2|");
            //Always set to 2 (both bid and ask will be sent).
            body.Append("269=0|269=1|");
            //Number of symbols requested.
            body.Append("146=" + noRelatedSymbol + "|");
            //Instrument identificators are provided by Spotware.
            body.Append("55=" + symbol + "|");
            var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.MarketDataRequest), messageSequenceNumber, body.ToString());
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        /// <summary>
        /// Constructs a message for requesting market data snapshot.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="messageSequenceNumber">The message sequence number.</param>
        /// <param name="symbol">Instrument identificators are provided by Spotware.</param>
        /// <param name="noMarketDataEntries">Number of entries following.</param>
        /// <param name="entryType">Valid values are: 0 = BID, 1 = OFFER.</param>
        /// <param name="entryPrice">Price of Market Data Entry.</param>
        /// <param name="marketDataRequestID">Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal.</param>
        /// <returns></returns>
        public string MarketDataSnapshotMessage(SessionQualifier qualifier, int messageSequenceNumber, long symbol, string noMarketDataEntries, int entryType, decimal entryPrice, string marketDataRequestID = "")
        {
            var body = new StringBuilder();
            //Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal.
            body.Append("262=" + marketDataRequestID + "|");
            //Instrument identificators are provided by Spotware.
            body.Append("55=" + symbol + "|");
            //Number of entries following.
            body.Append("268=" + noMarketDataEntries + "|");
            //Valid values are: 0 = BID, 1 = OFFER.
            body.Append("269=" + entryType + "|");
            //Price of Market Data Entry.
            body.Append("270=" + entryPrice + "|");
            var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.MarketDataRequest), messageSequenceNumber, body.ToString());
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        /// <summary>
        /// Markets the data incremental refresh message.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="messageSequenceNumber">The message sequence number.</param>
        /// <param name="marketDataRequestID">Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal.</param>
        /// <param name="noMarketDataEntries">Number of entries following. This repeating group contains a list of all types of Market Data Entries the requester wants to receive.</param>
        /// <param name="marketDataUpdateAction">Type of Market Data update action. Valid values: 0 = NEW, 2 = DELETE.</param>
        /// <param name="marketDataEntryType">Valid values are: 0 = BID, 1 = OFFER.</param>
        /// <param name="marketDataEntryID">ID of Market Data Entry.</param>
        /// <param name="noRelatedSymbol">The no related symbol.</param>
        /// <param name="marketDataEntryPrice">Conditionally required when MDUpdateAction <279> = New(0).</param>
        /// <param name="marketDataEntrySize">Conditionally required when MDUpdateAction <279> = New(0).</param>
        /// <param name="symbol">/Instrument identificators are provided by Spotware.</param>
        /// <returns></returns>
        public string MarketDataIncrementalRefreshMessage(SessionQualifier qualifier, int messageSequenceNumber, string marketDataRequestID, int noMarketDataEntries, int marketDataUpdateAction, int marketDataEntryType, string marketDataEntryID, int noRelatedSymbol, decimal marketDataEntryPrice = 0, double marketDataEntrySize = 0,
        long symbol = 0)
        {
            var body = new StringBuilder();
            //Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal.
            body.Append("262=" + marketDataRequestID + "|");
            //Number of entries following. This repeating group contains a list of all types of Market Data Entries the requester wants to receive
            body.Append("268=" + noMarketDataEntries + "|");
            //Type of Market Data update action. Valid values: 0 = NEW, 2 = DELETE
            body.Append("279=" + marketDataUpdateAction + "|");
            //Valid values are: 0 = BID, 1 = OFFER
            body.Append("269=" + marketDataEntryType + "|");
            //ID of Market Data Entry.
            body.Append("278=" + marketDataEntryID + "|");
            //Instrument identificators are provided by Spotware
            body.Append("55=" + symbol + "|");
            if (marketDataEntryPrice > 0)
            {
                //Conditionally required when MDUpdateAction <279> = New(0)
                body.Append("270=" + marketDataEntryPrice + "|");
            }
            if (marketDataEntrySize > 0)
            {
                //Conditionally required when MDUpdateAction <279> = New(0)
                body.Append("271=" + marketDataEntrySize + "|");
            }
            var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.MarketDataIncrementalRefresh), messageSequenceNumber, string.Empty);
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
            //return headerAndMessageAndTrailer;
        }

        /// <summary>
        /// News the order single message.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="messageSequenceNumber">The message sequence number.</param>
        /// <param name="orderID">Unique identifier for the order, allocated by the client.</param>
        /// <param name="symbol">The symbol.</param>
        /// <param name="side">1= Buy, 2 = Sell.</param>
        /// <param name="transactTime">Client generated request time.</param>
        /// <param name="orderQuantity">The fixed currency amount.</param>
        /// <param name="orderType">1 = Market, the Order will be processed by 'Immediate Or Cancel'scheme(see TimeInForce(59): IOC);
        /// 2 = Limit, the Order will be processed by 'Good Till Cancel' scheme(see TimeInForce(59): GTC).</param>
        /// <param name="timeInForce">1 = Good Till Cancel (GTC), it will be active only for Limit Orders (see OrdType(40)) ;
        /// 3 = Immediate Or Cancel (IOC), it will be active only for Market Orders(see OrdType(40));
        /// 6 = Good Till Date(GTD), it will be active only if ExpireTime is defined (see ExpireTime(126)).
        /// GTD has a high priority, so if ExpireTime is defined, GTD will be used for the Order processing.</param>
        /// <param name="price">The worst client price that the client will accept.
        /// Required when OrdType = 2, in which case the order will notfill unless this price can be met.</param>
        /// /// <param name="stopPrice">Reserved for future use</param>
        /// <param name="expireTime">  Expire Time in YYYYMMDDHH:MM:SS format.If is assigned then the Order will be processed by 'Good Till Date' scheme
        /// (see TimeInForce: GTD).</param>
        /// <param name="positionID">Position ID, where this order should be placed. If not set, new position will be created, it’s id will be returned in ExecutionReport(8) message.</param>
        /// <returns></returns>
        public string NewOrderSingleMessage(SessionQualifier qualifier, int messageSequenceNumber, string orderID, long symbol, int side, string transactTime, int orderQuantity, int orderType, string timeInForce, decimal price = 0,
        decimal stopPrice = 0, string expireTime = "", string positionID = "")
        {
            var body = new StringBuilder();
            //Unique identifier for the order, allocated by the client.
            body.Append("11=" + orderID + "|");
            //Instrument identificators are provided by Spotware.
            body.Append("55=" + symbol + "|");
            //1= Buy, 2 = Sell
            body.Append("54=" + side + "|");
            // Client generated request time.
            body.Append("60=" + transactTime + "|");
            //The fixed currency amount.
            body.Append("38=" + orderQuantity + "|");
            //1 = Market, the Order will be processed by 'Immediate Or Cancel'scheme(see TimeInForce(59): IOC);
            //2 = Limit, the Order will be processed by 'Good Till Cancel' scheme(see TimeInForce(59): GTC).
            body.Append("40=" + orderType + "|");
            if (price != 0)
            {
                //Reserved for future use.
                body.Append("44=" + price + "|");
            }
            if (stopPrice != 0)
            {
                //The worst client price that the client will accept.
                //Required when OrdType = 2, in which case the order will notfill unless this price can be met.
                body.Append("99=" + stopPrice + "|");
            }
            // 1 = Good Till Cancel (GTC), it will be active only for Limit Orders (see OrdType(40)) ;
            // 3 = Immediate Or Cancel (IOC), it will be active only for Market Orders(see OrdType(40));
            // 6 = Good Till Date(GTD), it will be active only if ExpireTime is defined (see ExpireTime(126)).
            // GTD has a high priority, so if ExpireTime is defined, GTD will be used for the Order processing.
            body.Append("59=" + timeInForce + "|");
            if (expireTime != string.Empty)
            {
                // Expire Time in YYYYMMDDHH:MM:SS format.If is assigned then the Order will be processed by 'Good Till Date' scheme
                // (see TimeInForce: GTD).
                body.Append("126=" + expireTime + "|");
            }
            if (positionID != string.Empty)
            {
                // Position ID, where this order should be placed. If not set, new position will be created, it’s id will be returned in ExecutionReport(8) message.
                body.Append("721=" + positionID + "|");
            }

            var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.NewOrderSingle), messageSequenceNumber, body.ToString());
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        public string CancelOrderSingleMessage(SessionQualifier qualifier, int messageSequenceNumber, string orderID, string oldOrdID, int side, string transactTime, int orderType, string timeInForce, decimal stopPrice = 0, string expireTime = "",
        string positionID = "")
        {
            var body = new StringBuilder();
            //OldID identifier for the order, allocated by the client.
            body.Append("41=" + oldOrdID + "|");
            //Unique identifier for the order, allocated by the client.
            body.Append("11=" + orderID + "|");
            /* following is NOT needed for cancel orderModify Order.
            body.Append("55=" + symbol + "|");
            body.Append("54=" + side + "|");
            body.Append("60=" + transactTime + "|");
            body.Append("38=" + orderQuantity + "|");
            body.Append("40=" + orderType + "|");
            body.Append("99=" + price + "|");
            //Instrument identificators are provided by Spotware.
                                   body.Append("55=" + symbol + "|");
            //1= Buy, 2 = Sell
            body.Append("54=" + side + "|");
            // Client generated request time.
            body.Append("60=" + transactTime + "|");
            //The fixed currency amount.
            body.Append("38=" + orderQuantity + "|");
            //1 = Market, the Order will be processed by 'Immediate Or Cancel'scheme(see TimeInForce(59): IOC);
            //2 = Limit, the Order will be processed by 'Good Till Cancel' scheme(see TimeInForce(59): GTC).
            body.Append("40=" + orderType + "|");
            if (price != 0)
            {
                //Reserved for future use.
                body.Append("44=" + price + "|");
            }
            if (stopPrice != 0)
            {
                //The worst client price that the client will accept.
                //Required when OrdType = 2, in which case the order will notfill unless this price can be met.
                // body.Append("99=" + stopPrice + "|"); 
            }
            // 1 = Good Till Cancel (GTC), it will be active only for Limit Orders (see OrdType(40)) ;
            // 3 = Immediate Or Cancel (IOC), it will be active only for Market Orders(see OrdType(40));
            // 6 = Good Till Date(GTD), it will be active only if ExpireTime is defined (see ExpireTime(126)).
            // GTD has a high priority, so if ExpireTime is defined, GTD will be used for the Order processing.
            // body.Append("59=" + timeInForce + "|"); //not needed for modify
            if (expireTime != string.Empty)
            {
                // Expire Time in YYYYMMDDHH:MM:SS format.If is assigned then the Order will be processed by 'Good Till Date' scheme
                // (see TimeInForce: GTD).
                body.Append("126=" + expireTime + "|");
            }
            if (positionID != string.Empty)
            {
                // Position ID, where this order should be placed. If not set, new position will be created, it’s id will be returned in ExecutionReport(8) message.
                body.Append("721=" + positionID + "|");
            }
*/
            var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.CancelOrderSingle), messageSequenceNumber, body.ToString());
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }
        /// <summary>
        /// Orders the status request.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="messageSequenceNumber">The message sequence number.</param>
        /// <param name="orderID">Unique identifier for the order, allocated by the client.</param>
        /// <returns></returns>
        public string OrderStatusRequest(SessionQualifier qualifier, int messageSequenceNumber, string orderID, int symb, int orderTyp)
        {
            var body = new StringBuilder();
            // Unique identifier for the order, allocated by the client.
            body.Append("11=" + orderID + "|");
            //Symbol - added by me
            //body.Append("55=" + symb + "|");//it was giving me error
            // 1 = Buy; 2 = Sell. There is for the FIX compatibility only, so it will be ignored.
            body.Append("54=" + orderTyp + "|");
            var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.OrderStatusRequest), messageSequenceNumber, body.ToString());
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        /// <summary>
        /// Executions the report.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="messageSequenceNumber">The message sequence number.</param>
        /// <param name="cTraderOrderID">cTrader order id..</param>
        /// <param name="orderStatus"> 0 = New; 1 = Partially filled; 2 = Filled;  8 = Rejected; 4 = Cancelled(When an order is partially filled, "Cancelled" is
        /// returned signifying Tag 151: LeavesQty is cancelled and will not be subsequently filled); C = Expired.</param>
        /// <param name="transactTime">Time the transaction represented by this ExecutionReport occurred message(in UTC).</param>
        /// <param name="symbol">Instrument identificators are provided by Spotware..</param>
        /// <param name="side">1 = Buy; 2 = Sell.</param>
        /// <param name="averagePrice">The price at which the deal was filled.For an IOC or GTD order, this is the VWAP(Volume Weighted Average Price) of the filled order.</param>
        /// <param name="orderQuantity"> The fixed currency amount.</param>
        /// <param name="leavesQuantity">The amount of the order still to be filled.This is a value between 0 (fully filled) and OrderQty (partially filled).</param>
        /// <param name="cumQuantity">The total amount of the order which has been filled.</param>
        /// <param name="orderID"> Unique identifier for the order, allocated by the client.</param>
        /// <param name="orderType"> 1 = Market; 2 = Limit.</param>
        /// <param name="price">If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport.</param>
        /// <param name="stopPrice">If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport.</param>
        /// <param name="timeInForce">U1 = Good Till Cancel (GTC); 3 = Immediate Or Cancel (IOC); 6 = Good Till Date (GTD).</param>
        /// <param name="expireTime"> If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport.</param>
        /// <param name="text">Where possible, message to explain execution report.</param>
        /// <param name="orderRejectionReason">0 = OrdRejReason.BROKER_EXCHANGE_OPTION</param>
        /// <param name="positionID">Position ID.</param>
        /// <returns></returns>
        public string ExecutionReport(SessionQualifier qualifier, int messageSequenceNumber, string cTraderOrderID, string orderStatus, string transactTime, long symbol = 0, int side = 1, int averagePrice = 0, int orderQuantity = 0, int leavesQuantity = 0,
        int cumQuantity = 0, string orderID = "", string orderType = "", int price = 0, int stopPrice = 0, string timeInForce = "", string expireTime = "", string text = "", int orderRejectionReason = -1, string positionID = "")
        {
            var body = new StringBuilder();
            // cTrader order id.
            body.Append("37=" + cTraderOrderID + "|");
            // Unique identifier for the order, allocated by the client.
            body.Append("11=" + orderID + "|");
            // Execution Type.
            body.Append("150=F|");
            // 0 = New; 1 = Partially filled; 2 = Filled;  8 = Rejected; 4 = Cancelled(When an order is partially filled, "Cancelled" is
            // returned signifying Tag 151: LeavesQty is cancelled and will not be subsequently filled); C = Expired.
            body.Append("39=" + orderStatus + "|");
            // Instrument identificators are provided by Spotware.
            body.Append("55=" + symbol + "|");
            // 1 = Buy; 2 = Sell.
            body.Append("54=" + side + "|");
            // Time the transaction represented by this ExecutionReport occurred message(in UTC).
            body.Append("60=" + transactTime + "|");
            if (averagePrice > 0)
            {
                // The price at which the deal was filled.For an IOC or GTD order, this is the VWAP(Volume Weighted Average Price) of the filled order.
                body.Append("6=" + averagePrice + "|");
            }
            if (orderQuantity > 0)
            {
                // The fixed currency amount.
                body.Append("38=" + orderQuantity + "|");
            }
            if (leavesQuantity > 0)
            {
                // The amount of the order still to be filled.This is a value between 0 (fully filled) and OrderQty (partially filled).
                body.Append("151=" + leavesQuantity + "|");
            }
            if (cumQuantity > 0)
            {
                // The total amount of the order which has been filled.
                body.Append("14=" + cumQuantity + "|");
            }
            if (orderType != string.Empty)
            {
                // 1 = Market; 2 = Limit.
                body.Append("40=" + orderType + "|");
            }
            if (price > 0)
            {
                // If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport.
                body.Append("44=" + price + "|");
            }
            if (stopPrice > 0)
            {
                // If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport.
                body.Append("99=" + stopPrice + "|");
            }
            if (timeInForce != string.Empty)
            {
                // U1 = Good Till Cancel (GTC); 3 = Immediate Or Cancel (IOC); 6 = Good Till Date (GTD).
                body.Append("59=" + timeInForce + "|");
            }
            if (expireTime != string.Empty)
            {
                // If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport.
                body.Append("126=" + expireTime + "|");
            }
            if (text != string.Empty)
            {
                // Where possible, message to explain execution report.
                body.Append("58=" + text + "|");
            }
            if (orderRejectionReason != -1)
            {
                // 0 = OrdRejReason.BROKER_EXCHANGE_OPTION
                body.Append("103=" + orderRejectionReason + "|");
            }
            if (positionID != string.Empty)
            {
                // Position ID.
                body.Append("721=" + positionID + "|");
            }

            var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.OrderStatusRequest), messageSequenceNumber, body.ToString());
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        /// <summary>
        /// Businesses the message reject.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="messageSequenceNumber">The message sequence number.</param>
        /// <param name="referenceSequenceNum">MsgSeqNum<34> of rejected message.</param>
        /// <param name="referenceMessageType">TThe MsgType<35> of the FIX message being referenced.</param>
        /// <param name="businessRejectRefID">The value of the business-level 'ID' field on the message being referenced.Required unless the corresponding ID field was not specified.</param>
        /// <param name="businessRejectReason">Where possible, message to explain reason for rejection.</param>
        /// <param name="text">Where possible, message to explain reason for rejection.</param>
        /// <returns></returns>
        public string BusinessMessageReject(SessionQualifier qualifier, int messageSequenceNumber, int referenceSequenceNum = 0, string referenceMessageType = "", string businessRejectRefID = "", int businessRejectReason = -1, string text = "")
        {
            var body = new StringBuilder();
            if (referenceSequenceNum != 0)
            {
                // MsgSeqNum<34> of rejected message.
                body.Append("45=" + referenceSequenceNum + "|");
            }
            if (referenceMessageType != string.Empty)
            {
                // The MsgType<35> of the FIX message being referenced.
                body.Append("372=" + referenceMessageType + "|");
            }
            if (businessRejectRefID != string.Empty)
            {
                // The value of the business-level 'ID' field on the message being referenced.Required unless the corresponding ID field was not specified.
                body.Append("379=" + businessRejectRefID + "|");
            }
            if (businessRejectReason != -1)
            {
                // Code to identify reason for a Business Message Reject<j> message. 0 = OTHER.
                body.Append("380=" + businessRejectReason + "|");
            }
            if (text != string.Empty)
            {
                // Where possible, message to explain reason for rejection.
                body.Append("58=" + text + "|");
            }
            var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.BusinessMessageReject), messageSequenceNumber, body.ToString());
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        /// <summary>
        /// Requests for positions.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="messageSequenceNumber">The message sequence number.</param>
        /// <param name="requestID">Unique request ID (set by client).</param>
        /// <param name="positionRequestID">Position ID to request. If not set, all open positions will be returned.</param>
        /// <returns></returns>
        public string RequestForPositions(SessionQualifier qualifier, int messageSequenceNumber, string requestID, string positionRequestID = "")
        {
            var body = new StringBuilder();
            // Unique request ID (set by client).
            body.Append("710=" + requestID + "|");
            if (positionRequestID != string.Empty)
            {
                // Position ID to request. If not set, all open positions will be returned.
                body.Append("721=" + positionRequestID + "|");
            }
            var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.RequestForPosition), messageSequenceNumber, body.ToString());
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        /// <summary>
        /// Gets the position of reporting.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="messageSequenceNumber">The message sequence number.</param>
        /// <param name="requestID">Id of RequestForPositions.</param>
        /// <param name="totalNumberOfPositionReports">Total count of PositionReport’s in sequence when PosReqResult(728) is VALID_REQUEST, otherwise = 0.</param>
        /// <param name="positionRequestResult">0 = Valid Request; 2 = No open positions found that match criteria.</param>
        /// <param name="positionID">Position ID (is not set if PosReqResult(728) is not VALID_REQUEST).</param>
        /// <param name="symbol">The symbol for which the current Position Report is prepared. (is not set if PosReqResult(728) is not VALID_REQUEST).</param>
        /// <param name="noOfPositions">1 when PosReqResult(728) is  VALID_REQUEST, otherwise not set.</param>
        /// <param name="longQuantity">Position’s open volume in case of BUY trade side, = 0 in case of SELL trade side, is not set if PosReqResult(728) is not VALID_REQUEST.</param>
        /// <param name="shortQuantity">Position’s open volume in case of SELL trade side, = 0 in case of BUY trade side, is not set if PosReqResult(728) is not VALID_REQUEST.</param>
        /// <param name="settlementPrice">Average price of the opened volume in the current PositionReport.</param>
        /// <returns></returns>
        public string PositionReport(SessionQualifier qualifier, int messageSequenceNumber, string requestID, string totalNumberOfPositionReports, string positionRequestResult, string positionID = "", string symbol = "", string noOfPositions = "", string longQuantity = "", string shortQuantity = "",
        string settlementPrice = "")
        {
            var body = new StringBuilder();
            // Id of RequestForPositions.
            body.Append("710=" + requestID + "|");
            if (positionID != string.Empty)
            {
                // Position ID (is not set if PosReqResult(728) is not VALID_REQUEST).
                body.Append("721=" + positionID + "|");
            }
            // Total count of PositionReport’s in sequence when PosReqResult(728) is VALID_REQUEST, otherwise = 0.
            body.Append("727=" + totalNumberOfPositionReports + "|");
            // 0 = Valid Request; 2 = No open positions found that match criteria.
            body.Append("728=" + positionRequestResult + "|");

            if (symbol != string.Empty)
            {
                // The symbol for which the current Position Report is prepared. (is not set if PosReqResult(728) is not VALID_REQUEST).
                body.Append("55=" + symbol + "|");
            }
            if (noOfPositions != string.Empty)
            {
                // 1 when PosReqResult(728) is  VALID_REQUEST, otherwise not set.
                body.Append("702=" + noOfPositions + "|");
            }
            if (longQuantity != string.Empty)
            {
                // Position’s open volume in case of BUY trade side, = 0 in case of SELL trade side, is not set if PosReqResult(728) is not VALID_REQUEST.
                body.Append("704=" + requestID + "|");
            }
            if (shortQuantity != string.Empty)
            {
                //Position’s open volume in case of SELL trade side, = 0 in case of BUY trade side, is not set if PosReqResult(728) is not VALID_REQUEST.
                body.Append("705=" + shortQuantity + "|");
            }
            if (settlementPrice != string.Empty)
            {
                // Average price of the opened volume in the current PositionReport.
                body.Append("730=" + settlementPrice + "|");
            }
            var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.PositionReport), messageSequenceNumber, string.Empty);
            var headerAndBody = header + body;
            var trailer = ConstructTrailer(headerAndBody);
            var headerAndMessageAndTrailer = header + body + trailer;
            return headerAndMessageAndTrailer.Replace("|", "\u0001");
        }

        /// <summary>
        /// Constructs the message header.
        /// </summary>
        /// <param name="qualifier">The session qualifier.</param>
        /// <param name="type">The message type.</param>
        /// <param name="messageSequenceNumber">The message sequence number.</param>
        /// <param name="bodyMessage">The body message.</param>
        /// <returns></returns>
        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();
        }

        /// <summary>
        /// Constructs the message trailer.
        /// </summary>
        /// <param name="message">The message trailer.</param>
        /// <returns></returns>
        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;
        }

        /// <summary>
        /// Calculates the checksum.
        /// </summary>
        /// <param name="dataToCalculate">The data to calculate.</param>
        /// <returns></returns>
        private int CalculateChecksum(string dataToCalculate)
        {
            byte[] byteToCalculate = Encoding.ASCII.GetBytes(dataToCalculate);
            int checksum = 0;
            foreach (byte chData in byteToCalculate)
            {
                checksum += chData;
            }
            return checksum % 256;
        }

        /// <summary>
        /// Returns the session the message code.
        /// </summary>
        /// <param name="type">The session message type.</param>
        /// <returns></returns>
        private string SessionMessageCode(SessionMessageType type)
        {
            switch (type)
            {
                case SessionMessageType.Heartbeat:
                    return "0";
                //break;

                case SessionMessageType.Logon:
                    return "A";
                //break;

                case SessionMessageType.Logout:
                    return "5";
                // break;

                case SessionMessageType.Reject:
                    return "3";
                //break;

                case SessionMessageType.Resend:
                    return "2";
                //break;

                case SessionMessageType.SequenceReset:
                    return "4";
                //break;

                case SessionMessageType.TestRequest:
                    return "1";
                default:
                    //break;

                    return "0";
            }
        }

        /// <summary>
        /// Returns the application message code.
        /// </summary>
        /// <param name="type">The application message type.</param>
        /// <returns></returns>
        private string ApplicationMessageCode(ApplicationMessageType type)
        {
            switch (type)
            {
                case ApplicationMessageType.MarketDataRequest:
                    return "V";
                //break;

                case ApplicationMessageType.MarketDataIncrementalRefresh:
                    return "X";
                //break;

                case ApplicationMessageType.NewOrderSingle:
                    return "D";
                //break;

                case ApplicationMessageType.CancelOrderSingle:
                    return "F";
                // break;

                case ApplicationMessageType.OrderStatusRequest:
                    return "H";
                // break;

                case ApplicationMessageType.ExecutionReport:
                    return "8";
                //  break;

                case ApplicationMessageType.BusinessMessageReject:
                    return "j";
                //  break;

                case ApplicationMessageType.RequestForPosition:
                    return "AN";
                //  break;

                case ApplicationMessageType.PositionReport:
                    return "AP";
                default:
                    //   break;

                    return "0";
            }
        }
    }
}

 


@netread2004

netread2004
05 Nov 2018, 09:31

Looks like this is logON issue. I checked response for LogOn FIX message and the response is empty message.

As far as my original issue is concerend, I think it was arising due to sending logOn message to the server already Logged on and no Logout sent.

I will monitor this further and update on this.

 

Thanks

 

 


@netread2004