Required tag missing in Resend Request Message

Created at 21 Nov 2018, 14:22
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

Required tag missing in Resend Request Message
21 Nov 2018, 14:22


I am using FIX API Sample program with appropriate modifications to implement FIX Engine based Robot. To test out this code I am using simple robot that that takes Pending Stop Order and after 1000ms cancel this order.

I use following sequence of FIX messages to accomplish the above:

I send HeartBeat message every 10 sec.

1) Send Stop Order request FIX Message

2) Send Order Status Check FIX Message

3) Resend Request FIX Message until I receive 35=8 with 39=0

4) After Order is placed wait for 1000ms

5) Send Cancel Order FIX message.

I encountered following issue with this robot.

1) Resend Request gives error "Required Tag Missing". Please see following received message:
21/11/2018 11:43:59.349 | SendText : 8=FIX.4.4 9=90 35=2 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=9 52=20181121-11:43:57 16=8 10=233 
21/11/2018 11:43:59.349 | ReceivedText : 8=FIX.4.4 9=136 35=3 34=4 49=cServer 50=TRADE 52=20181121-11:43:59.241 56=circlemarkets.4000022 57=TRADE 45=9 58=Required tag missing 371=7 372=2 373=1 10=106 

Please note I modified code to use tag 7 in the message but that did not work.

2) The cancel order FIX message sometime fail to cancel the exisiting Pending stop order for some reason.

3) Eventually it crashed with the message which say closed by the remote host as follows:
21/11/2018 12:13:42.542Crashed in OnTick with IOException: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.

I am attaching code.

 

