public static PriceSpreadCheckResult CreateNoOrderResult()
        {
            PriceSpreadCheckResult result = new PriceSpreadCheckResult();

            result.OrderReason          = TaskOrderReason.None;
            result.PriceSpreadThreshold = 0;
            return(result);
        }
        /// <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);
        }
        /// <summary>
        /// 检查是否满足任务组监控价差条件。
        /// </summary>
        /// <param name="taskGroup">任务组。</param>
        /// <returns></returns>
        private PriceSpreadCheckResult CheckPriceSpread(OpenCloseType openCloseType, ArbitrageArgument argument)
        {
            USeMarketData nearMarketData = m_quoteDriver.Query(argument.NearInstrument);
            USeMarketData farMarketData  = m_quoteDriver.Query(argument.FarInstrument);

            decimal nearPrice = 0m;
            decimal farPrice  = 0m;

            if (openCloseType == OpenCloseType.Open)
            {
                nearPrice = GetMarketPrice(nearMarketData, argument.OpenArg.NearOrderPriceType);
                farPrice  = GetMarketPrice(farMarketData, argument.OpenArg.FarOrderPriceType);
            }
            else if (openCloseType == OpenCloseType.Close)
            {
                nearPrice = GetMarketPrice(nearMarketData, argument.CloseArg.NearOrderPriceType);
                farPrice  = GetMarketPrice(farMarketData, argument.CloseArg.FarOrderPriceType);
            }
            else
            {
                Debug.Assert(false);
                return(PriceSpreadCheckResult.CreateNoOrderResult());
            }

            if (nearPrice <= 0 || farPrice <= 0)
            {
                return(PriceSpreadCheckResult.CreateNoOrderResult());
            }

            decimal priceSpread = nearPrice - farPrice;

            if (openCloseType == OpenCloseType.Open)
            {
                Debug.Assert(argument.OpenArg != null && argument.OpenArg.OpenCondition != null);
                if (IsInPriceSpread(argument.OpenArg.OpenCondition, priceSpread))
                {
                    PriceSpreadCheckResult result = new PriceSpreadCheckResult();
                    result.OrderReason          = TaskOrderReason.Open;
                    result.PriceSpreadThreshold = argument.OpenArg.OpenCondition.PriceSpreadThreshold;
                    return(result);
                }
            }
            else if (openCloseType == OpenCloseType.Close)
            {
                Debug.Assert(argument.CloseArg != null && argument.CloseArg.CloseCondition != null);
                if (argument.CloseArg != null && argument.CloseArg.CloseCondition != null)
                {
                    if (IsInPriceSpread(argument.CloseArg.CloseCondition, priceSpread))
                    {
                        PriceSpreadCheckResult result = new PriceSpreadCheckResult();
                        result.OrderReason          = TaskOrderReason.Close;
                        result.PriceSpreadThreshold = argument.CloseArg.CloseCondition.PriceSpreadThreshold;
                        return(result);
                    }
                }

                if (argument.StopLossArg != null && argument.StopLossArg.StopLossCondition != null)
                {
                    if (IsInPriceSpread(argument.StopLossArg.StopLossCondition, priceSpread))
                    {
                        PriceSpreadCheckResult result = new PriceSpreadCheckResult();
                        result.OrderReason          = TaskOrderReason.StopLoss;
                        result.PriceSpreadThreshold = argument.StopLossArg.StopLossCondition.PriceSpreadThreshold;
                        return(result);
                    }
                }
            }

            return(PriceSpreadCheckResult.CreateNoOrderResult());
        }