static public void Main(string[] args)
        {
            if (args.Length < 10 || args.Length > 11)
            {
                show_usage(Process.GetCurrentProcess().ProcessName);
                return;
            }

            string url = args[0];
            int    broker_id;

            try
            {
                broker_id = Int32.Parse(args[1]);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                show_usage(Process.GetCurrentProcess().ProcessName);
                return;
            }

            string symbol = args[2];

            char side;

            switch (args[3].ToUpper())
            {
            case "BUY":
                side = OrderSide.BUY;
                break;

            case "SELL":
                side = OrderSide.SELL;
                break;

            case "BOTH":
                side = default(char);
                break;

            default:
                show_usage(Process.GetCurrentProcess().ProcessName);
                return;
            }

            // ** temporary workaround to support market pegged sell order strategy without plugins **
            TradingStrategy.PriceType priceType;
            switch (args[4].ToUpper())
            {
            case "DEFAULT":
            case "FIXED":
                priceType = TradingStrategy.PriceType.FIXED;
                break;

            case "PEGGED":
            case "FLOAT":
                if (side == OrderSide.SELL)
                {
                    priceType = TradingStrategy.PriceType.PEGGED;
                }
                else
                {
                    throw new ArgumentException("PEGGED is currently supported only for SELL");
                }
                break;

            default:
                show_usage(Process.GetCurrentProcess().ProcessName);
                return;
            }

            ulong maxTradeSize;

            try
            {
                maxTradeSize = (ulong)(Double.Parse(args[5]) * 1e8);
                if (maxTradeSize < 10000)
                {
                    throw new ArgumentException("Invalid Trade Size, must be at least 10,000 satoshis");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                show_usage(Process.GetCurrentProcess().ProcessName);
                return;
            }

            // ***
            ulong buyTargetPrice;

            try
            {
                buyTargetPrice = (ulong)(Double.Parse(args[6]) * 1e8);
                if (buyTargetPrice < 0)
                {
                    throw new ArgumentException("Invalid Buy Target Price");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                show_usage(Process.GetCurrentProcess().ProcessName);
                return;
            }

            ulong sellTargetPrice;

            try
            {
                sellTargetPrice = (ulong)(Double.Parse(args[7]) * 1e8);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                show_usage(Process.GetCurrentProcess().ProcessName);
                return;
            }

            try
            {
                if ((side == OrderSide.BUY || side == default(char)) && buyTargetPrice == 0)
                {
                    throw new ArgumentException("Invalid BUY Target Price");
                }

                if ((side == OrderSide.SELL || side == default(char)) && sellTargetPrice == 0)
                {
                    throw new ArgumentException("Invalid SELL Target Price");
                }

                if (side == default(char) && buyTargetPrice >= sellTargetPrice)
                {
                    throw new ArgumentException("Invalid SELL and BUY Price RANGE");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                show_usage(Process.GetCurrentProcess().ProcessName);
                return;
            }

            string user          = args[8];
            string password      = args[9];
            string second_factor = args.Length == 11 ? args[10] : null;

            try
            {
                // instantiate the tradeclient object to handle the trading stuff
                TradingStrategy strategy = new TradingStrategy(maxTradeSize, buyTargetPrice, sellTargetPrice, side, priceType);

                // instantiate the protocol engine object to handle the blinktrade messaging stuff
                WebSocketClientProtocolEngine protocolEngine = new WebSocketClientProtocolEngine();

                SimpleTradeClient tradeclient = new SimpleTradeClient(broker_id, symbol, strategy, protocolEngine);

                // tradeclient must subscribe to receive the callback events from the protocol engine
                protocolEngine.SystemEvent    += tradeclient.OnBrokerNotification;
                protocolEngine.LogStatusEvent += LogStatus;
                strategy.LogStatusEvent       += LogStatus;


                // workaround (on windows working only in DEBUG) to trap the console application exit
                // and dump the last state of the Market Data Order Book(s), MiniOMS and Security Status
                                #if  (__MonoCS__ || DEBUG)
                System.AppDomain appDom = System.AppDomain.CurrentDomain;
                appDom.ProcessExit += new EventHandler(tradeclient.OnApplicationExit);
                                        #if __MonoCS__
                Thread signal_thread = new Thread(UnixSignalTrap);
                signal_thread.Start();
                                        #else
                var consoleHandler = new HandlerRoutine(OnConsoleCtrlCheck);                                 // hold handler to not get GC'd
                SetConsoleCtrlHandler(consoleHandler, true);
                                        #endif
                                #endif

                // objects to encapsulate and provide user account credentials
                UserAccountCredentials userAccount = new UserAccountCredentials(broker_id, user, password, second_factor);

                while (!_userRequestExit)
                {
                    try
                    {
                        LogStatus(LogStatusType.WARN, "Please Wait...");

                        // gather and provide the user device data (local ip, external ip etc)
                        UserDevice userDevice = new UserDevice();

                        // start the connection task to handle the Websocket connectivity and initiate the whole process
                                                #if __MonoCS__
                        Task /*<int>*/ task = WebSocketSharpClientConnection.Start(url, userAccount, userDevice, protocolEngine);
                                                #else
                        Task task = WebSocketClientConnection.Start(url, userAccount, userDevice, protocolEngine);
                                                #endif

                        /*
                         * Task<int>[] tasks = new Task<int>[2];
                         * tasks[0] = WebSocketSharpClientConnection.Start (url, userAccount, userDevice, protocolEngine);
                         * //tasks[1] = ...
                         * int index = Task.WaitAny(tasks);
                         * tasks[index].Result;
                         */

                        task.Wait();                         // aguardar até a Task finalizar
                        if (!_userRequestExit)
                        {
                            tradeclient.ResetData();                             // must reset tradeclient to refresh whole data after new connection
                            LogStatus(LogStatusType.WARN, "Trying to reconnect in 5 seconds...");
                            Task.Delay(TimeSpan.FromSeconds(5)).Wait();
                        }
                    }
                    catch (System.Net.WebException ex)
                    {
                        LogStatus(LogStatusType.ERROR, ex.Message + '\n' + ex.StackTrace);
                        Task.Delay(TimeSpan.FromSeconds(5)).Wait();
                        continue;
                    }
                }
            }
            catch (Exception ex)
            {
                LogStatus(LogStatusType.ERROR, ex.Message + '\n' + ex.StackTrace);
                return;
            }

            /*
             #if DEBUG
             * Console.WriteLine("Press any key to exit...");
             * Console.ReadKey();
             #endif
             */
        }
        public static async Task /*<int>*/ Start(
            string serverUri,
            UserAccountCredentials account,
            UserDevice device,
            WebSocketClientProtocolEngine protocolEngine)
        {
            WebSocketSharpClientConnection connectionInstance = new WebSocketSharpClientConnection(account, device, protocolEngine);

            try
            {
                WebSocket ws = new WebSocket(serverUri);
                connectionInstance._webSocket = ws;

                ws.OnOpen += (sender, e) =>
                {
                    connectionInstance._protocolEngine.OnOpen(connectionInstance);
                };

                ws.OnMessage += (sender, e) =>
                {
                    if (!e.IsPing)
                    {
                        // increment the number of received messages to help the keep-alive mechanism
                        Interlocked.Increment(ref connectionInstance._receiveMessageCounter);
                        // invoke the callbacks
                        connectionInstance._protocolEngine.OnLogEvent(LogStatusType.MSG_IN, e.Data);
                        connectionInstance._protocolEngine.OnMessage(e.Data, connectionInstance);
                    }
                };


                ws.OnError += (sender, e) =>
                {
                    connectionInstance._protocolEngine.OnError(e.Message, connectionInstance);
                };

                ws.OnClose += (sender, e) =>
                {
                    connectionInstance._protocolEngine.OnClose(connectionInstance);
                    connectionInstance._protocolEngine.OnLogEvent(LogStatusType.ERROR,
                                                                  String.Format("WebSocket Close ({0} {1})", e.Code, e.Reason)
                                                                  );
                };

                connectionInstance._webSocket.Connect();
                await Task.WhenAll(TestRequest(connectionInstance));
            }
            catch (Exception ex)
            {
                string msg = (ex.InnerException != null ? ex.Message + ". " + ex.InnerException.Message : ex.Message) + '\n' + ex.StackTrace;
                connectionInstance._protocolEngine.OnError(msg, connectionInstance);
            }
            finally
            {
                if (connectionInstance._webSocket != null)
                {
                    ((IDisposable)connectionInstance._webSocket).Dispose();
                }
            }
            //return 0;
        }