//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 = 1)]
        public int BarHeightThresh { 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("dispFIXMsges", DefaultValue = false)]
        public bool dispFIXMsges { 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;
        string initPriceForSL;
        string randomNum = "";
        double stopOrderPrice = 0;
        int symID = 0;
        string[] filledPosiitonID = 
        {
            ""
        };
        string filPosID;
        string avePricePosition;
        string clOrdNumGlob;
        int ordSide = 0;
        bool origStopOrdFilled = false;
        int totalPosGlob = 0;
        string clOrdIdForPosition = "";
        int closedPosNum = 0;
        double positionOpenPrc;
        string ordstpID;

        //FIX Credentials
        private int _pricePort = 5211;
        private int _tradePort = 5212;
        private string _host = "h28.p.ctrader.com";
        private string _username = "<user>";
        private string _password = ",password>";
        private string _senderCompID = "circlemarkets.<user>";
        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;

        BollingerBands bollingerBands;

        string globIDForCheckOrder = "";
        string globIdForSLCheckStat = "";
        string globIDStopOrd = null;
        int ordNumClosed = 0;
        int subIdIndx = 0;
        bool stpOrderCreated = false;
        int iterLoops = 0;
        bool orderCancelledTriggered = false;
        PendingOrder OrderstopRes;
        PendingOrderType ordSide1;


        protected override void OnStart()
        {
            bollingerBands = Indicators.BollingerBands(Source, Periods, Deviations, MAType);

            Print("Send Quote LogOn Message....");
            Logon();
            Print("Market Data Request for EURUSD and GBPUSD ..");
            SpotMarketData(1);
            SpotMarketData(2);
            Print("Send Trade LogOn Message....");
            LogonT();
            Timer.TimerTick += OnTimerTick;
            Timer.Start(10);
            //start timer with 10 second interval
            Positions.Closed += PositionsOnClosed;
            PendingOrders.Filled += PendingOrdersOnFilled;
            PendingOrders.Created += PendingOrdersOnCreated;
            PendingOrders.Cancelled += PendingOrdersOnCancelled;
        }
        protected override void OnStop()
        {
            LogoutT();
            Logout();
        }
        private void OnTimerTick()
        {
            HeartbeatT();
            Heartbeat();
            Print("HeartBeat is sent every 10 sec " + Time.ToString("HH:mm:ss"));
            Chart.DrawStaticText("time", Time.ToString("HH:mm:ss") + " HearBeat Sent every 10sec", VerticalAlignment.Bottom, HorizontalAlignment.Left, Color.Lime);

        }
        private void PendingOrdersOnCreated(PendingOrderCreatedEventArgs args)
        {
            stopOrderPrice = args.PendingOrder.TargetPrice;
            Print("Pending order with id {0} was created @ Price {1}", args.PendingOrder.Id + " " + args.PendingOrder.SymbolCode, stopOrderPrice);

            orderCancelledTriggered = false;
            OrderstopRes = args.PendingOrder;
            ordSide1 = args.PendingOrder.OrderType;
            ordSide = (int)ordSide1;
            Chart.DrawStaticText("numpend", "\n\n\n\n\n\n\n\n\n\n NumPend   : " + args.PendingOrder.Id + " " + args.PendingOrder.SymbolCode + " " + args.PendingOrder.TradeType + " " + args.PendingOrder.OrderType + " " + stopOrderPrice, VerticalAlignment.Top, HorizontalAlignment.Left, Color.White);
        }
        private void PendingOrdersOnCancelled(PendingOrderCancelledEventArgs args)
        {
            Print("Pending order with id {0} was cancelled. Reason: {1}", args.PendingOrder.Id, args.Reason);
            Chart.DrawStaticText("pendcanc", "\n\n\n\n\n\n\n\n\n\n\n\n PendCancelled   : " + args.PendingOrder.Id + " CancelTrigg : " + orderCancelledTriggered, VerticalAlignment.Top, HorizontalAlignment.Left, Color.Lime);
            stpOrderCreated = false;
            stopLossPlaced = false;

        }
        private void PendingOrdersOnFilled(PendingOrderFilledEventArgs args)
        {

            Print("Pending order with id {0} was filled, position id  is {1}", args.PendingOrder.Id, args.Position.Id);
            filPosID = Convert.ToString(args.Position.Id);
            positionOpenPrc = args.Position.EntryPrice;
            Print("Position opened at {0}", positionOpenPrc);
            origStopOrdFilled = true;

        }
        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            var position = args.Position;
            Print("Position closed with {0} profit", position.GrossProfit);
            stopLossPlaced = false;
            clOrdNumGlob = "";
            origStopOrdFilled = false;
            initPriceForSL = "";
            filPosID = "";
            globIDForCheckOrder = "";
            globIdForSLCheckStat = "";
            globIDForCheckOrder = "";
            globIdForSLCheckStat = "";
            globIDStopOrd = null;
            subIdIndx++;
            ordNumClosed++;
            Print("Order # ", ordNumClosed, " Closed Successfully!!!!    -------------");
            orderCancelledTriggered = false;
        }


        protected override void OnTick()
        {
            var top = bollingerBands.Top.Last(1);
            var bottom = bollingerBands.Bottom.Last(1);
            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 (dispFIXMsges)
                displaySendReceive();
            if (barHeight >= 0.5 * Symbol.PipSize && ((Symbol.Ask - Symbol.Bid) < allowedSpread * Symbol.PipSize))
            {
                if (Symbol.Bid > top)
                {
                    ordSide = 2;
                    ordstpID = getRandomNumber("ToStartSELL");
                    globIDStopOrd = ordstpID;
                    placeSimpleStopOrder(2, ordstpID);
                    //firstTimePlace = true;
                    globIDForCheckOrder = ordstpID;
                }
                else if (Symbol.Ask < bottom)
                {
                    ordSide = 1;
                    ordstpID = getRandomNumber("ToStartBUY");
                    globIDStopOrd = ordstpID;
                    placeSimpleStopOrder(1, ordstpID);
                    //firstTimePlace = true;
                    globIDForCheckOrder = ordstpID;
                }
            }
        }


        private void placeSimpleStopOrder(int odSide, string clntOrdID)
        {
            if (Symbol.Code == "EURUSD")
                symID = EURUSD;
            if (Symbol.Code == "GBPUSD")
                symID = GBPUSD;
            if (symID > 0)
            {
                if (PendingOrders.Count == 0 && !stpOrderCreated)
                {
                    if (odSide == 1)
                    {
                        if (clntOrdID != "")
                        {
                            if (!stpOrderCreated)
                            {
                                stopOrderPrice = Symbol.Ask + (2.0 * Symbol.PipSize);
                                StopOrder(symID, 1000, stopOrderPrice, clntOrdID, odSide, "");
                                Print("BuyStop Order Placed @{0}", stopOrderPrice);
                                OrderStatusRequest(clntOrdID, symID, odSide);
                                ResendRequestT();
                                ResendRequestT();
                            }
                            iterLoops = 0;
                            while (!stpOrderCreated && iterLoops < 30)
                            {
                                ResendRequestT();
                                printSendReceive();
                                iterLoops++;
                                Print("stpOrderCreated 35=8 inside : ", stpOrderCreated, " Iter# : ", iterLoops);
                                Print("BuyStop Order place Trail # ", iterLoops);
                            }
                            string prce = Convert.ToString(Math.Round((stopOrderPrice - Symbol.Ask) / Symbol.PipSize, 1));
                            Print("BuyStop Order place outOfLoop Trail # ", iterLoops, " @Price : ", stopOrderPrice, " Offset : ", prce);
                        }
                    }
                    if (odSide == 2)
                    {
                        if (clntOrdID != "")
                        {
                            if (!stpOrderCreated)
                            {
                                stopOrderPrice = Symbol.Bid - (2.0 * Symbol.PipSize);
                                StopOrder(symID, 1000, stopOrderPrice, clntOrdID, odSide, "");
                                Print("SellStop Order Placed @{0}", stopOrderPrice);
                                OrderStatusRequest(clntOrdID, symID, odSide);
                                ResendRequestT();
                                ResendRequestT();
                            }
                            iterLoops = 0;

                            while (!stpOrderCreated && iterLoops < 30)
                            {


                                ResendRequestT();
                                printSendReceive();
                                iterLoops++;
                                Print("stpOrderCreated 35=8 inside : ", stpOrderCreated, " Iter# : ", iterLoops);

                                Print("SellStop Order place Trail # ", iterLoops);
                            }
                            string prce1 = Convert.ToString(Math.Round((Symbol.Bid - stopOrderPrice) / Symbol.PipSize, 1));
                            Print("SellStop Order place putofLoop Trail # ", iterLoops, " @Price : ", stopOrderPrice, " Offset : ", prce1);


                        }
                    }
                }
                if (stpOrderCreated)
                {
                    Thread.Sleep(1000);
                    orderCancelledTriggered = false;
                    Print("Cancel Stop Order ");
                    string newOrdIDbeforeCancel = getRandomNumber("ToCancelSTOP");
                    CancelOrder(newOrdIDbeforeCancel, clntOrdID);
                    printSendReceive();
                    OrderStatusRequest(clntOrdID, symID, odSide);
                    iterLoops = 0;
                    while (!orderCancelledTriggered && iterLoops < 30)
                    {
                        ResendRequestT();
                        printSendReceive();
                        Print("Resend Cancel");
                        iterLoops++;
                    }
                    stpOrderCreated = false;
                }
            }
        }

        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 displaySendReceive()
        {
            string recString = txtMessageReceived_Text.Replace("\u0001", " ");
            string sentStrng = txtMessageSend_Text.Replace("\u0001", " ");

            bool heartb = sentStrng.Contains(" 35=0 ");
            if (!heartb)
            {
                Chart.DrawStaticText("sentmsg", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n SentMessage   : " + sentStrng, VerticalAlignment.Top, HorizontalAlignment.Left, Color.Lime);
                Chart.DrawStaticText("recdmsg", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n SentMessage   : " + recString, VerticalAlignment.Top, HorizontalAlignment.Left, Color.Gold);
            }
        }
        private void deCryptMessage(string sentMssg, string recvdMessg)
        {
            //Sent message decrypt
            string[] sep = 
            {
                "\u0001"
            };


            bool hit39 = false, hit721 = false, hit6 = false, hit150 = false, hit11 = false;
            string hit39Val = "", hit721Val = "", hit6Val = "", hit150Val = "", hit11Val = "";
            bool hit35 = false, hit11sen = false, hit41 = false, hit710 = false;
            string tagtyp = "", sen11Val = "", sen41Val = "", sen710Val = "";
            bool validMsg = false;
            bool rec41 = false, getCurOrdStat = false, getPositiobID = false, getAvePrice = false, filledOrNot = false, orderSide = false, rec11 = false;
            bool hit41Rec = true;
            string hit41RecVal = "";
            bool rec99 = false;
            bool hit99Rec = false;
            string hit99RecVal = "";
            bool checkForStPrce = false;
            bool rec35 = false;
            bool hit35Rec = false;
            string hit35RecVal = "";
            bool rec705 = false;
            bool rec727 = false, rec728 = false;
            bool hit727 = false, hit728 = false;
            string hit727Val = "", hit728Val = "";
            bool rec710 = false, hitRec710 = false;
            string hitRec710Val = "";
            string prevClosedClOrdID = "", prevfilPosID = "", prevHit11OrdID = "";
            string[] result = sentMssg.Split(sep, System.StringSplitOptions.RemoveEmptyEntries);
            int arrLengthSen = result.Length;
            int actualLen = 0;

            for (int i = 0; i < arrLengthSen; i++)
            {
                if (deCryptNoPrint)
                    Print("Sent Field# ", i, " FieldContent : ", result[i]);
                actualLen++;
                bool newOrd = result[i].StartsWith("35=");
                bool sen11 = result[i].StartsWith("11=");
                bool sen41 = result[i].StartsWith("41=");
                bool sen710 = result[i].StartsWith("710=");

                string[] sep1 = 
                {
                    "="
                };

                string[] receiveMsg = result[i].Split(sep1, System.StringSplitOptions.RemoveEmptyEntries);
                if (newOrd)
                {
                    tagtyp = receiveMsg[1];
                    hit35 = true;

                }
                if (sen11)
                {
                    sen11Val = receiveMsg[1];
                    hit11sen = true;

                }

                if (sen41)
                {
                    sen41Val = receiveMsg[1];
                    hit41 = true;
                }

                if (sen710)
                {
                    sen710Val = receiveMsg[1];
                    hit710 = true;
                }
                bool containsSearchResult = result[i].StartsWith("10=");
                if (containsSearchResult)
                    break;
            }
            if (deCryptNoPrint)
                Print("ArrayLengthSent : ", actualLen);
            //Receive message
            result = recvdMessg.Split(sep, System.StringSplitOptions.RemoveEmptyEntries);
            int arrLengthRec = result.Length;
            actualLen = 0;
            for (int i = 0; i < arrLengthRec; i++)
            {
                if (deCryptNoPrint)
                    Print("Rec Field# ", i, " FieldContent : ", result[i]);
                actualLen++;
                getCurOrdStat = result[i].StartsWith("39=");
                getPositiobID = result[i].StartsWith("721=");
                getAvePrice = result[i].StartsWith("6=");
                filledOrNot = result[i].StartsWith("150=");
                orderSide = result[i].StartsWith("54=");
                rec11 = result[i].StartsWith("11=");
                rec41 = result[i].StartsWith("41=");
                rec99 = result[i].StartsWith("99=");
                rec35 = result[i].StartsWith("35=");
                rec705 = result[i].StartsWith("705=");
                rec727 = result[i].StartsWith("727=");
                //rec727 number of positions
                rec728 = result[i].StartsWith("728=");
                //rec728 no such position
                rec710 = result[i].StartsWith("710=");

                string[] sep1 = 
                {
                    "="
                };

                string[] recedTextParts = result[i].Split(sep1, System.StringSplitOptions.RemoveEmptyEntries);
                if (getCurOrdStat)
                {
                    hit39 = true;
                    hit39Val = recedTextParts[1];
                }
                if (getPositiobID)
                {
                    hit721 = true;
                    hit721Val = recedTextParts[1];
                }
                if (getAvePrice)
                {
                    hit6 = true;
                    hit6Val = recedTextParts[1];
                }
                if (filledOrNot)
                {
                    hit150 = true;
                    hit150Val = recedTextParts[1];
                }

                if (rec11)
                {
                    hit11 = true;
                    hit11Val = recedTextParts[1];
                }
                if (rec41)
                {
                    hit41Rec = true;
                    hit41RecVal = recedTextParts[1];
                }
                if (rec99)
                {
                    hit99Rec = true;
                    hit99RecVal = recedTextParts[1];
                }
                if (rec35)
                {
                    hit35Rec = true;
                    hit35RecVal = recedTextParts[1];
                }

                if (rec727)
                {
                    hit727 = true;
                    hit727Val = recedTextParts[1];
                }
                if (rec728)
                {
                    hit728 = true;
                    hit728Val = recedTextParts[1];
                }
                if (rec710)
                {
                    hitRec710 = true;
                    hitRec710Val = recedTextParts[1];
                }
                bool containsSearchResult = result[i].StartsWith("10=");
                if (containsSearchResult)
                    break;
            }


            if (hit35Rec)
            {

                Print("hit35RecVal : ", hit35RecVal, " hit39Val : ", hit39Val, " hit39 : ", hit39);
                if (hit35RecVal == "8" && hit39Val == "0" && hit39)
                {
                    stpOrderCreated = true;
                    Print("stpOrderCreated 35=8 : ", stpOrderCreated);
                    printSendReceive();
                }

                if (hit35RecVal == "8" && hit39Val == "4" && hit39)
                {
                    orderCancelledTriggered = true;

                }
            }

            if (hit35 && tagtyp == "H" && hit11sen)
            {
                if (hit35Rec && hit35RecVal == "8" && hit11 && hit11Val == globIDStopOrd)
                {
                    if (hit150)
                    {
                        if (hit150Val == "0" && origStopOrdFilled)
                        {
                            //printSendReceive();
                            //Print("False - Sen11Val : ", sen11Val, " GlobID : ", globIDStopOrd);
                        }

                        if (hit150Val == "F")
                        {
                            // origStopOrdFilled = true;
                            //Print("True - Sen11Val : ", sen11Val, " GlobID : ", globIDStopOrd);
                            //printSendReceive();
                        }
                    }
                }
            }
            if (hit35)
            {
                if (hit11sen && hit11 && (tagtyp == "H" || tagtyp == "D"))
                {
                    bool comres = sen11Val.Equals(hit11Val, StringComparison.Ordinal);
                    if (comres)
                    {
                        validMsg = true;
                    }
                }
                //Following is for Position SL stop Order
                if (hit41 && hit41Rec && tagtyp == "F")
                {
                    bool comres = sen41Val.Equals(hit41RecVal, StringComparison.Ordinal);
                    if (comres)
                    {
                        validMsg = true;
                    }
                }
                //FOllowing is for pure Stop Order
                if (hit41 && hit11 && tagtyp == "F")
                {
                    bool comres = sen41Val.Equals(hit11Val, StringComparison.Ordinal);
                    if (comres)
                    {
                        validMsg = true;
                    }
                }
                if (hit721 && hit710 && tagtyp == "AN")
                {
                    bool comres = sen710Val.Equals(hit721Val, StringComparison.Ordinal);
                    if (comres)
                    {
                        validMsg = true;
                    }
                }
                if (hit35Rec)
                {
                    bool checkAp = hit35RecVal.Equals("AP", StringComparison.Ordinal);
                    bool checkAn = tagtyp.Equals("AN", StringComparison.Ordinal);

                    if (checkAn && checkAp)
                    {
                        bool positRep = false;
                        if (hitRec710 && hit710)
                        {
                            double hitRec710ValD = Convert.ToDouble(hitRec710Val);
                            double sen710ValD = Convert.ToDouble(sen710Val);

                            if (hitRec710ValD == sen710ValD && hit727 && hit728)
                            {
                                positRep = true;
                                // globPositionID = hitRec710Val;
                            }
                        }

                        if (hit727Val == "0" && hit728Val == "2" && positRep)
                        {


                            closedPosNum++;
                            if (hit11)
                            {
                                prevHit11OrdID = hit11Val;

                            }
                            prevfilPosID = filPosID;
                            filPosID = "";
                            prevClosedClOrdID = clOrdIdForPosition;
                            clOrdIdForPosition = "";

                        }

                    }
                }
            }


            if (hit35Rec && hit35RecVal == "8" && hit35 && tagtyp == "H")
            {
                if (hit150 && hit150Val == "F" && hit721)
                {

                    bool prevIDCompare = false;
                    if (hit39 && hit39Val == "2")
                    {
                        if (hit11)
                        {
                            clOrdIdForPosition = hit11Val;
                            prevIDCompare = hit11Val.Equals(prevHit11OrdID, StringComparison.Ordinal);
                        }
                        if (!prevIDCompare)
                        {
                            //origStopOrdFilled = true;

                        }

                        if (hit721)
                        {
                            filPosID = hit721Val;
                            //globPositionID = hit721Val;

                        }

                        if (hit99Rec)
                        {
                            initPriceForSL = hit99RecVal;
                        }

                    }


                }
            }
            if (hit11)
            {
                bool comres = hit11Val.Equals(globIDForCheckOrder, StringComparison.Ordinal);


            }


            if (validMsg)
            {
                if (stopLossPlaced)
                {
                    bool comres = hit11Val.Equals(clOrdNumGlob, StringComparison.Ordinal);
                    if (hit11 && comres)
                    {
                        //lookForPrice = true;

                    }



                }
                if (hit721 && hit710 && tagtyp == "AN" && hit150 && hit150Val == "F")
                {
                    bool comres = sen710Val.Equals(hit721Val, StringComparison.Ordinal);
                    if (comres)
                    {
                        //posReqStatFilled = true;
                    }
                }



                if (hit11)
                {
                    bool comres = hit11Val.Equals(globIdForSLCheckStat, StringComparison.Ordinal);

                    if (comres && tagtyp == "H")
                    {
                        checkForStPrce = true;
                    }
                    else
                    {
                        checkForStPrce = false;
                    }
                }


                if (hit6 && checkForStPrce)
                {

                    avePricePosition = hit6Val;

                }



            }

            if (deCryptNoPrint)
                Print("ArrayLengthRec : ", actualLen);
        }

        //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 Logon()
        {
            ClearText();
            var message = _messageConstructor.LogonMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, 30, true);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);

        }

        private void TestRequest()
        {
            ClearText();
            var message = _messageConstructor.TestRequestMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, _testRequestID);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

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

        private void MarketDataRequest()
        {
            ClearText();
            var message = _messageConstructor.MarketDataRequestMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, "EURUSD:WDqsoT", 1, 0, 0, 1, 1);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

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

        private void ResendRequest()
        {
            ClearText();
            var message = _messageConstructor.ResendMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, _messageSequenceNumber - 1);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

        private void Reject()
        {
            ClearText();
            var message = _messageConstructor.RejectMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, 0);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

        private void SequenceReset()
        {
            ClearText();
            var message = _messageConstructor.SequenceResetMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, 0);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

        private void NewOrderSingle()
        {
            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);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

        private void OrderStatusRequest(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 RequestForPositions(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 LogonT()
        {
            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 HeartbeatT()
        {
            ClearText();
            var message = _messageConstructor.HeartbeatMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message, false);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

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

        private void LogoutT()
        {
            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 ResendRequestT()
        {
            ClearText();
            var message = _messageConstructor.ResendMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, _messageSequenceNumber - 1);
            _testRequestID++;
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendTradeMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

        private void SpotMarketData(int symbCode)
        {
            ClearText();
            var message = _messageConstructor.MarketDataRequestMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, "EURUSD:WDqsoT", 1, 1, 0, 1, symbCode);
            txtMessageSend_Text = message;
            txtMessageReceived_Text = SendPriceMessage(message);
            if (printWholeFixMsg)
                printSendReceive();
            if (deCryptEn)
                deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text);
        }

        private void StopOrder(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 CancelOrder(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 LimitOrder()
        {
            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();
            //I added Tag 7 becasue it was missing
            //body.Append("7=" + endSequenceNo + "|");
            //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
Replies

PanagiotisCharalampous
21 Nov 2018, 15:30

Hi netread2004,

1) I added tag 7 and worked fine. Can you please share the message with tag 7 and the response you receive?

2) I will need more information like the messages sent and received. 

3) This is probably caused due to the other issues.

Best Regards,

Panagiotis


@PanagiotisCharalampous

netread2004
21 Nov 2018, 18:19

Hi Panagiotis,

Sorry what I meant was my Robot did not work that is it stopped taking STOP orders.

When I added Tag 7 it stopped giving me "Missing Tag" error but my Robot stopped working because it never received any FIX message with 35=8.  It always received 35=4 (Sequence Reset) message. So, obviously which does not indicate any STOP Order placed.

Here are the FIX messages sent and received when it strated giving Resend Request to first Order Check Message:

21/11/2018 16:02:23.080 | SendText : 8=FIX.4.4 9=104 35=H 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=6 52=20181121-16:01:51 11=1362478880 54=1 10=203 
21/11/2018 16:02:23.080 | ReceivedText : 8=FIX.4.4 9=89 35=0 34=3 49=cServer 50=TRADE 52=20181121-16:02:23.062 56=circlemarkets.4000022 57=TRADE 10=203 

 

21/11/2018 16:02:23.315 | SendText : 8=FIX.4.4 9=94 35=2 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=7 52=20181121-16:02:21 7=6 16=6 10=139 
21/11/2018 16:02:23.315 | ReceivedText : 8=FIX.4.4 9=127 35=4 34=6 43=Y 49=cServer 50=TRADE 52=20181121-16:02:23.281 56=circlemarkets.4000022 57=TRADE 122=20181121-16:02:23 36=4 123=Y 10=054 

 

21/11/2018 16:02:23.533 | SendText : 8=FIX.4.4 9=94 35=2 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=8 52=20181121-16:02:21 7=7 16=7 10=142 
21/11/2018 16:02:23.533 | ReceivedText : 8=FIX.4.4 9=127 35=4 34=7 43=Y 49=cServer 50=TRADE 52=20181121-16:02:23.526 56=circlemarkets.4000022 57=TRADE 122=20181121-16:02:23 36=4 123=Y 10=057 

 

As you can see the first message from the above is 35=H (Order Check Request) with 34=6 and in response I received 35=0 which I can ignore I guess. Following this message it sent Resend Request (35=2) with 7=6 ( 6 is the sequence number of earlier Order Check message indicating it is Resending this Order Check Message) and since there in only one message to send 7=6 as well as 16=6.

After this Resent request it sends another Resend Request and it receives all the time 35=4 (Sequence Reset) message and it never received 35=8. This goes on in the loop and therefore my Robot wont take any stop order.

Not sure what is the meaning of this received message 35=4. Does it mean I need to send Reset Response message. Not sure. Please let me know.

 

Thanks for your prompt response to my earlier message.

 


@netread2004

PanagiotisCharalampous
22 Nov 2018, 09:59

Hi netread2004,

The problem could be that the order is never accepted. Can you post your order message as well? Maybe there is a problem there.

Best Regards,

Panagiotis


@PanagiotisCharalampous

netread2004
22 Nov 2018, 12:07

Here is the sequence of messages right from the begining LogOn to QUOTE server:

 

1)LogOn to Quote

22/11/2018 09:49:22.168 | SendText : 8=FIX.4.4 9=128 35=A 49=circlemarkets.4000022 56=cServer 57=QUOTE 50=TRADE 34=1 52=20181122-09:49:19 98=0 108=30 141=Y 553=4000022 554=qwerty12 10=211 

22/11/2018 09:49:22.168 | ReceivedText : 8=FIX.4.4 9=107 35=A 34=1 49=cServer 50=QUOTE 52=20181122-09:49:22.069 56=circlemarkets.4000022 57=TRADE 98=0 108=30 141=Y 10=121 

 

2)Get Spot Market data for EURUSD

