0

I have a sever running already (acceptor) and I am trying to build something to send orders to this server by using quickfix and c# .net 4.7

I installed the quick fix library and tried to copy the sample tradeClient from the official website, but I am not seeing any actual connection made.

PS:

  1. I am using WinForms, so I commented out the Console.Readline() and put a fixed value for testing purposes.
  2. when it trigger run() it will run the QueryNew function, it never hit the OnLogon() function
  3. from the console, i see the following log message:
<event> Created session>
<event> Connecting to xxx.xxx.xxx.xxx on port xxxx 
<event> Connection successed
<outgoing> 8=Fix4.2|9=71|35=A|34=2|49=SENDER|52=20230207 15:06:56.858|56=TARGET|90=0|108=30|10=134|
<event> Initiated logon request
The thread 0X84a8 has exited with code 0(0x0).

i have a few questions:

  1. Is it correct that whenever run() started, it will automatically tried to logon? or do I have to call a logon function?
  2. Is there any additional setup required from the server side if I am trying to connect it with a new application? (Currently, there is already a program connecting to it, so the network is not a concern)
  3. How can I logon to the session and get the heartbeat and send orders after

Here is my code

Initiator.cs

using QuickFix;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FIXLogAnalyser.FixSender
{
    public partial class Initiator : Form
    {
        public Initiator()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Console.WriteLine("=============");
            Console.WriteLine("This is only an example program, meant to run against the Executor or SimpleAcceptor example programs.");
            Console.WriteLine();
            Console.WriteLine("                                                    ! ! !");
            Console.WriteLine("              DO NOT USE THIS ON A COMMERCIAL FIX INTERFACE!  It won't work and it's a bad idea!");
            Console.WriteLine("                                                    ! ! !");
            Console.WriteLine();
            Console.WriteLine("=============");

            //if (args.Length != 1)
            //{
            //    System.Console.WriteLine("usage: TradeClient.exe CONFIG_FILENAME");
            //    System.Environment.Exit(2);
            //}

            string file = "tradeclient.cfg";

            try
            {
                QuickFix.SessionSettings settings = new QuickFix.SessionSettings(file);
                TradeClientApp application = new TradeClientApp();
                QuickFix.IMessageStoreFactory storeFactory = new QuickFix.FileStoreFactory(settings);
                QuickFix.ILogFactory logFactory = new QuickFix.ScreenLogFactory(settings);
                QuickFix.Transport.SocketInitiator initiator = new QuickFix.Transport.SocketInitiator(application, storeFactory, settings, logFactory);

                // this is a developer-test kludge.  do not emulate.
                application.MyInitiator = initiator;

                initiator.Start();
                Console.WriteLine(initiator.IsLoggedOn());
                application.Run();
                initiator.Stop();
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }
            Environment.Exit(1);
        }
    }
}

tradeClientApp.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using QuickFix;
using QuickFix.Fields;

namespace FIXLogAnalyser.FixSender
{
    class TradeClientApp : QuickFix.MessageCracker, QuickFix.IApplication
    {
        Session _session = null;

        // This variable is a kludge for developer test purposes.  Don't do this on a production application.
        public IInitiator MyInitiator = null;

        #region IApplication interface overrides

        public void OnCreate(SessionID sessionID)
        {
            _session = Session.LookupSession(sessionID);
        }

