Crashed in OnTick with IOException
Crashed in OnTick with IOException
29 Oct 2018, 02:15
I am using FIX API Sample program to implement FIX engine in cTrader.
I am getting this crash quite often with following message:
29/10/2018 00:07:56.238 | Crashed in OnTick with IOException: Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.
I am using HeartBeat every 10 second. Still I am not able to get rid of this error. This makes my FIX engine program unsuable.
Could you please give me some idea why this is happening and any work-around you have to fix this issue.
Thanks,
Replies
netread2004
05 Nov 2018, 02:34
RE:
Panagiotis Charalampous said:
Hi netread2004,
Can you share the cBot code so that we can reproduce the issue?
Best Regards,
Panagiotis
Here is the error messages I am getting now when I run this code.
05/11/2018 00:27:49.254 | cBot "FIXengine_iCMarkets_test" was started successfully for GBPUSD, m1.
05/11/2018 00:28:09.613 | Crashed in OnTimer with IOException: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.
05/11/2018 00:28:09.613 | Crashed in OnStop with IOException: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.
05/11/2018 00:28:09.629 | cBot "FIXengine_iCMarkets_test" was stopped for GBPUSD, m1.
Please change FIX credential appropriatly to match with your server while testing it in your environment.
//using FIX_API_Library; using System; using System.Linq; using cAlgo.API; using cAlgo.API.Indicators; using cAlgo.API.Internals; using cAlgo.Indicators; using System.Net.Security; using System.Net.Sockets; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; namespace cAlgo { [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)] public partial class frmFIXAPISample : Robot { [Parameter("Source")] public DataSeries Source { get; set; } [Parameter("Stop Loss (pips)", DefaultValue = 1.3, MinValue = 1)] public double StopLossInPips { get; set; } [Parameter("Take Profit (pips)", DefaultValue = 100.0, MinValue = 1)] public double TakeProfitInPips { get; set; } [Parameter("Quantity (Lots)", DefaultValue = 0.01, MinValue = 0.01, Step = 0.01)] public double Quantity { get; set; } [Parameter("Bollinger Bands Deviations", DefaultValue = 0.5)] public double Deviations { get; set; } [Parameter("Bollinger Bands Periods", DefaultValue = 2)] public int Periods { get; set; } [Parameter("Bollinger Bands MA Type")] public MovingAverageType MAType { get; set; } [Parameter("BarHeight Thresh", DefaultValue = 16)] public int BarHeightThresh { get; set; } [Parameter("pipUpDn Thresh", DefaultValue = 180)] public double pipUpDnThresh { get; set; } [Parameter("Tralling Stop (pips)", DefaultValue = 1.3)] public double StopLoss { get; set; } [Parameter("Inital Stop Loss (pips)", DefaultValue = 1.3)] public double init_StopLoss { get; set; } [Parameter("RiskPC", DefaultValue = 10.0)] public double risk { get; set; } [Parameter("AllowedSpread", DefaultValue = 2.0)] public double allowedSpread { get; set; } [Parameter("toDisp", DefaultValue = true)] public bool toDisp { get; set; } [Parameter("ordNumDisp", DefaultValue = false)] public bool ordNumDisp { get; set; } [Parameter("printWholeFixMsg", DefaultValue = false)] public bool printWholeFixMsg { get; set; } [Parameter("symbolID", DefaultValue = 1)] public int symbolID { get; set; } public const int EURUSD = 1; public const int GBPUSD = 2; string txtMessageSend_Text = ""; string txtMessageReceived_Text = ""; bool deCryptEn = true; bool deCryptNoPrint = false; bool stopLossPlaced = false; bool lookForPrice = false; bool filledDueToSLHit = false; string initPriceForSL; string randomNum = ""; string[] filledPosiitonID = { "" }; string filPosID; string avePricePosition; string clOrdNumGlob; bool origStopOrdFilled = false; int totalPosGlob = 0; //Ctrader private int _pricePort = 5211; private int _tradePort = 5212; private string _host = "h1.p.ctrader.cn"; private string _username = "3388140"; private string _password = "qwerty12"; private string _senderCompID = "icmarkets.3388140"; private string _targetCompID = "cServer"; private string _senderSubID = "TRADE"; private int _messageSequenceNumber = 1; private int _testRequestID = 1; private TcpClient _priceClient; private SslStream _priceStreamSSL; private TcpClient _tradeClient; private SslStream _tradeStreamSSL; private MessageConstructor _messageConstructor; private double High; private double Low; double spread; string globIDForCheckOrder = ""; string globIdForSLCheckStat = ""; protected override void OnStart() { btnLogonT_Click(); Timer.TimerTick += OnTimerTick; Timer.Start(10); Positions.Closed += PositionsOnClosed; } protected override void OnStop() { btnLogoutT_Click(); } private void OnTimerTick() { btnHeartbeatT_Click(); } private void PositionsOnClosed(PositionClosedEventArgs args) { var position = args.Position; Print("Position closed with {0} profit", position.GrossProfit); filledDueToSLHit = false; stopLossPlaced = false; clOrdNumGlob = ""; origStopOrdFilled = false; initPriceForSL = ""; Print("Order Closed Successfully!!!! -------------"); filPosID = ""; globIDForCheckOrder = ""; globIdForSLCheckStat = ""; } protected override void OnTick() { High = MarketSeries.High.Last(0); Low = MarketSeries.Low.Last(0); int totalPositions = Positions.Count; var totalPendOrders = PendingOrders.Count; var barHeight = High - Low; totalPosGlob = totalPositions; if (origStopOrdFilled && totalPositions == 0) { } spread = (Symbol.Ask - Symbol.Bid) / Symbol.PipSize; } private string getRandomNumber(string coment) { Random random = new Random(); int randomNumber = random.Next(); randomNum = randomNumber.ToString(); if (ordNumDisp) Print(coment + " ClOrdeID : ", randomNum); return (randomNum); } private void printSendReceive() { Print("SendText : ", txtMessageSend_Text.Replace("\u0001", " ")); Print("ReceivedText : ", txtMessageReceived_Text.Replace("\u0001", " ")); } private void deCryptMessage(string sentMssg, string recvdMessg) { } //End of my routines public frmFIXAPISample() { //InitializeComponent(); _priceClient = new TcpClient(_host, _pricePort); _priceStreamSSL = new SslStream(_priceClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); _priceStreamSSL.AuthenticateAsClient(_host); _tradeClient = new TcpClient(_host, _tradePort); _tradeStreamSSL = new SslStream(_tradeClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); _tradeStreamSSL.AuthenticateAsClient(_host); _messageConstructor = new MessageConstructor(_host, _username, _password, _senderCompID, _senderSubID, _targetCompID); } private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) return true; Console.WriteLine("Certificate error: {0}", sslPolicyErrors); return false; } private void ClearText() { txtMessageSend_Text = ""; txtMessageReceived_Text = ""; } private string SendPriceMessage(string message, bool readResponse = true) { return SendMessage(message, _priceStreamSSL, readResponse); } private string SendTradeMessage(string message, bool readResponse = true) { return SendMessage(message, _tradeStreamSSL, readResponse); } private string SendMessage(string message, SslStream stream, bool readResponse = true) { var byteArray = Encoding.ASCII.GetBytes(message); System.Net.ServicePointManager.Expect100Continue = false; //I inserted Above line to see if it fixes crash issue stream.Write(byteArray, 0, byteArray.Length); var buffer = new byte[1024]; if (readResponse) { Thread.Sleep(100); stream.Read(buffer, 0, 1024); } _messageSequenceNumber++; var returnMessage = Encoding.ASCII.GetString(buffer); return returnMessage; } private void btnLogon_Click() { ClearText(); var message = _messageConstructor.LogonMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, 30, false); txtMessageSend_Text = message; txtMessageReceived_Text = SendPriceMessage(message); if (printWholeFixMsg) printSendReceive(); } private void btnTestRequest_Click(object sender, EventArgs e) { ClearText(); var message = _messageConstructor.TestRequestMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, _testRequestID); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendPriceMessage(message); } private void btnLogout_Click() { ClearText(); var message = _messageConstructor.LogoutMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber); txtMessageSend_Text = message; txtMessageReceived_Text = SendPriceMessage(message); _messageSequenceNumber = 1; if (printWholeFixMsg) printSendReceive(); } private void btnMarketDataRequest_Click(object sender, EventArgs e) { ClearText(); var message = _messageConstructor.MarketDataRequestMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, "EURUSD:WDqsoT", 1, 0, 0, 1, 1); txtMessageSend_Text = message; txtMessageReceived_Text = SendPriceMessage(message); } private void btnHeartbeat_Click() { ClearText(); var message = _messageConstructor.HeartbeatMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber); txtMessageSend_Text = message; txtMessageReceived_Text = SendPriceMessage(message, false); if (printWholeFixMsg) printSendReceive(); } private void btnResendRequest_Click(object sender, EventArgs e) { ClearText(); var message = _messageConstructor.ResendMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, _messageSequenceNumber - 1); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendPriceMessage(message); } private void btnReject_Click(object sender, EventArgs e) { ClearText(); var message = _messageConstructor.RejectMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, 0); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendPriceMessage(message); } private void btnSequenceReset_Click(object sender, EventArgs e) { ClearText(); var message = _messageConstructor.SequenceResetMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, 0); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendPriceMessage(message); } private void btnNewOrderSingle_Click(object sender, EventArgs e) { ClearText(); var message = _messageConstructor.NewOrderSingleMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, "1408471", 1, 1, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss"), 1000, 1, "1"); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendTradeMessage(message); } private void btnOrderStatusRequest_Click(string orderId, int symbl, int ordtyp) { ClearText(); var message = _messageConstructor.OrderStatusRequest(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, orderId, symbl, ordtyp); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendTradeMessage(message); if (printWholeFixMsg) printSendReceive(); if (deCryptEn) deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text); } private string Timestamp() { return (DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds.ToString(); } private void btnRequestForPositions_Click(string posID) { ClearText(); var message = _messageConstructor.RequestForPositions(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, posID); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendTradeMessage(message); if (printWholeFixMsg) printSendReceive(); if (deCryptEn) deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text); } private void btnLogonT_Click() { ClearText(); var message = _messageConstructor.LogonMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, 30, false); txtMessageSend_Text = message; txtMessageReceived_Text = SendTradeMessage(message); if (printWholeFixMsg) printSendReceive(); if (deCryptEn) deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text); } private void btnHeartbeatT_Click() { ClearText(); var message = _messageConstructor.HeartbeatMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber); txtMessageSend_Text = message; txtMessageReceived_Text = SendTradeMessage(message, false); if (printWholeFixMsg) printSendReceive(); } private void btnTestRequestT_Click(object sender, EventArgs e) { ClearText(); var message = _messageConstructor.TestRequestMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, _testRequestID); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendTradeMessage(message); } private void btnLogoutT_Click() { ClearText(); var message = _messageConstructor.LogoutMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber); txtMessageSend_Text = message; txtMessageReceived_Text = SendTradeMessage(message); _messageSequenceNumber = 1; if (printWholeFixMsg) printSendReceive(); if (deCryptEn) deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text); } private void btnResendRequestT_Click(object sender, EventArgs e) { ClearText(); var message = _messageConstructor.ResendMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, _messageSequenceNumber - 1); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendTradeMessage(message); } private void btnSpotMarketData_Click(object sender, EventArgs e) { ClearText(); var message = _messageConstructor.MarketDataRequestMessage(MessageConstructor.SessionQualifier.QUOTE, _messageSequenceNumber, "EURUSD:WDqsoT", 1, 1, 0, 1, 1); txtMessageSend_Text = message; txtMessageReceived_Text = SendPriceMessage(message); } private void btnStopOrder_Click(int symb, int vol, double stpPrice, string ClOrdID, int side, string posiID) { ClearText(); var message = _messageConstructor.NewOrderSingleMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, ClOrdID, symb, side, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss"), vol, 3, "3", 0, (decimal)stpPrice, "", posiID); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendTradeMessage(message); if (printWholeFixMsg) printSendReceive(); if (deCryptEn) deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text); } private void btnCancelOrder_Click(string ClOrdID, string oldOrdID) { ClearText(); var message = _messageConstructor.CancelOrderSingleMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, ClOrdID, oldOrdID, 1, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss"), 3, "3", 0); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendTradeMessage(message); if (printWholeFixMsg) printSendReceive(); if (deCryptEn) deCryptMessage(txtMessageSend_Text, txtMessageReceived_Text); } private void btnLimitOrder_Click() { ClearText(); var message = _messageConstructor.NewOrderSingleMessage(MessageConstructor.SessionQualifier.TRADE, _messageSequenceNumber, "10", 1, 1, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss"), 1000, 2, "3", (decimal)1.08); _testRequestID++; txtMessageSend_Text = message; txtMessageReceived_Text = SendTradeMessage(message); if (printWholeFixMsg) printSendReceive(); } } public class MessageConstructor { public enum SessionMessageType { Logon, Logout, Heartbeat, TestRequest, Resend, Reject, SequenceReset } public enum ApplicationMessageType { MarketDataRequest, MarketDataIncrementalRefresh, NewOrderSingle, CancelOrderSingle, OrderStatusRequest, ExecutionReport, BusinessMessageReject, RequestForPosition, PositionReport } public enum SessionQualifier { QUOTE, TRADE } private string _host; private string _username; private string _password; private string _senderCompID; private string _senderSubID; private string _targetCompID; public MessageConstructor(string host, string username, string password, string senderCompID, string senderSubID, string targetCompID) { _host = host; _username = username; _password = password; _senderCompID = senderCompID; _senderSubID = senderSubID; _targetCompID = targetCompID; } /// <summary> /// Logons the message. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="messageSequenceNumber">The message sequence number.</param> /// <param name="heartBeatSeconds">The heart beat seconds.</param> /// <param name="resetSeqNum">All sides of FIX session should have sequence numbers reset. Valid value ///is "Y" = Yes(reset)..</param> /// <returns></returns> public string LogonMessage(SessionQualifier qualifier, int messageSequenceNumber, int heartBeatSeconds, bool resetSeqNum) { var body = new StringBuilder(); //Defines a message encryption scheme.Currently, only transportlevel security //is supported.Valid value is "0"(zero) = NONE_OTHER (encryption is not used). body.Append("98=0|"); //Heartbeat interval in seconds. //Value is set in the 'config.properties' file (client side) as 'SERVER.POLLING.INTERVAL'. //30 seconds is default interval value. If HeartBtInt is set to 0, no heart beat message //is required. body.Append("108=" + heartBeatSeconds + "|"); // All sides of FIX session should have //sequence numbers reset. Valid value //is "Y" = Yes(reset). if (resetSeqNum) body.Append("141=Y|"); //The numeric User ID. User is linked to SenderCompID (#49) value (the //user’s organization). body.Append("553=" + _username + "|"); //USer Password body.Append("554=" + _password + "|"); var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.Logon), messageSequenceNumber, body.ToString()); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } public string HeartbeatMessage(SessionQualifier qualifier, int messageSequenceNumber) { var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.Heartbeat), messageSequenceNumber, string.Empty); var trailer = ConstructTrailer(header); var headerAndMessageAndTrailer = header + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } public string TestRequestMessage(SessionQualifier qualifier, int messageSequenceNumber, int testRequestID) { var body = new StringBuilder(); //Heartbeat message ID. TestReqID should be incremental. body.Append("112=" + testRequestID + "|"); var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.TestRequest), messageSequenceNumber, body.ToString()); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } public string LogoutMessage(SessionQualifier qualifier, int messageSequenceNumber) { var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.Logout), messageSequenceNumber, string.Empty); var trailer = ConstructTrailer(header); var headerAndMessageAndTrailer = header + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } /// <summary> /// Resends the message. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="messageSequenceNumber">Message sequence number of last record in range to be resent.</param> /// <param name="endSequenceNo">The end sequence no.</param> /// <returns></returns> public string ResendMessage(SessionQualifier qualifier, int messageSequenceNumber, int endSequenceNo) { var body = new StringBuilder(); //Message sequence number of last record in range to be resent. body.Append("16=" + endSequenceNo + "|"); var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.Resend), messageSequenceNumber, body.ToString()); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } public string RejectMessage(SessionQualifier qualifier, int messageSequenceNumber, int rejectSequenceNumber) { var body = new StringBuilder(); //Referenced message sequence number. body.Append("45=" + rejectSequenceNumber + "|"); var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.Reject), messageSequenceNumber, string.Empty); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } public string SequenceResetMessage(SessionQualifier qualifier, int messageSequenceNumber, int rejectSequenceNumber) { var body = new StringBuilder(); //New Sequence Number body.Append("36=" + rejectSequenceNumber + "|"); var header = ConstructHeader(qualifier, SessionMessageCode(SessionMessageType.SequenceReset), messageSequenceNumber, string.Empty); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } /// <summary> /// Constructs a message for requesting market data. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="messageSequenceNumber">The message sequence number.</param> /// <param name="marketDataRequestID">Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal.</param> /// <param name="subscriptionRequestType">1 = Snapshot plus updates (subscribe) 2 = Disable previous snapshot plus update request (unsubscribe).</param> /// <param name="marketDepth">Full book will be provided, 0 = Depth subscription, 1 = Spot subscription.</param> /// <param name="marketDataEntryType">Always set to 2 (both bid and ask will be sent).</param> /// <param name="noRelatedSymbol">Number of symbols requested.</param> /// <param name="symbol">Instrument identificators are provided by Spotware.</param> /// <returns></returns> public string MarketDataRequestMessage(SessionQualifier qualifier, int messageSequenceNumber, string marketDataRequestID, int subscriptionRequestType, int marketDepth, int marketDataEntryType, int noRelatedSymbol, long symbol = 0) { var body = new StringBuilder(); //Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal. body.Append("262=" + marketDataRequestID + "|"); //1 = Snapshot plus updates (subscribe) 2 = Disable previous snapshot plus update request (unsubscribe) body.Append("263=" + subscriptionRequestType + "|"); //Full book will be provided, 0 = Depth subscription, 1 = Spot subscription body.Append("264=" + marketDepth + "|"); //Only Incremental refresh is supported. body.Append("265=1|"); //Always set to 2 (both bid and ask will be sent). body.Append("267=2|"); //Always set to 2 (both bid and ask will be sent). body.Append("269=0|269=1|"); //Number of symbols requested. body.Append("146=" + noRelatedSymbol + "|"); //Instrument identificators are provided by Spotware. body.Append("55=" + symbol + "|"); var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.MarketDataRequest), messageSequenceNumber, body.ToString()); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } /// <summary> /// Constructs a message for requesting market data snapshot. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="messageSequenceNumber">The message sequence number.</param> /// <param name="symbol">Instrument identificators are provided by Spotware.</param> /// <param name="noMarketDataEntries">Number of entries following.</param> /// <param name="entryType">Valid values are: 0 = BID, 1 = OFFER.</param> /// <param name="entryPrice">Price of Market Data Entry.</param> /// <param name="marketDataRequestID">Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal.</param> /// <returns></returns> public string MarketDataSnapshotMessage(SessionQualifier qualifier, int messageSequenceNumber, long symbol, string noMarketDataEntries, int entryType, decimal entryPrice, string marketDataRequestID = "") { var body = new StringBuilder(); //Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal. body.Append("262=" + marketDataRequestID + "|"); //Instrument identificators are provided by Spotware. body.Append("55=" + symbol + "|"); //Number of entries following. body.Append("268=" + noMarketDataEntries + "|"); //Valid values are: 0 = BID, 1 = OFFER. body.Append("269=" + entryType + "|"); //Price of Market Data Entry. body.Append("270=" + entryPrice + "|"); var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.MarketDataRequest), messageSequenceNumber, body.ToString()); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } /// <summary> /// Markets the data incremental refresh message. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="messageSequenceNumber">The message sequence number.</param> /// <param name="marketDataRequestID">Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal.</param> /// <param name="noMarketDataEntries">Number of entries following. This repeating group contains a list of all types of Market Data Entries the requester wants to receive.</param> /// <param name="marketDataUpdateAction">Type of Market Data update action. Valid values: 0 = NEW, 2 = DELETE.</param> /// <param name="marketDataEntryType">Valid values are: 0 = BID, 1 = OFFER.</param> /// <param name="marketDataEntryID">ID of Market Data Entry.</param> /// <param name="noRelatedSymbol">The no related symbol.</param> /// <param name="marketDataEntryPrice">Conditionally required when MDUpdateAction <279> = New(0).</param> /// <param name="marketDataEntrySize">Conditionally required when MDUpdateAction <279> = New(0).</param> /// <param name="symbol">/Instrument identificators are provided by Spotware.</param> /// <returns></returns> public string MarketDataIncrementalRefreshMessage(SessionQualifier qualifier, int messageSequenceNumber, string marketDataRequestID, int noMarketDataEntries, int marketDataUpdateAction, int marketDataEntryType, string marketDataEntryID, int noRelatedSymbol, decimal marketDataEntryPrice = 0, double marketDataEntrySize = 0, long symbol = 0) { var body = new StringBuilder(); //Unique quote request id. New ID for a new subscription, same one as previously used for subscription removal. body.Append("262=" + marketDataRequestID + "|"); //Number of entries following. This repeating group contains a list of all types of Market Data Entries the requester wants to receive body.Append("268=" + noMarketDataEntries + "|"); //Type of Market Data update action. Valid values: 0 = NEW, 2 = DELETE body.Append("279=" + marketDataUpdateAction + "|"); //Valid values are: 0 = BID, 1 = OFFER body.Append("269=" + marketDataEntryType + "|"); //ID of Market Data Entry. body.Append("278=" + marketDataEntryID + "|"); //Instrument identificators are provided by Spotware body.Append("55=" + symbol + "|"); if (marketDataEntryPrice > 0) { //Conditionally required when MDUpdateAction <279> = New(0) body.Append("270=" + marketDataEntryPrice + "|"); } if (marketDataEntrySize > 0) { //Conditionally required when MDUpdateAction <279> = New(0) body.Append("271=" + marketDataEntrySize + "|"); } var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.MarketDataIncrementalRefresh), messageSequenceNumber, string.Empty); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); //return headerAndMessageAndTrailer; } /// <summary> /// News the order single message. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="messageSequenceNumber">The message sequence number.</param> /// <param name="orderID">Unique identifier for the order, allocated by the client.</param> /// <param name="symbol">The symbol.</param> /// <param name="side">1= Buy, 2 = Sell.</param> /// <param name="transactTime">Client generated request time.</param> /// <param name="orderQuantity">The fixed currency amount.</param> /// <param name="orderType">1 = Market, the Order will be processed by 'Immediate Or Cancel'scheme(see TimeInForce(59): IOC); /// 2 = Limit, the Order will be processed by 'Good Till Cancel' scheme(see TimeInForce(59): GTC).</param> /// <param name="timeInForce">1 = Good Till Cancel (GTC), it will be active only for Limit Orders (see OrdType(40)) ; /// 3 = Immediate Or Cancel (IOC), it will be active only for Market Orders(see OrdType(40)); /// 6 = Good Till Date(GTD), it will be active only if ExpireTime is defined (see ExpireTime(126)). /// GTD has a high priority, so if ExpireTime is defined, GTD will be used for the Order processing.</param> /// <param name="price">The worst client price that the client will accept. /// Required when OrdType = 2, in which case the order will notfill unless this price can be met.</param> /// /// <param name="stopPrice">Reserved for future use</param> /// <param name="expireTime"> Expire Time in YYYYMMDDHH:MM:SS format.If is assigned then the Order will be processed by 'Good Till Date' scheme /// (see TimeInForce: GTD).</param> /// <param name="positionID">Position ID, where this order should be placed. If not set, new position will be created, it’s id will be returned in ExecutionReport(8) message.</param> /// <returns></returns> public string NewOrderSingleMessage(SessionQualifier qualifier, int messageSequenceNumber, string orderID, long symbol, int side, string transactTime, int orderQuantity, int orderType, string timeInForce, decimal price = 0, decimal stopPrice = 0, string expireTime = "", string positionID = "") { var body = new StringBuilder(); //Unique identifier for the order, allocated by the client. body.Append("11=" + orderID + "|"); //Instrument identificators are provided by Spotware. body.Append("55=" + symbol + "|"); //1= Buy, 2 = Sell body.Append("54=" + side + "|"); // Client generated request time. body.Append("60=" + transactTime + "|"); //The fixed currency amount. body.Append("38=" + orderQuantity + "|"); //1 = Market, the Order will be processed by 'Immediate Or Cancel'scheme(see TimeInForce(59): IOC); //2 = Limit, the Order will be processed by 'Good Till Cancel' scheme(see TimeInForce(59): GTC). body.Append("40=" + orderType + "|"); if (price != 0) { //Reserved for future use. body.Append("44=" + price + "|"); } if (stopPrice != 0) { //The worst client price that the client will accept. //Required when OrdType = 2, in which case the order will notfill unless this price can be met. body.Append("99=" + stopPrice + "|"); } // 1 = Good Till Cancel (GTC), it will be active only for Limit Orders (see OrdType(40)) ; // 3 = Immediate Or Cancel (IOC), it will be active only for Market Orders(see OrdType(40)); // 6 = Good Till Date(GTD), it will be active only if ExpireTime is defined (see ExpireTime(126)). // GTD has a high priority, so if ExpireTime is defined, GTD will be used for the Order processing. body.Append("59=" + timeInForce + "|"); if (expireTime != string.Empty) { // Expire Time in YYYYMMDDHH:MM:SS format.If is assigned then the Order will be processed by 'Good Till Date' scheme // (see TimeInForce: GTD). body.Append("126=" + expireTime + "|"); } if (positionID != string.Empty) { // Position ID, where this order should be placed. If not set, new position will be created, it’s id will be returned in ExecutionReport(8) message. body.Append("721=" + positionID + "|"); } var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.NewOrderSingle), messageSequenceNumber, body.ToString()); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } public string CancelOrderSingleMessage(SessionQualifier qualifier, int messageSequenceNumber, string orderID, string oldOrdID, int side, string transactTime, int orderType, string timeInForce, decimal stopPrice = 0, string expireTime = "", string positionID = "") { var body = new StringBuilder(); //OldID identifier for the order, allocated by the client. body.Append("41=" + oldOrdID + "|"); //Unique identifier for the order, allocated by the client. body.Append("11=" + orderID + "|"); /* following is NOT needed for cancel orderModify Order. body.Append("55=" + symbol + "|"); body.Append("54=" + side + "|"); body.Append("60=" + transactTime + "|"); body.Append("38=" + orderQuantity + "|"); body.Append("40=" + orderType + "|"); body.Append("99=" + price + "|"); //Instrument identificators are provided by Spotware. body.Append("55=" + symbol + "|"); //1= Buy, 2 = Sell body.Append("54=" + side + "|"); // Client generated request time. body.Append("60=" + transactTime + "|"); //The fixed currency amount. body.Append("38=" + orderQuantity + "|"); //1 = Market, the Order will be processed by 'Immediate Or Cancel'scheme(see TimeInForce(59): IOC); //2 = Limit, the Order will be processed by 'Good Till Cancel' scheme(see TimeInForce(59): GTC). body.Append("40=" + orderType + "|"); if (price != 0) { //Reserved for future use. body.Append("44=" + price + "|"); } if (stopPrice != 0) { //The worst client price that the client will accept. //Required when OrdType = 2, in which case the order will notfill unless this price can be met. // body.Append("99=" + stopPrice + "|"); } // 1 = Good Till Cancel (GTC), it will be active only for Limit Orders (see OrdType(40)) ; // 3 = Immediate Or Cancel (IOC), it will be active only for Market Orders(see OrdType(40)); // 6 = Good Till Date(GTD), it will be active only if ExpireTime is defined (see ExpireTime(126)). // GTD has a high priority, so if ExpireTime is defined, GTD will be used for the Order processing. // body.Append("59=" + timeInForce + "|"); //not needed for modify if (expireTime != string.Empty) { // Expire Time in YYYYMMDDHH:MM:SS format.If is assigned then the Order will be processed by 'Good Till Date' scheme // (see TimeInForce: GTD). body.Append("126=" + expireTime + "|"); } if (positionID != string.Empty) { // Position ID, where this order should be placed. If not set, new position will be created, it’s id will be returned in ExecutionReport(8) message. body.Append("721=" + positionID + "|"); } */ var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.CancelOrderSingle), messageSequenceNumber, body.ToString()); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } /// <summary> /// Orders the status request. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="messageSequenceNumber">The message sequence number.</param> /// <param name="orderID">Unique identifier for the order, allocated by the client.</param> /// <returns></returns> public string OrderStatusRequest(SessionQualifier qualifier, int messageSequenceNumber, string orderID, int symb, int orderTyp) { var body = new StringBuilder(); // Unique identifier for the order, allocated by the client. body.Append("11=" + orderID + "|"); //Symbol - added by me //body.Append("55=" + symb + "|");//it was giving me error // 1 = Buy; 2 = Sell. There is for the FIX compatibility only, so it will be ignored. body.Append("54=" + orderTyp + "|"); var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.OrderStatusRequest), messageSequenceNumber, body.ToString()); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } /// <summary> /// Executions the report. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="messageSequenceNumber">The message sequence number.</param> /// <param name="cTraderOrderID">cTrader order id..</param> /// <param name="orderStatus"> 0 = New; 1 = Partially filled; 2 = Filled; 8 = Rejected; 4 = Cancelled(When an order is partially filled, "Cancelled" is /// returned signifying Tag 151: LeavesQty is cancelled and will not be subsequently filled); C = Expired.</param> /// <param name="transactTime">Time the transaction represented by this ExecutionReport occurred message(in UTC).</param> /// <param name="symbol">Instrument identificators are provided by Spotware..</param> /// <param name="side">1 = Buy; 2 = Sell.</param> /// <param name="averagePrice">The price at which the deal was filled.For an IOC or GTD order, this is the VWAP(Volume Weighted Average Price) of the filled order.</param> /// <param name="orderQuantity"> The fixed currency amount.</param> /// <param name="leavesQuantity">The amount of the order still to be filled.This is a value between 0 (fully filled) and OrderQty (partially filled).</param> /// <param name="cumQuantity">The total amount of the order which has been filled.</param> /// <param name="orderID"> Unique identifier for the order, allocated by the client.</param> /// <param name="orderType"> 1 = Market; 2 = Limit.</param> /// <param name="price">If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport.</param> /// <param name="stopPrice">If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport.</param> /// <param name="timeInForce">U1 = Good Till Cancel (GTC); 3 = Immediate Or Cancel (IOC); 6 = Good Till Date (GTD).</param> /// <param name="expireTime"> If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport.</param> /// <param name="text">Where possible, message to explain execution report.</param> /// <param name="orderRejectionReason">0 = OrdRejReason.BROKER_EXCHANGE_OPTION</param> /// <param name="positionID">Position ID.</param> /// <returns></returns> public string ExecutionReport(SessionQualifier qualifier, int messageSequenceNumber, string cTraderOrderID, string orderStatus, string transactTime, long symbol = 0, int side = 1, int averagePrice = 0, int orderQuantity = 0, int leavesQuantity = 0, int cumQuantity = 0, string orderID = "", string orderType = "", int price = 0, int stopPrice = 0, string timeInForce = "", string expireTime = "", string text = "", int orderRejectionReason = -1, string positionID = "") { var body = new StringBuilder(); // cTrader order id. body.Append("37=" + cTraderOrderID + "|"); // Unique identifier for the order, allocated by the client. body.Append("11=" + orderID + "|"); // Execution Type. body.Append("150=F|"); // 0 = New; 1 = Partially filled; 2 = Filled; 8 = Rejected; 4 = Cancelled(When an order is partially filled, "Cancelled" is // returned signifying Tag 151: LeavesQty is cancelled and will not be subsequently filled); C = Expired. body.Append("39=" + orderStatus + "|"); // Instrument identificators are provided by Spotware. body.Append("55=" + symbol + "|"); // 1 = Buy; 2 = Sell. body.Append("54=" + side + "|"); // Time the transaction represented by this ExecutionReport occurred message(in UTC). body.Append("60=" + transactTime + "|"); if (averagePrice > 0) { // The price at which the deal was filled.For an IOC or GTD order, this is the VWAP(Volume Weighted Average Price) of the filled order. body.Append("6=" + averagePrice + "|"); } if (orderQuantity > 0) { // The fixed currency amount. body.Append("38=" + orderQuantity + "|"); } if (leavesQuantity > 0) { // The amount of the order still to be filled.This is a value between 0 (fully filled) and OrderQty (partially filled). body.Append("151=" + leavesQuantity + "|"); } if (cumQuantity > 0) { // The total amount of the order which has been filled. body.Append("14=" + cumQuantity + "|"); } if (orderType != string.Empty) { // 1 = Market; 2 = Limit. body.Append("40=" + orderType + "|"); } if (price > 0) { // If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport. body.Append("44=" + price + "|"); } if (stopPrice > 0) { // If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport. body.Append("99=" + stopPrice + "|"); } if (timeInForce != string.Empty) { // U1 = Good Till Cancel (GTC); 3 = Immediate Or Cancel (IOC); 6 = Good Till Date (GTD). body.Append("59=" + timeInForce + "|"); } if (expireTime != string.Empty) { // If supplied in the NewOrderSingle, it is echoed back in this ExecutionReport. body.Append("126=" + expireTime + "|"); } if (text != string.Empty) { // Where possible, message to explain execution report. body.Append("58=" + text + "|"); } if (orderRejectionReason != -1) { // 0 = OrdRejReason.BROKER_EXCHANGE_OPTION body.Append("103=" + orderRejectionReason + "|"); } if (positionID != string.Empty) { // Position ID. body.Append("721=" + positionID + "|"); } var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.OrderStatusRequest), messageSequenceNumber, body.ToString()); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } /// <summary> /// Businesses the message reject. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="messageSequenceNumber">The message sequence number.</param> /// <param name="referenceSequenceNum">MsgSeqNum<34> of rejected message.</param> /// <param name="referenceMessageType">TThe MsgType<35> of the FIX message being referenced.</param> /// <param name="businessRejectRefID">The value of the business-level 'ID' field on the message being referenced.Required unless the corresponding ID field was not specified.</param> /// <param name="businessRejectReason">Where possible, message to explain reason for rejection.</param> /// <param name="text">Where possible, message to explain reason for rejection.</param> /// <returns></returns> public string BusinessMessageReject(SessionQualifier qualifier, int messageSequenceNumber, int referenceSequenceNum = 0, string referenceMessageType = "", string businessRejectRefID = "", int businessRejectReason = -1, string text = "") { var body = new StringBuilder(); if (referenceSequenceNum != 0) { // MsgSeqNum<34> of rejected message. body.Append("45=" + referenceSequenceNum + "|"); } if (referenceMessageType != string.Empty) { // The MsgType<35> of the FIX message being referenced. body.Append("372=" + referenceMessageType + "|"); } if (businessRejectRefID != string.Empty) { // The value of the business-level 'ID' field on the message being referenced.Required unless the corresponding ID field was not specified. body.Append("379=" + businessRejectRefID + "|"); } if (businessRejectReason != -1) { // Code to identify reason for a Business Message Reject<j> message. 0 = OTHER. body.Append("380=" + businessRejectReason + "|"); } if (text != string.Empty) { // Where possible, message to explain reason for rejection. body.Append("58=" + text + "|"); } var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.BusinessMessageReject), messageSequenceNumber, body.ToString()); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } /// <summary> /// Requests for positions. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="messageSequenceNumber">The message sequence number.</param> /// <param name="requestID">Unique request ID (set by client).</param> /// <param name="positionRequestID">Position ID to request. If not set, all open positions will be returned.</param> /// <returns></returns> public string RequestForPositions(SessionQualifier qualifier, int messageSequenceNumber, string requestID, string positionRequestID = "") { var body = new StringBuilder(); // Unique request ID (set by client). body.Append("710=" + requestID + "|"); if (positionRequestID != string.Empty) { // Position ID to request. If not set, all open positions will be returned. body.Append("721=" + positionRequestID + "|"); } var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.RequestForPosition), messageSequenceNumber, body.ToString()); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } /// <summary> /// Gets the position of reporting. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="messageSequenceNumber">The message sequence number.</param> /// <param name="requestID">Id of RequestForPositions.</param> /// <param name="totalNumberOfPositionReports">Total count of PositionReport’s in sequence when PosReqResult(728) is VALID_REQUEST, otherwise = 0.</param> /// <param name="positionRequestResult">0 = Valid Request; 2 = No open positions found that match criteria.</param> /// <param name="positionID">Position ID (is not set if PosReqResult(728) is not VALID_REQUEST).</param> /// <param name="symbol">The symbol for which the current Position Report is prepared. (is not set if PosReqResult(728) is not VALID_REQUEST).</param> /// <param name="noOfPositions">1 when PosReqResult(728) is VALID_REQUEST, otherwise not set.</param> /// <param name="longQuantity">Position’s open volume in case of BUY trade side, = 0 in case of SELL trade side, is not set if PosReqResult(728) is not VALID_REQUEST.</param> /// <param name="shortQuantity">Position’s open volume in case of SELL trade side, = 0 in case of BUY trade side, is not set if PosReqResult(728) is not VALID_REQUEST.</param> /// <param name="settlementPrice">Average price of the opened volume in the current PositionReport.</param> /// <returns></returns> public string PositionReport(SessionQualifier qualifier, int messageSequenceNumber, string requestID, string totalNumberOfPositionReports, string positionRequestResult, string positionID = "", string symbol = "", string noOfPositions = "", string longQuantity = "", string shortQuantity = "", string settlementPrice = "") { var body = new StringBuilder(); // Id of RequestForPositions. body.Append("710=" + requestID + "|"); if (positionID != string.Empty) { // Position ID (is not set if PosReqResult(728) is not VALID_REQUEST). body.Append("721=" + positionID + "|"); } // Total count of PositionReport’s in sequence when PosReqResult(728) is VALID_REQUEST, otherwise = 0. body.Append("727=" + totalNumberOfPositionReports + "|"); // 0 = Valid Request; 2 = No open positions found that match criteria. body.Append("728=" + positionRequestResult + "|"); if (symbol != string.Empty) { // The symbol for which the current Position Report is prepared. (is not set if PosReqResult(728) is not VALID_REQUEST). body.Append("55=" + symbol + "|"); } if (noOfPositions != string.Empty) { // 1 when PosReqResult(728) is VALID_REQUEST, otherwise not set. body.Append("702=" + noOfPositions + "|"); } if (longQuantity != string.Empty) { // Position’s open volume in case of BUY trade side, = 0 in case of SELL trade side, is not set if PosReqResult(728) is not VALID_REQUEST. body.Append("704=" + requestID + "|"); } if (shortQuantity != string.Empty) { //Position’s open volume in case of SELL trade side, = 0 in case of BUY trade side, is not set if PosReqResult(728) is not VALID_REQUEST. body.Append("705=" + shortQuantity + "|"); } if (settlementPrice != string.Empty) { // Average price of the opened volume in the current PositionReport. body.Append("730=" + settlementPrice + "|"); } var header = ConstructHeader(qualifier, ApplicationMessageCode(ApplicationMessageType.PositionReport), messageSequenceNumber, string.Empty); var headerAndBody = header + body; var trailer = ConstructTrailer(headerAndBody); var headerAndMessageAndTrailer = header + body + trailer; return headerAndMessageAndTrailer.Replace("|", "\u0001"); } /// <summary> /// Constructs the message header. /// </summary> /// <param name="qualifier">The session qualifier.</param> /// <param name="type">The message type.</param> /// <param name="messageSequenceNumber">The message sequence number.</param> /// <param name="bodyMessage">The body message.</param> /// <returns></returns> private string ConstructHeader(SessionQualifier qualifier, string type, int messageSequenceNumber, string bodyMessage) { var header = new StringBuilder(); // Protocol version. FIX.4.4 (Always unencrypted, must be first field // in message. header.Append("8=FIX.4.4|"); var message = new StringBuilder(); // Message type. Always unencrypted, must be third field in message. message.Append("35=" + type + "|"); // ID of the trading party in following format: <BrokerUID>.<Trader Login> // where BrokerUID is provided by cTrader and Trader Login is numeric // identifier of the trader account. message.Append("49=" + _senderCompID + "|"); // Message target. Valid value is "CSERVER" message.Append("56=" + _targetCompID + "|"); // Additional session qualifier. Possible values are: "QUOTE", "TRADE". message.Append("57=" + qualifier.ToString() + "|"); // Assigned value used to identify specific message originator. message.Append("50=" + _senderSubID + "|"); // Message Sequence Number message.Append("34=" + messageSequenceNumber + "|"); // Time of message transmission (always expressed in UTC(Universal Time // Coordinated, also known as 'GMT'). message.Append("52=" + DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss") + "|"); var length = message.Length + bodyMessage.Length; // Message body length. Always unencrypted, must be second field in message. header.Append("9=" + length + "|"); header.Append(message); return header.ToString(); } /// <summary> /// Constructs the message trailer. /// </summary> /// <param name="message">The message trailer.</param> /// <returns></returns> private string ConstructTrailer(string message) { //Three byte, simple checksum. Always last field in message; i.e. serves, //with the trailing<SOH>, //as the end - of - message delimiter. Always defined as three characters //(and always unencrypted). var trailer = "10=" + CalculateChecksum(message.Replace("|", "\u0001").ToString()).ToString().PadLeft(3, '0') + "|"; return trailer; } /// <summary> /// Calculates the checksum. /// </summary> /// <param name="dataToCalculate">The data to calculate.</param> /// <returns></returns> private int CalculateChecksum(string dataToCalculate) { byte[] byteToCalculate = Encoding.ASCII.GetBytes(dataToCalculate); int checksum = 0; foreach (byte chData in byteToCalculate) { checksum += chData; } return checksum % 256; } /// <summary> /// Returns the session the message code. /// </summary> /// <param name="type">The session message type.</param> /// <returns></returns> private string SessionMessageCode(SessionMessageType type) { switch (type) { case SessionMessageType.Heartbeat: return "0"; //break; case SessionMessageType.Logon: return "A"; //break; case SessionMessageType.Logout: return "5"; // break; case SessionMessageType.Reject: return "3"; //break; case SessionMessageType.Resend: return "2"; //break; case SessionMessageType.SequenceReset: return "4"; //break; case SessionMessageType.TestRequest: return "1"; default: //break; return "0"; } } /// <summary> /// Returns the application message code. /// </summary> /// <param name="type">The application message type.</param> /// <returns></returns> private string ApplicationMessageCode(ApplicationMessageType type) { switch (type) { case ApplicationMessageType.MarketDataRequest: return "V"; //break; case ApplicationMessageType.MarketDataIncrementalRefresh: return "X"; //break; case ApplicationMessageType.NewOrderSingle: return "D"; //break; case ApplicationMessageType.CancelOrderSingle: return "F"; // break; case ApplicationMessageType.OrderStatusRequest: return "H"; // break; case ApplicationMessageType.ExecutionReport: return "8"; // break; case ApplicationMessageType.BusinessMessageReject: return "j"; // break; case ApplicationMessageType.RequestForPosition: return "AN"; // break; case ApplicationMessageType.PositionReport: return "AP"; default: // break; return "0"; } } } }
@netread2004
netread2004
05 Nov 2018, 09:31
Looks like this is logON issue. I checked response for LogOn FIX message and the response is empty message.
As far as my original issue is concerend, I think it was arising due to sending logOn message to the server already Logged on and no Logout sent.
I will monitor this further and update on this.
Thanks
@netread2004
PanagiotisCharalampous
29 Oct 2018, 11:37
Hi netread2004,
Can you share the cBot code so that we can reproduce the issue?
Best Regards,
Panagiotis
@PanagiotisCharalampous