22/11/2018 09:49:22.371 | SendText : 8=FIX.4.4 9=150 35=V 49=circlemarkets.4000022 56=cServer 57=QUOTE 50=TRADE 34=2 52=20181122-09:49:20 262=EURUSD:WDqsoT 263=1 264=1 265=1 267=2 269=0 269=1 146=1 55=1 10=214 

22/11/2018 09:49:22.371 | ReceivedText : 8=FIX.4.4 9=136 35=W 34=2 49=cServer 50=QUOTE 52=20181122-09:49:22.276 56=circlemarkets.4000022 57=TRADE 55=1 268=2 269=0 270=1.14064 269=1 270=1.14068 10=194 

 

3)Get Spot Market data for GBPUSD

22/11/2018 09:49:22.574 SendText : 8=FIX.4.4 9=150 35=V 49=circlemarkets.4000022 56=cServer 57=QUOTE 50=TRADE 34=3 52=20181122-09:49:20 262=EURUSD:WDqsoT 263=1 264=1 265=1 267=2 269=0 269=1 146=1 55=2 10=216

22/11/2018 09:49:22.574 | ReceivedText : 8=FIX.4.4 9=136 35=W 34=3 49=cServer 50=QUOTE 52=20181122-09:49:22.484 56=circlemarkets.4000022 57=TRADE 55=2 268=2 269=0 270=1.27906 269=1 270=1.27913 10=209 

 

