コード例 #1
0
            private decimal InternalCalculateFee(USeInstrument instrument, USeOffsetType offsetType, int qty, decimal price)
            {
                USeFee fee = InternalGetFee(instrument);

                if (fee == null)
                {
                    return(0m);
                }

                int volumeMultiple = InternalGetVolumeMultiple(instrument);

                switch (offsetType)
                {
                case USeOffsetType.Open: return(fee.OpenRatioByMoney * qty * price * volumeMultiple + fee.OpenRatioByVolume * qty);

                case USeOffsetType.CloseHistory:
                case USeOffsetType.Close: return(fee.CloseRatioByMoney * qty * price * volumeMultiple + fee.CloseRatioByVolume * qty);

                case USeOffsetType.CloseToday: return(fee.CloseTodayRatioByMoney * qty * price * volumeMultiple + fee.CloseTodayRatioByVolume * qty);

                default:
                    Debug.Assert(false);
                    return(0m);
                }
            }
コード例 #2
0
ファイル: USeOffsetType.cs プロジェクト: handayu/TFS-WebKit
        /// <summary>
        /// 开平仓方向描述。
        /// </summary>
        /// <param name="offsetType">开平仓方向。</param>
        /// <returns>描述字符串。</returns>
        public static string ToDescription(this USeOffsetType offsetType)
        {
            switch (offsetType)
            {
            case USeOffsetType.Open: return("开仓");

            case USeOffsetType.CloseHistory: return("平昨仓");

            case USeOffsetType.CloseToday: return("平今仓");

            case USeOffsetType.Close: return("平仓");

            default: return("未知");
            }
        }
コード例 #3
0
        private USeOffsetType GetChoiceOffsetType()
        {
            USeOffsetType order_offset_type = USeOffsetType.Open;

            if (this.radioButton_Open.Checked)
            {
                order_offset_type = USeOffsetType.Open;
            }
            else if (this.radioButton_CloseToday.Checked)
            {
                order_offset_type = USeOffsetType.CloseToday;
            }
            else if (this.radioButton_CloseYD.Checked)
            {
                order_offset_type = USeOffsetType.CloseHistory;
            }
            else
            {
                Debug.Assert(false);
            }

            return(order_offset_type);
        }
コード例 #4
0
        /// <summary>
        /// 创建空的委托回报。
        /// </summary>
        /// <param name="orderNum">委托单号。</param>
        /// <param name="instrument">合约。</param>
        /// <param name="orderQty">委托量。</param>
        /// <param name="orderPrice">委托价格。</param>
        /// <param name="offsetType">开平方向。</param>
        /// <param name="orderSide">买卖方向。</param>
        /// <returns></returns>
        private USeOrderBook CreateOrignalUSeOrderBook(USeOrderNum orderNum, USeInstrument instrument, int orderQty, decimal orderPrice, USeOffsetType offsetType, USeOrderSide orderSide)
        {
            USeOrderBook orderBook = new USeOrderBook();

            orderBook.OrderNum    = orderNum;
            orderBook.Account     = string.Empty;
            orderBook.Instrument  = instrument;
            orderBook.OrderQty    = orderQty;
            orderBook.OrderPrice  = orderPrice;
            orderBook.TradeQty    = 0;
            orderBook.TradeAmount = 0m;
            orderBook.TradePrice  = 0m;
            orderBook.TradeFee    = 0m;
            orderBook.OrderStatus = USeOrderStatus.Unknown;
            orderBook.CancelQty   = 0;
            orderBook.OrderSide   = orderSide;
            orderBook.OffsetType  = offsetType;
            orderBook.Memo        = string.Empty;
            orderBook.OrderTime   = DateTime.Now;

            return(orderBook);
        }