        public void OnLogon(SessionID sessionID)
        {
            try
            {
                Console.WriteLine("Logon - " + sessionID.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine("fail: " + ex.Message);
            }
        }
        public void OnLogout(SessionID sessionID) { Console.WriteLine("Logout - " + sessionID.ToString()); }

        public void FromAdmin(Message message, SessionID sessionID)
        {
            Console.WriteLine("from admin: " + message);
        }
        public void ToAdmin(Message message, SessionID sessionID)
        {
            Console.WriteLine(sessionID.SenderCompID + " - " + sessionID.TargetCompID);
            if (message.GetType() == typeof(QuickFix.FIX42.Logon))
            {
                //   message.SetField(new Username("YOUR_USERNAME"));
                //   message.SetField(new Password("YOUR_PASSWORD"));
            }

            //           message.SetField(new QuickFix.Fields.Account("YOUR_ACCOUNT_NUMBER"));
        }

        public void FromApp(Message message, SessionID sessionID)
        {
            Console.WriteLine("IN:  " + message.ToString());
            try
            {
                Crack(message, sessionID);
            }
            catch (Exception ex)
            {
                Console.WriteLine("==Cracker exception==");
                Console.WriteLine(ex.ToString());
                Console.WriteLine(ex.StackTrace);
            }
        }

        public void ToApp(Message message, SessionID sessionID)
        {
            try
            {
                bool possDupFlag = false;
                if (message.Header.IsSetField(QuickFix.Fields.Tags.PossDupFlag))
                {
                    possDupFlag = QuickFix.Fields.Converters.BoolConverter.Convert(
                        message.Header.GetString(QuickFix.Fields.Tags.PossDupFlag)); /// FIXME
                }
                if (possDupFlag)
                    throw new DoNotSend();
            }
            catch (FieldNotFoundException)
            { }

            Console.WriteLine();
            Console.WriteLine("OUT: " + message.ToString());
        }
        #endregion


        #region MessageCracker handlers
        public void OnMessage(QuickFix.FIX42.ExecutionReport m, SessionID s)
        {
            Console.WriteLine("Received execution report");
        }

        public void OnMessage(QuickFix.FIX42.OrderCancelReject m, SessionID s)
        {
            Console.WriteLine("Received order cancel reject");
        }
        #endregion


        public void Run()
        {
            try
            {
                
                Console.WriteLine(MyInitiator.IsLoggedOn());
                char action = QueryAction();
                if (action == '1')
                    QueryEnterOrder();
                else if (action == '2')
                    QueryCancelOrder();
                else if (action == '3')
                    QueryReplaceOrder();
                else if (action == '4')
                    QueryMarketDataRequest();
                else if (action == 'g')
                {
                    if (this.MyInitiator.IsStopped)
                    {
                        Console.WriteLine("Restarting initiator...");
                        this.MyInitiator.Start();
                    }
                    else
                        Console.WriteLine("Already started.");
                }
                else if (action == 'x')
                {
                    if (this.MyInitiator.IsStopped)
                        Console.WriteLine("Already stopped.");
                    else
                    {
                        Console.WriteLine("Stopping initiator...");
                        this.MyInitiator.Stop();
                    }
                }
                else if (action == 'q' || action == 'Q')
                    Console.WriteLine("break");// break;
                Console.WriteLine(MyInitiator.IsLoggedOn());

            }
            catch (System.Exception e)
            {
                Console.WriteLine("Message Not Sent: " + e.Message);
                Console.WriteLine("StackTrace: " + e.StackTrace);
            }

            Console.WriteLine("Program shutdown.");
        }

        private void SendMessage(Message m)
        {
            if (_session != null)
                _session.Send(m);
            else
            {
                // This probably won't ever happen.
                Console.WriteLine("Can't send message: session not created.");
            }
        }

        private char QueryAction()
        {
            // Commands 'g' and 'x' are intentionally hidden.
            Console.Write("\n"
                + "1) Enter Order\n"
                + "2) Cancel Order\n"
                + "3) Replace Order\n"
                + "4) Market data test\n"
                + "Q) Quit\n"
                + "Action: "
            );

            HashSet<string> validActions = new HashSet<string>("1,2,3,4,q,Q,g,x".Split(','));
            string cmd = "g";
            // string cmd = Console.ReadLine().Trim();
            if (cmd.Length != 1 || validActions.Contains(cmd) == false)
                throw new System.Exception("Invalid action");

            return cmd.ToCharArray()[0];
        }

        private void QueryEnterOrder()
        {
            Console.WriteLine("\nNewOrderSingle");

            QuickFix.FIX42.NewOrderSingle m = QueryNewOrderSingle44();

            if (m != null && QueryConfirm("Send order"))
            {
                m.Header.GetString(Tags.BeginString);

                SendMessage(m);
            }
        }

        private void QueryCancelOrder()
        {
            Console.WriteLine("\nOrderCancelRequest");

            QuickFix.FIX42.OrderCancelRequest m = QueryOrderCancelRequest44();

            if (m != null && QueryConfirm("Cancel order"))
                SendMessage(m);
        }

        private void QueryReplaceOrder()
        {
            Console.WriteLine("\nCancelReplaceRequest");

            QuickFix.FIX42.OrderCancelReplaceRequest m = QueryCancelReplaceRequest42();

            if (m != null && QueryConfirm("Send replace"))
                SendMessage(m);
        }

        private void QueryMarketDataRequest()
        {
            Console.WriteLine("\nMarketDataRequest");

            QuickFix.FIX42.MarketDataRequest m = QueryMarketDataRequest44();

            if (m != null && QueryConfirm("Send market data request"))
                SendMessage(m);
        }

        private bool QueryConfirm(string query)
        {
            Console.WriteLine();
            Console.WriteLine(query + "?: ");
            //       string line = Console.ReadLine().Trim();
            string line = "y";
            return (line[0].Equals('y') || line[0].Equals('Y'));
        }

        #region Message creation functions
        private QuickFix.FIX42.NewOrderSingle QueryNewOrderSingle44()
        {
            QuickFix.Fields.OrdType ordType = null;

            QuickFix.FIX42.NewOrderSingle newOrderSingle = new QuickFix.FIX42.NewOrderSingle(
                QueryClOrdID(),
                QueryHandlInst(),
                QuerySymbol(),
                QuerySide(),
                new TransactTime(DateTime.Now),
                ordType = QueryOrdType()); ;

            newOrderSingle.Set(new HandlInst('1'));
            newOrderSingle.Set(QueryOrderQty());
            newOrderSingle.Set(QueryTimeInForce());
            if (ordType.getValue() == OrdType.LIMIT || ordType.getValue() == OrdType.STOP_LIMIT)
                newOrderSingle.Set(QueryPrice());
            if (ordType.getValue() == OrdType.STOP || ordType.getValue() == OrdType.STOP_LIMIT)
                newOrderSingle.Set(QueryStopPx());

            return newOrderSingle;
        }

        private QuickFix.FIX42.OrderCancelRequest QueryOrderCancelRequest44()
        {
            QuickFix.FIX42.OrderCancelRequest orderCancelRequest = new QuickFix.FIX42.OrderCancelRequest(
                QueryOrigClOrdID(),
                QueryClOrdID(),
                QuerySymbol(),
                QuerySide(),
                new TransactTime(DateTime.Now));

            orderCancelRequest.Set(QueryOrderQty());
            return orderCancelRequest;
        }

        private QuickFix.FIX42.OrderCancelReplaceRequest QueryCancelReplaceRequest42()
        {
            QuickFix.FIX42.OrderCancelReplaceRequest ocrr = new QuickFix.FIX42.OrderCancelReplaceRequest(
                QueryOrigClOrdID(),
                QueryClOrdID(),
                QueryHandlInst(),
                QuerySymbol(),
                QuerySide(),
                new TransactTime(DateTime.Now),
                QueryOrdType());

            ocrr.Set(new HandlInst('1'));
            if (QueryConfirm("New price"))
                ocrr.Set(QueryPrice());
            if (QueryConfirm("New quantity"))
                ocrr.Set(QueryOrderQty());

            return ocrr;
        }

        private QuickFix.FIX42.MarketDataRequest QueryMarketDataRequest44()
        {
            MDReqID mdReqID = new MDReqID("MARKETDATAID");
            SubscriptionRequestType subType = new SubscriptionRequestType(SubscriptionRequestType.SNAPSHOT);
            MarketDepth marketDepth = new MarketDepth(0);

            QuickFix.FIX42.MarketDataRequest.NoMDEntryTypesGroup marketDataEntryGroup = new QuickFix.FIX42.MarketDataRequest.NoMDEntryTypesGroup();
            marketDataEntryGroup.Set(new MDEntryType(MDEntryType.BID));

            QuickFix.FIX42.MarketDataRequest.NoRelatedSymGroup symbolGroup = new QuickFix.FIX42.MarketDataRequest.NoRelatedSymGroup();
            symbolGroup.Set(new Symbol("LNUX"));

            QuickFix.FIX42.MarketDataRequest message = new QuickFix.FIX42.MarketDataRequest(mdReqID, subType, marketDepth);
            message.AddGroup(marketDataEntryGroup);
            message.AddGroup(symbolGroup);

            return message;
        }
        #endregion

        #region field query private methods
        private ClOrdID QueryClOrdID()
        {
            Console.WriteLine();
            Console.Write("ClOrdID? ");
            return new ClOrdID("orderID123");
            // return new ClOrdID(Console.ReadLine().Trim());
        }

        private OrigClOrdID QueryOrigClOrdID()
        {
            Console.WriteLine();
            Console.Write("OrigClOrdID? ");
            //return new OrigClOrdID(Console.ReadLine().Trim())
            return new OrigClOrdID("OrigClordID123");

        }
        private HandlInst QueryHandlInst()
        {
            Console.WriteLine();
            Console.Write("QueryHandlInst? ");
            //    return new HandlInst(Console.ReadLine()[0]);
            return new HandlInst('1');

        }
        private Symbol QuerySymbol()
        {
            Console.WriteLine();
            Console.Write("Symbol? ");
            //     return new Symbol(Console.ReadLine().Trim());
            return new Symbol("700 HK");

        }

        private Side QuerySide()
        {
            Console.WriteLine();
            Console.WriteLine("1) Buy");
            Console.WriteLine("2) Sell");
            Console.WriteLine("3) Sell Short");
            Console.WriteLine("4) Sell Short Exempt");
            Console.WriteLine("5) Cross");
            Console.WriteLine("6) Cross Short");
            Console.WriteLine("7) Cross Short Exempt");
            Console.Write("Side? ");
            //           string s = Console.ReadLine().Trim();
            string s = "1";

            char c = ' ';
            switch (s)
            {
                case "1": c = Side.BUY; break;
                case "2": c = Side.SELL; break;
                case "3": c = Side.SELL_SHORT; break;
                case "4": c = Side.SELL_SHORT_EXEMPT; break;
                case "5": c = Side.CROSS; break;
                case "6": c = Side.CROSS_SHORT; break;
                case "7": c = 'A'; break;
                default: throw new Exception("unsupported input");
            }
            return new Side(c);
        }

        private OrdType QueryOrdType()
        {
            Console.WriteLine();
            Console.WriteLine("1) Market");
            Console.WriteLine("2) Limit");
            Console.WriteLine("3) Stop");
            Console.WriteLine("4) Stop Limit");
            Console.Write("OrdType? ");
            //string s = Console.ReadLine().Trim();
            string s = "1";

            char c = ' ';
            switch (s)
            {
                case "1": c = OrdType.MARKET; break;
                case "2": c = OrdType.LIMIT; break;
                case "3": c = OrdType.STOP; break;
                case "4": c = OrdType.STOP_LIMIT; break;
                default: throw new Exception("unsupported input");
            }
            return new OrdType(c);
        }

        private OrderQty QueryOrderQty()
        {
            Console.WriteLine();
            Console.Write("OrderQty? ");
            //  return new OrderQty(Convert.ToDecimal(Console.ReadLine().Trim()));
            return new OrderQty(Convert.ToDecimal("400.00"));
        }

        private TimeInForce QueryTimeInForce()
        {
            Console.WriteLine();
            Console.WriteLine("1) Day");
            Console.WriteLine("2) IOC");
            Console.WriteLine("3) OPG");
            Console.WriteLine("4) GTC");
            Console.WriteLine("5) GTX");
            Console.Write("TimeInForce? ");
            //       string s = Console.ReadLine().Trim();
            string s = "1";

            char c = ' ';
            switch (s)
            {
                case "1": c = TimeInForce.DAY; break;
                case "2": c = TimeInForce.IMMEDIATE_OR_CANCEL; break;
                case "3": c = TimeInForce.AT_THE_OPENING; break;
                case "4": c = TimeInForce.GOOD_TILL_CANCEL; break;
                case "5": c = TimeInForce.GOOD_TILL_CROSSING; break;
                default: throw new Exception("unsupported input");
            }
            return new TimeInForce(c);
        }

        private Price QueryPrice()
        {
            Console.WriteLine();
            Console.Write("Price? ");
            return new Price(Convert.ToDecimal(Console.ReadLine().Trim()));
        }

        private StopPx QueryStopPx()
        {
            Console.WriteLine();
            Console.Write("StopPx? ");
            return new StopPx(Convert.ToDecimal(Console.ReadLine().Trim()));
        }

        #endregion
    }
}

tradeClient.cfg

[DEFAULT]
ConnectionType=initiator
ReconnectInterval=2
FileStorePath=logpath
FileLogPath=log
StartTime=01:00:00
EndTime=23:00:00
UseDataDictionary=Y
DataDictionary=FIX42.xml
SocketConnectHost=xxx.xxx.xxx.xxx
SocketConnectPort=xxxx
LogoutTimeout=5
ResetOnLogon=N
ResetOnDisconnect=Y

[SESSION]
# inherit ConnectionType, ReconnectInterval and SenderCompID from default
BeginString=FIX.4.2
SenderCompID=SENDER
TargetCompID=TARGET
HeartBtInt=30 



cutecutebj
  • 179
  • 1
  • 15

0 Answers0