4)LogOn to TRADE server

22/11/2018 09:49:22.840 | SendText : 8=FIX.4.4 9=122 35=A 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=4 52=20181122-09:49:20 98=0 108=30 553=4000022 554=qwerty12 10=125 

22/11/2018 09:49:22.840 | ReceivedText : 8=FIX.4.4 9=101 35=A 34=1 49=cServer 50=TRADE 52=20181122-09:49:22.738 56=circlemarkets.4000022 57=TRADE 98=0 108=30 10=043 

 

5)Send New Stop Order 35=D 40=3, 54=2 for GBPUSD 55=2

22/11/2018 09:49:39.574 | SendText : 8=FIX.4.4 9=158 35=D 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=7 52=20181122-09:49:37 11=976009052 55=2 54=2 60=20181122-09:49:37 38=1000 40=3 99=1.27889 59=3 10=219 

22/11/2018 09:49:39.574 | ReceivedText : 8=FIX.4.4 9=98 35=2 34=2 49=cServer 50=TRADE 52=20181122-09:49:32.955 56=circlemarkets.4000022 57=TRADE 7=2 16=0 10=097 

 

6)I send OrderStatus Check 35=H

22/11/2018 09:50:03.153 | SendText : 8=FIX.4.4 9=103 35=H 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=8 52=20181122-09:49:37 11=976009052 54=2 10=167 