コード例 #5
0
        /// <summary>
        /// 创建委托命令集合。
        /// </summary>
        /// <param name="taskId">任务ID。</param>
        /// <param name="instrument">合约。</param>
        /// <param name="orderSide">买卖方向。</param>
        /// <param name="offsetType">开平方向。</param>
        /// <param name="orderQty">委托量。</param>
        /// <param name="orderPrice">委托价格。</param>
        /// <param name="orderReason">委托原因。</param>
        /// <returns></returns>
        private List <OrderCommand> CreateOrderCommands(int taskId, USeInstrument instrument, USeOrderSide orderSide, USeOffsetType offsetType, int orderQty, decimal orderPrice, string orderReason)
        {
            List <OrderCommand> commandList = new List <OrderCommand>();

            //构造指令
            if (offsetType == USeOffsetType.Open)
            {
                OrderCommand command = new OrderCommand()
                {
                    TaskId      = taskId,
                    Instrument  = instrument,
                    OrderSide   = orderSide,
                    OffsetType  = USeOffsetType.Open,
                    OrderQty    = orderQty,
                    OrderPrice  = orderPrice,
                    OrderReason = orderReason
                };

                commandList.Add(command);
            }
            else
            {
                Debug.Assert(offsetType == USeOffsetType.Close);

                if (instrument.Market == USeMarket.SHFE)
                {
                    #region  交所平仓
                    USeDirection direction = orderSide == USeOrderSide.Buy ? USeDirection.Short : USeDirection.Long;
                    //上海交易所平仓需区分平今还是平昨
                    USePosition position = m_orderDriver.QueryPositions(instrument, direction);
                    //[yangming]
                    string tmpTestText = string.Format(@"[hanyuClose]Ins:{0} OrderSide:{1} OffsetFlag:{2} OrderQty:{3},NewAvaliablePosition:{4} ,NewFrozonPosition:{5},NewPosition{6}," +
                                                       "OldAvaliablePosition:{7},OldFrozonPosition:{8},OldPosition:{9}", instrument.InstrumentCode, orderSide, offsetType, orderQty, position.NewAvaliablePosition,
                                                       position.NewFrozonPosition, position.NewPosition, position.OldAvaliablePosition, position.OldFrozonPosition, position.OldPosition);

                    USeManager.Instance.EventLogger.WriteAudit(tmpTestText);
                    //
                    if (position == null || position.AvaliablePosition < orderQty)
                    {
                        //查询不到仓位,或者仓位不足,直接构造平今指令
                        OrderCommand command = new OrderCommand()
                        {
                            TaskId      = taskId,
                            Instrument  = instrument,
                            OrderSide   = orderSide,
                            OffsetType  = USeOffsetType.CloseToday,
                            OrderQty    = orderQty,
                            OrderPrice  = orderPrice,
                            OrderReason = orderReason
                        };

                        commandList.Add(command);
                    }
                    else
                    {
                        //平今
                        int remainQty = orderQty;
                        if (position.NewAvaliablePosition > 0)
                        {
                            int          closeQty = Math.Min(position.NewAvaliablePosition, remainQty);
                            OrderCommand command  = new OrderCommand()
                            {
                                TaskId      = taskId,
                                Instrument  = instrument,
                                OrderSide   = orderSide,
                                OffsetType  = USeOffsetType.CloseToday,
                                OrderQty    = closeQty,
                                OrderPrice  = orderPrice,
                                OrderReason = orderReason
                            };
                            remainQty -= closeQty;
                            commandList.Add(command);
                        }

                        //平昨
                        if (remainQty > 0)
                        {
                            Debug.Assert(remainQty <= position.OldAvaliablePosition);
                            int          closeQty = remainQty;
                            OrderCommand command  = new OrderCommand()
                            {
                                TaskId      = taskId,
                                Instrument  = instrument,
                                OrderSide   = orderSide,
                                OffsetType  = USeOffsetType.CloseHistory,
                                OrderQty    = closeQty,
                                OrderPrice  = orderPrice,
                                OrderReason = orderReason
                            };
                            remainQty -= closeQty;
                            commandList.Add(command);
                        }
                        Debug.Assert(remainQty == 0);
                    }
                    #endregion
                }
                else
                {
                    OrderCommand command = new OrderCommand()
                    {
                        TaskId      = taskId,
                        Instrument  = instrument,
                        OrderSide   = orderSide,
                        OffsetType  = USeOffsetType.Close,
                        OrderQty    = orderQty,
                        OrderPrice  = orderPrice,
                        OrderReason = orderReason
                    };
                }
            }

            return(commandList);
        }
