private async Task <RESTClient4Trade> GetClientAsync()
        {
            string uid = cli4trd?.GetCurrentUId();

            if (uid == null || uid.Length < 1)
            {
                if (comboBoxTrdServer.Text.Length < 1 || textBoxUname.Text.Length < 1 || textBoxApiKey.Text.Length < 1 || textBoxApiSecret.Text.Length < 1)
                {
                    LOG("[WARN] 请先正确填写参数。。。\r\n");
                    return(null);
                }
                try
                {
                    var client = new RESTClient4Trade(comboBoxTrdServer.Text, textBoxUname.Text, Convert.ToInt32(textBoxVPID.Text), textBoxApiKey.Text, textBoxApiSecret.Text);
                    var info   = await client.GetUserInfoAsync();

                    LOG($"[DEBUG] connect trade-server, get user info: {info}\r\n");
                    cli4trd = client;
                }
                catch (Exception ex)
                {
                    LOG("[ERROR] connect trade server Exception: " + ex.Message + "\r\n");
                    return(null);
                }
            }
            return(cli4trd);
        }
        private async void buttonOrderNew_ClickAsync(object sender, EventArgs e)
        {
            /******
             * 用户下单注意事项:
             * 1. 用户通常在本地维护 【所有委托】表; 主键使用 COrdId;
             * 2. 所有委托通常会被分为三种:当前委托,条件委托,历史委托;
             * 2. 尽管 Server 端是使用 OrdId 来作为 Ord 的主键的,但是由于websockets的异步通讯机制,用户在下单(新建委托)时只能
             *    自己维护 COrdId 而要等待服务器返回对应的 OrdId;因此建议本地使用GUID来自己维护自己Ord的唯一性;故,本地保存的
             *    所有委托的主键使用 COrdId 比较方便;
             * 3. 特别注意的是,在WebSocket模式下, OrderNew 的返回结果并不能保证一定比 onOrder 消息到来的快,因此,在下单前,应该
             *    先本地保存 COrdId 入表以便 onOrder 能正确识别;
             * 4. 委托的有效性,首先看 ErrorCode 是否为 0,然后再看 Status;
             * 5. 对于条件委托,一开始OType是条件类型,触发后会自动变成 Limit 或 Market 类型;如在历史单中想判断是否条件单,可借
             *    助 StopPrz 来进一步判断。
             * 6. 性能考虑,建议单独建立一个历史委托的表单独存放已经不活动的委托,因为这些委托数据是不会再变化了。
             */
            if (cli4trd == null)
            {
                return;
            }

            var sym = textBox_ORD_sym.Text.Trim();

            if (sym.Length < 1)
            {
                return;
            }

            var acctype = comboBox_ORD_AccType.SelectedIndex + 1;

            Gmex.API.Models.Ord ord = new Gmex.API.Models.Ord();
            try
            {
                ord.COrdId = Guid.NewGuid().ToString();
                ord.AId    = cli4trd.GetCurrentUId() + acctype.ToString("D2");
                ord.Sym    = sym;
                ord.Prz    = Convert.ToDecimal(textBox_ORD_Prz.Text.Trim());
                ord.Qty    = Convert.ToDecimal(textBox_ORD_Qty.Text.Trim());
                ord.Dir    = comboBox_ORD_DIR.SelectedIndex == 1 ? Gmex.API.Models.Dir.SELL : Gmex.API.Models.Dir.BUY;
                ord.Tif    = (Gmex.API.Models.TimeInForce)comboBox_ORD_TIF.SelectedIndex;
                ord.OType  = (Gmex.API.Models.OfferType)comboBox_ORD_OffetType.SelectedIndex;

                if (checkBoxPOSTONLY.Checked)
                {
                    ord.OrdFlag__Set(Gmex.API.Models.OrdFlag.POSTONLY);
                }
                if (checkBoxREDUCEONLY.Checked)
                {
                    ord.OrdFlag__Set(Gmex.API.Models.OrdFlag.REDUCEONLY);
                }

                var ret = await cli4trd.OrderNewAsync(ord);

                LOG($"[OrderNew] <<\r\n");
                LOG($"{Helper.MyJsonMarshal(ret)}\r\n");
                LOG($"========\r\n");
            }
            catch (Exception ex)
            {
                LOG("[ERROR] Exception: " + ex.Message);
                return;
            }
        }