22/11/2018 09:50:03.153 ReceivedText : 8=FIX.4.4 9=89 35=0 34=3 49=cServer 50=TRADE 52=20181122-09:50:03.063 56=circlemarkets.4000022 57=TRADE 10=208 

 

7)I Send Resend Request for above Order Status Check 7=8 16=8

22/11/2018 09:50:03.356 | SendText : 8=FIX.4.4 9=94 35=2 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=9 52=20181122-09:50:01 7=8 16=8 10=149 

22/11/2018 09:50:03.356 | ReceivedText : 8=FIX.4.4 9=127 35=4 34=8 43=Y 49=cServer 50=TRADE 52=20181122-09:50:03.265 56=circlemarkets.4000022 57=TRADE 122=20181122-09:50:03 36=4 123=Y 10=066 

 

8)I receieve ResetSequence message and I keep sending ResendRequest and this goes on in loop and Stop Order is never placed.

22/11/2018 09:50:03.559 | SendText : 8=FIX.4.4 9=95 35=2 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=10 52=20181122-09:50:01 7=9 16=9 10=192 

22/11/2018 09:50:03.559 | ReceivedText : 8=FIX.4.4 9=127 35=4 34=9 43=Y 49=cServer 50=TRADE 52=20181122-09:50:03.462 56=circlemarkets.4000022 57=TRADE 122=20181122-09:50:03 36=4 123=Y 10=066 