コード例 #6
0
        /// <summary>
        /// 套利单任务 -- 优先合约下单。
        /// </summary>
        /// <param name="taskGroup">开仓/平仓 任务组。</param>
        /// <param name="differentialUnit">最大仓差。</param>
        /// <returns></returns>
        private bool ProcessFirstSubTask(ArbitrageTaskGroup taskGroup, int differentialUnit)
        {
            #region 校验
            PriceSpreadCheckResult priceSpeadResult = CheckPriceSpread(taskGroup.OpenCloseType, m_arbitrageOrder.Argument);
            if (priceSpeadResult.OrderReason == TaskOrderReason.None)
            {
                WriteTraderDebugInfo("优先合约检查,不满足价差条件");
                return(false);
            }

            int firstUnExeTaskIndex = taskGroup.GetFirstTaskUnExecutIndex();
            if (firstUnExeTaskIndex < 0)
            {
                // 优先合约全部完成下单
                return(false);
            }

            bool secondTaskIsPlaceOrder = taskGroup.CheckSecondTaskIsPlaceOrder(firstUnExeTaskIndex);
            if (secondTaskIsPlaceOrder == false)
            {
                WriteTraderDebugInfo("反手合约还未下单,不许下单");
                return(false);
            }

            //反手仓位未成交任务数
            int secondUnTradeTaskCount = taskGroup.GetUnTradeSecondTaskCount(firstUnExeTaskIndex);
            if (secondUnTradeTaskCount >= differentialUnit)
            {
                WriteTraderDebugInfo("优先合约反手合约任务仓差大于等于允许最大仓差,不许下单");
                return(false);
            }

            ArbitrageTask task = taskGroup.TaskList[firstUnExeTaskIndex];
            Debug.Assert(task != null && task.TaskState == ArbitrageTaskState.None);
            ArbitrageSubTask firstSubTask = task.FirstSubTask;

            if (firstSubTask.TryOrderCount >= m_tryOrderCondition.MaxTryOrderCount)
            {
                m_backgroundRunFlag = false;

                string text = string.Format("流程暂停,{2}下单任务[{0}]超出最大尝试下单次数{1}次",
                                            task.TaskId, m_tryOrderCondition.MaxTryOrderCount, firstSubTask.Instrument.InstrumentCode);
                AutoTraderNotice notice = CreateTraderNotice(AutoTraderNoticeType.Order, text);
                SafeFireAutoTraderNotice(notice);

                AlarmNotice alarm = new AlarmNotice(AlarmType.AutoTraderWarning, text);
                SafeFireAutoTraderAlarm(alarm);

                WriteTraderNoticeLog(notice);

                return(false);
            }

            if (firstSubTask.CanPlaceNextOrder(m_tryOrderCondition.NextOrderInterval) == false)
            {
                WriteTraderDebugInfo("优先合约检查,距离上次下单时间过近,暂时不下单");
                return(false);
            }
            #endregion

            #region  单

            Debug.Assert(priceSpeadResult.OrderReason == TaskOrderReason.Open ||
                         priceSpeadResult.OrderReason == TaskOrderReason.Close ||
                         priceSpeadResult.OrderReason == TaskOrderReason.StopLoss);
            task.OrderReason = priceSpeadResult.OrderReason;
            task.PriceSpread = priceSpeadResult.PriceSpreadThreshold;

            //获取优先合约下单价格
            decimal orderPrice = GetFirstInstrumentOrderPrice(firstSubTask.Instrument, firstSubTask.OrderPriceType, firstSubTask.OrderSide);
            Debug.Assert(orderPrice > 0);
            int orderQty = firstSubTask.UnOrderQty;
            Debug.Assert(orderQty > 0);

            USeInstrument instrument = firstSubTask.Instrument;
            USeOffsetType offsetType = firstSubTask.OffsetType;
            USeOrderSide  orderSide  = firstSubTask.OrderSide;

            List <OrderCommand> commandList = null;
            lock (ms_orderSyncObj)
            {
                commandList = CreateOrderCommands(task.TaskId, instrument, orderSide, offsetType, orderQty, orderPrice, "优先合约");
                Debug.Assert(commandList != null && commandList.Count > 0);

                foreach (OrderCommand command in commandList)
                {
                    bool orderResult = PlaceOrderForOrderCommand(command);
                    if (orderResult)
                    {
                        firstSubTask.AddPositiveOrderBook(command.CreateOrignalOrderBook());
                        task.UpdateTaskState();
                        //task.TaskState = ArbitrageTaskState.FirstPlaceOrder;
                    }
                }
            }
            firstSubTask.AddTryOrderCount();  // 下单累加1次
            #endregion

            #region 通知
            foreach (OrderCommand command in commandList)
            {
                AutoTraderNotice notice = CreateTraderNotice(AutoTraderNoticeType.Order, command.ToDescription());
                SafeFireAutoTraderNotice(notice);
                WriteTraderNoticeLog(notice);
            }
            #endregion

            return(true);
        }