Please let me know if you need anything else.

thanks

 


@netread2004

PanagiotisCharalampous
22 Nov 2018, 12:22

Hi netread2004,

In tag 59 of your stop order message you use value 3. As per our Rules of Engagement, you need to use either 1 or 6. 3 can be used only for market orders. Can you please fix and try again?

Best Regards,

Panagiotis


@PanagiotisCharalampous

netread2004
22 Nov 2018, 13:23

Here is the Stop Order with 59=1 (GTC) sequence:

1)Stop Order 59=1
22/11/2018 11:15:25.995 | SendText : 8=FIX.4.4 9=158 35=D 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=5 52=20181122-11:15:23 11=836669846 55=2 54=1 60=20181122-11:15:23 38=1000 40=3 99=1.28907 59=1 10=186 
22/11/2018 11:15:25.995 | ReceivedText : 8=FIX.4.4 9=98 35=2 34=2 49=cServer 50=TRADE 52=20181122-11:15:26.004 56=circlemarkets.4000022 57=TRADE 7=2 16=0 10=071 

2)Order Status check 35=H 34=6
22/11/2018 11:15:56.058 | SendText : 8=FIX.4.4 9=103 35=H 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=6 52=20181122-11:15:24 11=836669846 54=1 10=164 
22/11/2018 11:15:56.058 | ReceivedText : 8=FIX.4.4 9=89 35=0 34=3 49=cServer 50=TRADE 52=20181122-11:15:56.062 56=circlemarkets.4000022 57=TRADE 10=209 