コード例 #7
0
        /// <summary>
        /// 套利单任务--反手合约下单(优先合约已成交)
        /// </summary>
        /// <param name="taskGroup">开仓/平仓 任务组。</param>
        private bool ProcessSecondSubTask(ArbitrageTaskGroup taskGroup)
        {
            for (int i = 0; i < taskGroup.TaskList.Count; i++)
            {
                #region 校验
                ArbitrageTask task = taskGroup.TaskList[i];

                if (task.TaskState != ArbitrageTaskState.FirstTradeFinish)
                {
                    //优先合约未成交,无需做反手合约检查
                    continue;
                }

                ArbitrageSubTask secondSubTask = task.SecondSubTask;

                if (secondSubTask.TryOrderCount >= m_tryOrderCondition.MaxTryOrderCount)
                {
                    m_backgroundRunFlag = false;

                    string text = string.Format("流程暂停,{2}下单任务[{0}]超出最大尝试下单次数{1}次",
                                                task.TaskId, m_tryOrderCondition.MaxTryOrderCount, secondSubTask.Instrument.InstrumentCode);
                    AutoTraderNotice notice = CreateTraderNotice(AutoTraderNoticeType.Order, text);
                    SafeFireAutoTraderNotice(notice);

                    AlarmNotice alarm = new AlarmNotice(AlarmType.AutoTraderWarning, text);
                    SafeFireAutoTraderAlarm(alarm);

                    WriteTraderNoticeLog(notice);

                    return(false);
                }

                if (secondSubTask.CanPlaceNextOrder(m_tryOrderCondition.NextOrderInterval) == false)
                {
                    WriteTraderDebugInfo("反手合约检查,距离上次下单时间过近,暂时不下单");
                    continue;
                }
                #endregion

                #region  单
                //获取反手合约下单价格
                decimal orderPrice = GetSecondTaskOrderPrice(taskGroup.OperationSide, taskGroup.PreferentialSide, task.FirstSubTaskAvgTradePrice, task.PriceSpread);

                orderPrice = TrimOrderPrice(secondSubTask.Instrument, orderPrice, secondSubTask.OrderSide);
                int orderQty = secondSubTask.UnOrderQty;
                Debug.Assert(orderQty > 0);

                USeInstrument instrument = secondSubTask.Instrument;
                USeOffsetType offsetType = secondSubTask.OffsetType;
                USeOrderSide  orderSide  = secondSubTask.OrderSide;

                List <OrderCommand> commandList = null;
                lock (ms_orderSyncObj)
                {
                    commandList = CreateOrderCommands(task.TaskId, instrument, orderSide, offsetType, orderQty, orderPrice, "反手合约");
                    Debug.Assert(commandList != null && commandList.Count > 0);

                    foreach (OrderCommand command in commandList)
                    {
                        bool orderResult = PlaceOrderForOrderCommand(command);
                        if (orderResult)
                        {
                            secondSubTask.AddPositiveOrderBook(command.CreateOrignalOrderBook());
                            task.UpdateTaskState();
                            //task.TaskState = ArbitrageTaskState.FirstPlaceOrder;
                        }
                    }
                }
                secondSubTask.AddTryOrderCount();  // 下单累加1次
                #endregion

                #region 通知
                foreach (OrderCommand command in commandList)
                {
                    AutoTraderNotice notice = CreateTraderNotice(AutoTraderNoticeType.Order, command.ToDescription());
                    SafeFireAutoTraderNotice(notice);
                    WriteTraderNoticeLog(notice);
                }
                #endregion
            }

            return(false);
        }