3)Resend Order Status Check 7=6 16=6
22/11/2018 11:15:56.276 | SendText : 8=FIX.4.4 9=94 35=2 49=circlemarkets.4000022 56=cServer 57=TRADE 50=TRADE 34=7 52=20181122-11:15:54 7=6 16=6 10=145 
22/11/2018 11:15:56.292 | ReceivedText : 8=FIX.4.4 9=127 35=4 34=6 43=Y 49=cServer 50=TRADE 52=20181122-11:15:56.267 56=circlemarkets.4000022 57=TRADE 122=20181122-11:15:56 36=4 123=Y 10=070 

I receive 35=4 for above Rsend Order and it goes on in loop, I send 35=2 and in response I get 35=4


@netread2004

PanagiotisCharalampous
22 Nov 2018, 14:45

Hi netread2004,

Something is wrong with your stop order but unfortunately I cannot reproduce this behavior. You should be getting an execution report and not a resend message. I used your details to send the below message for a stop order and I get an execution report and a successful order placement 

Order

8=FIX.4.49=15135=D49=circlemarkets.400002256=CSERVER57=TRADE50=TRADE34=252=20181122-12:43:4411=1055=254=160=20181122-12:43:4338=100040=399=1.2890759=110=114

Execution Report

8=FIX.4.49=20335=834=249=CSERVER50=TRADE52=20181122-12:43:44.18956=circlemarkets.400002257=TRADE11=1014=037=3195938=100039=040=354=155=259=160=20181122-12:43:44.18199=1.28907150=0151=1000721=1806810=214