コード例 #8
0
ファイル: USeOrderDriver.cs プロジェクト: handayu/TFS-WebKit
 /// <summary>
 /// 委托下单。
 /// </summary>
 /// <param name="product">委托产品。</param>
 /// <param name="qty">委托量。</param>
 /// <param name="price">委托价格。</param>
 /// <param name="offsetType">开平仓方向。</param>
 /// <param name="orderSide">买卖方向。</param>
 /// <param name="error">[out]委托失败原因。</param>
 /// <returns>委托单号。</returns>
 /// <remarks>返回为null代表失败,否则为委托单号。</remarks>
 public abstract USeOrderNum PlaceOrder(USeInstrument product, int qty, decimal price, USeOffsetType offsetType, USeOrderSide orderSide, out string error);
コード例 #9
0
        /// <summary>
        /// 委托下单。
        /// </summary>
        /// <param name="instrument">委托产品。</param>
        /// <param name="qty">委托量。</param>
        /// <param name="price">委托价格。</param>
        /// <param name="offsetType">开平仓方向。</param>
        /// <param name="orderSide">买卖方向。</param>
        /// <param name="error">[out]委托失败原因。</param>
        /// <returns>委托单号。</returns>
        /// <remarks>返回为null代表失败,否则为委托单号。</remarks>
        public override USeOrderNum PlaceOrder(USeInstrument instrument, int qty, decimal price, USeOffsetType offsetType, USeOrderSide orderSide, out string error)
        {
            error = "";
            System.Diagnostics.Debug.Assert(instrument != null);

            int orderNumValue = m_orderNumCreateor.Next();

            USeOrderBook orderBook = new USeOrderBook();

            orderBook.OrderNum    = new TestOrderNum(orderNumValue);
            orderBook.Account     = m_investorID;
            orderBook.Instrument  = instrument;
            orderBook.OrderQty    = qty;
            orderBook.OrderPrice  = price;
            orderBook.TradeQty    = 0;
            orderBook.TradeAmount = 0;
            orderBook.TradePrice  = 0;
            orderBook.TradeFee    = 0;
            orderBook.OrderStatus = USeOrderStatus.Unknown;
            orderBook.CancelQty   = 0;
            orderBook.OrderSide   = orderSide;
            orderBook.OffsetType  = offsetType;
            orderBook.Memo        = "";
            orderBook.OrderTime   = DateTime.Now;

            string error_orderInfo = string.Empty;

            VerfiyPlaceOrderToReturn(orderBook, out error_orderInfo);

            if (error_orderInfo == "开仓")
            {
                m_dataBuffer.OrderBookList.Add(orderBook);

                m_pushOrderBookList.Enqueue(orderBook);
                error = "Place Order Ok";

                return(orderBook.OrderNum);
            }
            else if (error_orderInfo == "CloseSuccessed")
            {
                //开仓
                orderBook.Memo = "平仓委托成功";
                m_dataBuffer.OrderBookList.Add(orderBook);

                m_pushOrderBookList.Enqueue(orderBook);
                error = "Place Order Ok";
                return(orderBook.OrderNum);
            }
            else
            {
                //平仓委托失败
                orderBook.Memo        = error_orderInfo;
                orderBook.OrderStatus = USeOrderStatus.BlankOrder;

                m_pushOrderBookList.Enqueue(orderBook);
                error = "Place Order Failed";
                return(orderBook.OrderNum);
            }
        }