Can you let me know if the order has been placed on your cTrader.

Best Regards,

Panagiotis


@PanagiotisCharalampous

netread2004
22 Nov 2018, 15:49

Yes I can see that Order ID 37=31959 (as OID31959 in cTrader) is placed in my cTrader. 

Not sure what the issue is with my environment.

Is there anything you can suggest me to try to root-cause this issue in my environment?

 

 


@netread2004

PanagiotisCharalampous
22 Nov 2018, 15:52

Hi netread2004,

I used the FIX API example application to send the order. I would suggest you try it as well and make sure the order is placed. Maybe something was messed up on code transfering.

Best Regards,

Panagiotis


@PanagiotisCharalampous

netread2004
22 Nov 2018, 16:01

Hi Panagiotis,

Did you use the same sequence of command I used?

1. logOn to Quote

2. Subscribe to Spot Market Data for EURUSD and GBPUSD

3. LogOn to TRADE

4. Place StopOrder for GBPUSD

 

Because when I don't subscribe to SPOT Market data I get execution report in response to Stop Order message.

This happens only when I LogOn to QUOTE and Subscribe to SPOT Market Data.

Please try this from your side to reproduce this issue.

 


@netread2004

netread2004
22 Nov 2018, 16:04

RE:

Panagiotis Charalampous said:

Hi netread2004,

I used the FIX API example application to send the order. I would suggest you try it as well and make sure the order is placed. Maybe something was messed up on code transfering.

Best Regards,

Panagiotis

I used same FIX API example application as well but  I can see the same issue there. Probably you did not log on to QUOTE server and did not subscribe to SPOT Market Data that is the reason you are able to get the execution report. I get Execution report when I DO NOT log on to Quote server and DO NOT subscribe to SPOT Market Data.

Could you please try using the same sequence as I used so that you can reproduce this issue.

 


@netread2004

PanagiotisCharalampous
22 Nov 2018, 16:20

Hi netread2004,

Ok now I understand. The reason this happens is because the two streams share the same message sequence number while they should not. You need to keep a separate sequence number for quote stream and for trade stream. I will try to update the example project soon to take this into consideration.

Best Regards,

Panagiotis


@PanagiotisCharalampous

netread2004
22 Nov 2018, 17:23

Hi Panagiotis,

I created two seperate counters for Sequence numbers and it is working now. I get execution report after I send Stop Order.

Thanks for your help.

I have more general question on using this FIX API sample code to implement my FIX Engine based Robot -- What I see here is this piece of code from Sample FIX API works perfectly alright and as long as I send correct FIX messages and decrypt received FIX messages correctly and implement logic around this send/receive info I think there should NOT be any other issue in implementing 100% correct Robot.  I am not checking CheckSum seperatly to validate the messages but I think it should not matter much. Apart from these concern what do you think there could be other issues that may affect implementation of Robot down the line?

Ypur input on this will be very helpful to move forward in implementing this Robot.

Please let me know.

 

 

 


@netread2004

PanagiotisCharalampous
23 Nov 2018, 10:03

Hi netread2004,

It is a very general question to give a specific answer. It all depends on what you are trying to do. The only advice I can provide is that the sample application has been developed with a sole purpose of demonstrating how to send and receive FIX messages using cTrader FIX API. It has not been designed for use in production software, therefore you should be very cautious if you decide to use any of its components in your cBot and make sure your cBot passes a rigorous testing procedure. 

Best Regards,

Panagiotis


@PanagiotisCharalampous