コード例 #10
0
        /// <summary>
        /// 平仓追单。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WorkerDoWorkForCloseChaseOrder(object sender, DoWorkEventArgs e)
        {
            {
                AutoTraderNotice notice = CreateTraderNotice("平仓追单对齐操作");
                SafeFireAutoTraderNotice(notice);
                WriteTraderNoticeLog(notice);
            }

            //开仓追单
            //1.撤销掉当前所有未成交委托单
            //2.检查不对齐欠缺仓位,对欠缺仓位进行开仓追单
            //3.开仓以市价委托,尽量保证成交
            Debug.Assert(m_arbitrageOrder.State == ArbitrageOrderState.Closeing);

            if (m_arbitrageOrder.HasUnFinishOrderBook)
            {
                string           text   = "平仓追单有未完成委托单正在撤单";
                AutoTraderNotice notice = CreateTraderNotice(AutoTraderNoticeType.Order, text);
                SafeFireAutoTraderNotice(notice);
                WriteTraderNoticeLog(notice);

                List <USeOrderBook> unFinishOrderBook = m_arbitrageOrder.GetAllUnfinishOrderBooks();
                foreach (USeOrderBook orderBook in unFinishOrderBook)
                {
                    string errorMessage = string.Empty;
                    bool   cancelResult = m_orderDriver.CancelOrder(orderBook.OrderNum, orderBook.Instrument, out errorMessage);
                    if (cancelResult == false)
                    {
                        text   = string.Format("平仓追单{0} 撤单失败", orderBook.OrderNum);
                        notice = CreateTraderNotice(AutoTraderNoticeType.Order, text);
                        SafeFireAutoTraderNotice(notice);
                        WriteTraderNoticeLog(notice);

                        return;   // 退出流程,触发预警
                    }
                }

                text   = "平仓追单操作完成,等待撤单成功";
                notice = CreateTraderNotice(AutoTraderNoticeType.Order, text);
                SafeFireAutoTraderNotice(notice);
                WriteTraderNoticeLog(notice);

                while (true)
                {
                    //等待撤单完成
                    m_operatorEvent.WaitOne(EVENT_WAIT_Time);

                    if (m_backgroundRunFlag == false)
                    {
                        text   = string.Format("平仓追单流程退出");
                        notice = CreateTraderNotice(AutoTraderNoticeType.Infomation, text);
                        SafeFireAutoTraderNotice(notice);
                        WriteTraderNoticeLog(notice);
                        return;
                    }

                    if (m_arbitrageOrder.HasUnFinishOrderBook == false)
                    {
                        text   = string.Format("平仓追单已完成撤单");
                        notice = CreateTraderNotice(AutoTraderNoticeType.Order, text);
                        SafeFireAutoTraderNotice(notice);
                        WriteTraderNoticeLog(notice);
                        break;
                    }
                }
            }

            List <OrderCommand> commandList = new List <OrderCommand>();

            // 对欠缺仓位进行补单
            foreach (ArbitrageTask task in m_arbitrageOrder.CloseTaskGroup.TaskList)
            {
                if (task.FirstSubTask.TradeQty == task.SecondSubTask.TradeQty)
                {
                    continue;
                }

                Debug.Assert(task.FirstSubTask.TradeQty > task.SecondSubTask.TradeQty);

                //追单
                USeInstrument instrument = task.SecondSubTask.Instrument;
                USeOrderSide  orderSide  = task.SecondSubTask.OrderSide;
                int           orderQty   = task.FirstSubTask.TradeQty - task.SecondSubTask.TradeQty;
                Debug.Assert(orderQty > 0);
                decimal orderPrice = GetFirstInstrumentOrderPrice(instrument, ArbitrageOrderPriceType.OpponentPrice, orderSide);
                Debug.Assert(orderPrice > 0);
                USeOffsetType offsetType = USeOffsetType.Close;

                List <OrderCommand> subCommandList = CreateOrderCommands(task.TaskId, instrument, orderSide, offsetType, orderQty, orderPrice, "平仓追单");
                foreach (OrderCommand command in subCommandList)
                {
                    bool orderResult = PlaceOrderForOrderCommand(command);
                    if (orderResult)
                    {
                        task.SecondSubTask.AddPositiveOrderBook(command.CreateOrignalOrderBook());
                        task.UpdateTaskState();
                        //task.TaskState = ArbitrageTaskState.FirstPlaceOrder;
                    }
                }

                commandList.AddRange(subCommandList);
            }

            #region 通知
            foreach (OrderCommand command in commandList)
            {
                AutoTraderNotice notice = CreateTraderNotice(AutoTraderNoticeType.Order, command.ToDescription());
                SafeFireAutoTraderNotice(notice);
                WriteTraderNoticeLog(notice);
            }
            #endregion

            {
                string           text   = "平仓追单已完成追单,等待成交";
                AutoTraderNotice notice = CreateTraderNotice(AutoTraderNoticeType.Order, text);
                SafeFireAutoTraderNotice(notice);
                WriteTraderNoticeLog(notice);
            }
        }
コード例 #11
0
        /// <summary>
        /// 委托下单。
        /// </summary>
        /// <param name="instrument">委托产品。</param>
        /// <param name="qty">委托量。</param>
        /// <param name="price">委托价格。</param>
        /// <param name="offsetType">开平仓方向。</param>
        /// <param name="orderSide">买卖方向。</param>
        /// <param name="error">[out]委托失败原因。</param>
        /// <returns>委托单号。</returns>
        /// <remarks>返回为null代表失败,否则为委托单号。</remarks>
        public override USeOrderNum PlaceOrder(USeInstrument instrument, int qty, decimal price, USeOffsetType offsetType, USeOrderSide orderSide, out string error)
        {
            if (m_ctpUser == null || m_ctpUser.IsLogin == false)
            {
                error = "OrderServer unable";
                return(null);
            }

            string orderRef  = m_orderRefIDCreator.Next().ToString(); // 生成报单引用
            int    requestID = m_requetSeqIDCreator.Next();

            error = string.Empty;

            try
            {
                OffsetFlagType ctpOffsetFlag;
                switch (offsetType)
                {
                case USeOffsetType.Open: ctpOffsetFlag = OffsetFlagType.Open; break;

                case USeOffsetType.Close: ctpOffsetFlag = OffsetFlagType.Close; break;

                case USeOffsetType.CloseToday: ctpOffsetFlag = OffsetFlagType.CloseToday; break;

                case USeOffsetType.CloseHistory: ctpOffsetFlag = OffsetFlagType.CloseYesterday; break;

                default:
                    throw new ArgumentException(string.Format("Invalid offsetType {0}.", offsetType), "offsetType");
                }

                DirectionType ctpDirection;
                switch (orderSide)
                {
                case USeOrderSide.Buy: ctpDirection = DirectionType.Buy; break;

                case USeOrderSide.Sell: ctpDirection = DirectionType.Sell; break;

                default:
                    throw new ArgumentException(string.Format("Invalid orderside {0}.", orderSide), "orderSide");
                }

                InputOrderField requestField = new InputOrderField();
                requestField.BrokerID            = m_brokerID;
                requestField.InvestorID          = m_investorID;
                requestField.InstrumentID        = instrument.InstrumentCode;
                requestField.OrderRef            = orderRef;
                requestField.UserID              = m_investorID;
                requestField.OrderPriceType      = OrderPriceType.LimitPrice;
                requestField.Direction           = ctpDirection;
                requestField.CombOffsetFlag1     = ctpOffsetFlag;
                requestField.CombHedgeFlag1      = HedgeFlagType.Speculation;
                requestField.LimitPrice          = Convert.ToDouble(price);
                requestField.VolumeTotalOriginal = qty;
                requestField.TimeCondition       = TimeConditionType.GFD;
                requestField.VolumeCondition     = VolumeConditionType.AV;
                requestField.MinVolume           = 1;
                requestField.ContingentCondition = ContingentConditionType.Immediately;
                requestField.ForceCloseReason    = ForceCloseReasonType.NotForceClose;
                requestField.IsAutoSuspend       = IntBoolType.No;
                requestField.BusinessUnit        = null;
                requestField.RequestID           = requestID;
                requestField.UserForceClose      = IntBoolType.No;

                //构造一个委托回报,防止报单不合规等问题遭CTP拒绝,但未有委托回报推送
                OrderField orderField = new OrderField();
                orderField.BrokerID            = m_brokerID;
                orderField.FrontID             = m_frontID;
                orderField.SessionID           = m_sessionID;
                orderField.OrderRef            = orderRef;
                orderField.OrderSysID          = string.Empty;
                orderField.InvestorID          = m_investorID;
                orderField.InstrumentID        = instrument.InstrumentCode;
                orderField.ExchangeID          = CtpProtocol.USeMarketToFtdcExchange(instrument.Market);
                orderField.VolumeTotalOriginal = qty;
                orderField.LimitPrice          = Convert.ToDouble(price);
                orderField.VolumeTraded        = 0;
                orderField.OrderStatus         = OrderStatusType.Unknown;
                orderField.Direction           = orderSide == USeOrderSide.Buy ? DirectionType.Buy : DirectionType.Sell;

                switch (offsetType)
                {
                case USeOffsetType.Open: orderField.CombOffsetFlag1 = OffsetFlagType.Open; break;

                case USeOffsetType.Close: orderField.CombOffsetFlag1 = OffsetFlagType.Close; break;

                case USeOffsetType.CloseHistory: orderField.CombOffsetFlag1 = OffsetFlagType.CloseYesterday; break;

                case USeOffsetType.CloseToday: orderField.CombOffsetFlag1 = OffsetFlagType.CloseToday; break;
                }
                orderField.InsertDate = DateTime.Now.ToString("yyyyMMdd");
                orderField.InsertTime = DateTime.Now.ToString("HH:mm:ss");

                m_dataBuffer.UpdateOrderField(orderField);


                m_ctpUser.ReqOrderInsert(ref requestField, requestID);

                USeOrderNum orderNum = new CtpOrderNum(m_frontID, m_sessionID, orderRef);

                m_logger.WriteInformation(string.Format("{0}.PlaceOrder() ok,[RequestID:{1}][Instrument:{2}][FulcOffsetType{3}][Qty:{4}][Price:{5}].",
                                                        ToString(), requestID, instrument.InstrumentCode, offsetType, qty, price));

                return(orderNum);
            }
            catch (Exception ex)
            {
                m_logger.WriteError(string.Format("{0} placeorder[Instrument:{1}][FulcOffsetType:{2}][Qty:{3}][Price:{4}] failed,Error:{5}.",
                                                  ToString(), instrument.InstrumentCode, offsetType, qty, price, ex.Message));
                error = ex.Message;
                return(null);
            }
        }