Esempio n. 1
0
        private static ArbitrageTask CreateTask()
        {
            ArbitrageTask task = new ArbitrageTask();

            task.TaskId = 100;
            //task.TaskState = ArbitrageOrderTaskState.Finish;
            //task.Instrument = new USeInstrument("CF1701", "CF1701", USeMarket.CFFE);
            //task.OrderPriceType = ArbitrageOrderPriceType.LastPrice;
            //task.OrderSide = USeOrderSide.Buy;
            //task.OffsetType = USeOffsetType.Close;
            //task.PlanOrderQty = 3;

            //List<USeOrderBook> use_order_booklist = new List<USeOrderBook>();
            //use_order_booklist.Add(CreateUseOrderBook());
            //task.OrderBooks = use_order_booklist;

            task.UnFinishOrderBooks.Add(CreateUseOrderBook());



            List <USeOrderBook> orderBookList = new List <USeOrderBook>();

            orderBookList.Add(CreateUseOrderBook());

            return(task);
        }
Esempio n. 2
0
        public ArbitrageTask Clone()
        {
            ArbitrageTask task = new ArbitrageTask();

            task.TaskId        = this.TaskId;
            task.TaskState     = this.TaskState;
            task.OrderReason   = this.OrderReason;
            task.PriceSpread   = this.PriceSpread;
            task.FirstSubTask  = m_firstSubTask == null ? null : m_firstSubTask.Clone();
            task.SecondSubTask = m_secondSubTask == null ? null : m_secondSubTask.Clone();

            return(task);
        }
Esempio n. 3
0
        /// <summary>
        /// 检查前置任务是否完成反手合约委托。
        /// </summary>
        /// <param name="taskIndex">任务索引。</param>
        /// <returns></returns>
        public bool CheckSecondTaskIsPlaceOrder(int taskIndex)
        {
            if (taskIndex < 0)
            {
                return(true);
            }

            for (int i = 0; i < m_taskList.Count && i < taskIndex; i++)
            {
                ArbitrageTask task = m_taskList[i];
                if (task.TaskState < ArbitrageTaskState.SecondPlaceOrderFinish)
                {
                    return(false);
                }
            }

            return(true);
        }
Esempio n. 4
0
        /// <summary>
        /// 获取指定任务前的前置任务 反手合约未完全成交的任务数。
        /// <param name="taskIndex">任务索引。</param>
        /// <returns></returns>
        public int GetUnTradeSecondTaskCount(int taskIndex)
        {
            if (taskIndex < 0)
            {
                return(0);
            }

            Debug.Assert(taskIndex < m_taskList.Count);

            int count = 0;

            for (int i = 0; i < m_taskList.Count && i < taskIndex; i++)
            {
                ArbitrageTask task = m_taskList[i];
                if (task.TaskState < ArbitrageTaskState.SecondTradeFinish)
                {
                    count++;
                }
            }

            return(count);
        }
        /// <summary>
        /// 创建平仓任务组。
        /// </summary>
        /// <param name="openTaskGroup">开仓任务组。</param>
        /// <param name="closeArg">平仓参数。</param>
        /// <returns></returns>
        private ArbitrageTaskGroup CreateCloseTaskGroup(ArbitrageTaskGroup openTaskGroup, ArbitrageArgument argument)
        {
            ArbitrageCloseArgument closeArg = argument.CloseArg;

            Debug.Assert(openTaskGroup.BuyInstrument == closeArg.SellInstrument);
            Debug.Assert(openTaskGroup.SellInstrument == closeArg.BuyInstrument);

            int buyPosition  = openTaskGroup.SellSubTaskTradeQty; // 平仓买入量 = 开仓卖出量
            int sellPosition = openTaskGroup.BuySubTaskTradeQty;  // 平仓卖出量 = 开仓买入量

            USeInstrument           firstInstrument      = null;
            USeInstrument           secondInstrument     = null;
            USeOrderSide            firstOrderSide       = USeOrderSide.Buy;
            USeOrderSide            secondOrderSide      = USeOrderSide.Sell;
            ArbitrageOrderPriceType firstOrderPriceType  = ArbitrageOrderPriceType.Unknown;
            ArbitrageOrderPriceType secondOrderPriceType = ArbitrageOrderPriceType.Unknown;
            int firstPosition  = 0;
            int secondPosition = 0;

            if (closeArg.PreferentialSide == USeOrderSide.Buy)
            {
                //优先买入
                firstInstrument      = closeArg.BuyInstrument;
                firstOrderSide       = USeOrderSide.Buy;
                firstOrderPriceType  = closeArg.BuyInstrumentOrderPriceType;
                secondInstrument     = closeArg.SellInstrument;
                secondOrderSide      = USeOrderSide.Sell;
                secondOrderPriceType = closeArg.SellInstrumentOrderPriceType;
                firstPosition        = buyPosition;
                secondPosition       = sellPosition;
            }
            else if (closeArg.PreferentialSide == USeOrderSide.Sell)
            {
                //优先卖出
                firstInstrument      = closeArg.SellInstrument;
                firstOrderSide       = USeOrderSide.Sell;
                firstOrderPriceType  = closeArg.SellInstrumentOrderPriceType;
                secondInstrument     = closeArg.BuyInstrument;
                secondOrderSide      = USeOrderSide.Buy;
                secondOrderPriceType = closeArg.BuyInstrumentOrderPriceType;
                firstPosition        = sellPosition;
                secondPosition       = buyPosition;
            }
            else
            {
                Debug.Assert(false);
            }


            Debug.Assert(closeArg.OrderQtyUint > 0);

            int maxPositon = Math.Max(buyPosition, sellPosition);
            int taskCount  = maxPositon / closeArg.OrderQtyUint;

            if ((maxPositon % closeArg.OrderQtyUint) > 0)
            {
                taskCount += 1;
            }

            #region 构造任务组
            ArbitrageTaskGroup taskGroup = new ArbitrageTaskGroup();
            taskGroup.OpenCloseType  = OpenCloseType.Close;
            taskGroup.BuyInstrument  = closeArg.BuyInstrument;
            taskGroup.SellInstrument = closeArg.SellInstrument;
            taskGroup.BuyInstrumentOrderPriceType  = closeArg.BuyInstrumentOrderPriceType;
            taskGroup.SellInstrumentOrderPriceType = closeArg.SellInstrumentOrderPriceType;

            taskGroup.OperationSide    = argument.OperationSide.GetOppositeSide();
            taskGroup.PreferentialSide = closeArg.PreferentialSide;

            List <ArbitrageTask> taskList = new List <ArbitrageTask>();
            int remainFirstPlanQty        = firstPosition;
            int remainSecondPlanQty       = secondPosition;
            for (int i = 1; i <= taskCount; i++)
            {
                int firstPlanOrderQty = Math.Min(closeArg.OrderQtyUint, remainFirstPlanQty);
                remainFirstPlanQty -= firstPlanOrderQty;
                int secondPlanOrderQty = Math.Min(closeArg.OrderQtyUint, remainSecondPlanQty);
                remainSecondPlanQty -= secondPlanOrderQty;

                ArbitrageTask task = new ArbitrageTask();
                task.TaskId    = i;
                task.TaskState = ArbitrageTaskState.None;
                ArbitrageSubTask firstSubTask = new ArbitrageSubTask()
                {
                    Instrument     = firstInstrument,
                    OrderPriceType = firstOrderPriceType,
                    OrderSide      = firstOrderSide,
                    PlanOrderQty   = firstPlanOrderQty,
                    OffsetType     = USeOffsetType.Close,
                };
                ArbitrageSubTask secondSubTask = new ArbitrageSubTask()
                {
                    Instrument     = secondInstrument,
                    OrderPriceType = secondOrderPriceType,
                    OrderSide      = secondOrderSide,
                    PlanOrderQty   = secondPlanOrderQty,
                    OffsetType     = USeOffsetType.Close
                };

                task.FirstSubTask  = firstSubTask;
                task.SecondSubTask = secondSubTask;

                taskList.Add(task);
            }
            Debug.Assert(remainFirstPlanQty == 0);
            Debug.Assert(remainSecondPlanQty == 0);
            taskGroup.TaskList = taskList;
            #endregion

            return(taskGroup);
        }
        /// <summary>
        /// 创建开仓任务组。
        /// </summary>
        /// <param name="openArg">开仓参数。</param>
        /// <returns></returns>
        private static ArbitrageTaskGroup CreateOpenTaskGroup(ArbitrageArgument argument)
        {
            ArbitrageOpenArgument openArg = argument.OpenArg;

            USeInstrument           firstInstrument      = null;
            USeInstrument           secondInstrument     = null;
            USeOrderSide            firstOrderSide       = USeOrderSide.Buy;
            USeOrderSide            secondOrderSide      = USeOrderSide.Sell;
            ArbitrageOrderPriceType firstOrderPriceType  = ArbitrageOrderPriceType.Unknown;
            ArbitrageOrderPriceType secondOrderPriceType = ArbitrageOrderPriceType.Unknown;

            if (openArg.PreferentialSide == USeOrderSide.Buy)
            {
                //优先买入
                firstInstrument     = openArg.BuyInstrument;
                firstOrderSide      = USeOrderSide.Buy;
                firstOrderPriceType = openArg.BuyInstrumentOrderPriceType;

                secondInstrument     = openArg.SellInstrument;
                secondOrderSide      = USeOrderSide.Sell;
                secondOrderPriceType = openArg.SellInstrumentOrderPriceType;
            }
            else if (openArg.PreferentialSide == USeOrderSide.Sell)
            {
                //优先卖出
                firstInstrument     = openArg.SellInstrument;
                firstOrderSide      = USeOrderSide.Sell;
                firstOrderPriceType = openArg.SellInstrumentOrderPriceType;

                secondInstrument     = openArg.BuyInstrument;
                secondOrderSide      = USeOrderSide.Buy;
                secondOrderPriceType = openArg.BuyInstrumentOrderPriceType;
            }
            else
            {
                Debug.Assert(false);
            }

            Debug.Assert(openArg.OrderQtyUint > 0);
            int taskCount = openArg.TotalOrderQty / openArg.OrderQtyUint;

            if ((openArg.TotalOrderQty % openArg.OrderQtyUint) > 0)
            {
                taskCount += 1;
            }

            #region 构造任务组
            ArbitrageTaskGroup taskGroup = new ArbitrageTaskGroup();
            taskGroup.OpenCloseType  = OpenCloseType.Open;
            taskGroup.BuyInstrument  = openArg.BuyInstrument;
            taskGroup.SellInstrument = openArg.SellInstrument;
            taskGroup.BuyInstrumentOrderPriceType  = openArg.BuyInstrumentOrderPriceType;
            taskGroup.SellInstrumentOrderPriceType = openArg.SellInstrumentOrderPriceType;

            taskGroup.OperationSide    = argument.OperationSide;
            taskGroup.PreferentialSide = openArg.PreferentialSide;

            List <ArbitrageTask> taskList = new List <ArbitrageTask>();
            int remainPlanQty             = openArg.TotalOrderQty;
            for (int i = 1; i <= taskCount; i++)
            {
                int planOrderQty = Math.Min(openArg.OrderQtyUint, remainPlanQty);
                Debug.Assert(planOrderQty > 0 && planOrderQty <= openArg.OrderQtyUint);
                remainPlanQty -= planOrderQty;

                ArbitrageTask task = new ArbitrageTask();
                task.TaskId    = i;
                task.TaskState = ArbitrageTaskState.None;
                ArbitrageSubTask firstSubTask = new ArbitrageSubTask()
                {
                    Instrument     = firstInstrument,
                    OrderPriceType = firstOrderPriceType,
                    OrderSide      = firstOrderSide,
                    PlanOrderQty   = planOrderQty,
                    OffsetType     = USeOffsetType.Open,
                };
                ArbitrageSubTask secondSubTask = new ArbitrageSubTask()
                {
                    Instrument     = secondInstrument,
                    OrderPriceType = secondOrderPriceType,
                    OrderSide      = secondOrderSide,
                    PlanOrderQty   = planOrderQty,
                    OffsetType     = USeOffsetType.Open
                };

                task.FirstSubTask  = firstSubTask;
                task.SecondSubTask = secondSubTask;

                taskList.Add(task);
            }
            Debug.Assert(remainPlanQty == 0);
            taskGroup.TaskList = taskList;
            #endregion

            return(taskGroup);
        }
        /// <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>
        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);
        }
        ///// <summary>
        ///// 绘制任务。
        ///// </summary>
        ///// <param name="g"></param>
        //private void DrawTaskList_2(Graphics g)
        //{
        //    ArbitrageTaskGroup taskGroup = m_taskGroup;
        //    float xBegin = 35.0f;
        //    float yBegin = 10.0f;
        //    List<ArbitrageTask> taskList = taskGroup.TaskList;
        //    if (taskList != null && taskList.Count > 0)
        //    {
        //        for (int i = 0; i < taskList.Count; i++)
        //        {
        //            ArbitrageTask task = taskList[i];
        //            float x = xBegin + (i * m_itemInterval);
        //            float y = yBegin;

        //            ArbitrageSubTask firstSubTask = task.FirstSubTask;
        //            ArbitrageSubTask secondSubTask = task.SecondSubTask;

        //            //优先任务
        //            Brush firstTaskBrush = m_taskNoExceuctBrush;
        //            if (firstSubTask.TradeQty == firstSubTask.PlanOrderQty)
        //            {
        //                firstTaskBrush = m_taskFinishBrush;
        //            }
        //            else if (firstSubTask.OrderQty > 0)
        //            {
        //                firstTaskBrush = m_taskInExecuteBrush;
        //            }
        //            else
        //            {
        //                firstTaskBrush = m_taskNoExceuctBrush;
        //            }
        //            g.FillEllipse(firstTaskBrush, x, y, m_taskDotWidth, m_taskDotHeight);
        //            g.DrawString(string.Format("{0}/{1}", firstSubTask.TradeQty, firstSubTask.PlanOrderQty),
        //                m_font, firstTaskBrush, new RectangleF(x + m_taskDotWidth / 2 - 15, y + 13, 30, 10), m_centerStringFormat);

        //            //反手任务
        //            Brush secondTaskBrush = m_taskNoExceuctBrush;
        //            if (secondSubTask.TradeQty == secondSubTask.PlanOrderQty)
        //            {
        //                secondTaskBrush = m_taskFinishBrush;
        //            }
        //            else if (secondSubTask.OrderQty > 0)
        //            {
        //                secondTaskBrush = m_taskInExecuteBrush;
        //            }
        //            else
        //            {
        //                secondTaskBrush = m_taskNoExceuctBrush;
        //            }
        //            //反手任务
        //            g.FillEllipse(secondTaskBrush, x, y + 30, m_taskDotWidth, m_taskDotHeight);
        //            g.DrawString(string.Format("{0}/{1}", secondSubTask.TradeQty, secondSubTask.PlanOrderQty),
        //                m_font, secondTaskBrush, new RectangleF(x + m_taskDotWidth / 2 - 15, y + 30 + 13, 30, 10), m_centerStringFormat);
        //        }
        //    }
        //}

        private void DrawTaskList(Graphics g)
        {
            float xBegin = 45.0f;              // 起始x坐标
            float yBegin = 10.0f;              // 起始y坐标

            float y_f_NegativeQtyOffset = 0;   // 优先任务反手量偏移位置
            float y_f_taskOffset        = 13f; // 优先任务主图标偏移位置
            float y_f_QtyOffset         = 26f; // 优先任务正手量偏移位置

            float y_s_taskOffset = 45f;        // 反手任务主图标偏移位置
            float y_s_QtyOffset  = 58f;        // 反手任务正手量偏移位置

            ArbitrageTaskGroup taskGroup = m_taskGroup;

            List <ArbitrageTask> taskList = taskGroup.TaskList;

            if (taskList == null || taskList.Count <= 0)
            {
                return;
            }

            for (int i = 0; i < taskList.Count; i++)
            {
                ArbitrageTask task = taskList[i];
                float         x    = xBegin + (i * m_itemInterval);
                float         y    = yBegin;

                ArbitrageSubTask firstSubTask    = task.FirstSubTask;
                ArbitrageSubTask secondSubTask   = task.SecondSubTask;
                Brush            firstTaskBrush  = GetSubTaskBrush(firstSubTask);
                Brush            secondTaskBrush = GetSubTaskBrush(secondSubTask);

                Pen tmpPen = new Pen(Color.Red);

                //优先合约反向委托量
                if (firstSubTask.NegativeOrderQty > 0)
                //if (i == 2)
                {
                    float      rectWidth  = 30f;
                    float      rectHeight = 10f;
                    RectangleF rect       = new RectangleF(x - (rectWidth / 2), y + y_f_NegativeQtyOffset, rectWidth, rectHeight);
                    string     text       = string.Format("{0}/{1}", firstSubTask.NegativeTradeQty, firstSubTask.NegativeOrderQty);
                    g.DrawString(text, m_negativeFont, m_negativeTaskBrush, rect, m_centerStringFormat);
                }

                //优先任务点
                g.FillEllipse(firstTaskBrush, x - m_taskDotDiameter / 2, y + y_f_taskOffset, m_taskDotDiameter, m_taskDotDiameter);

                //g.DrawRectangle(tmpPen, x, y + f_y_taskOffset, m_taskDotWidth, m_taskDotHeight);
                {
                    float      rectWidth  = 30f;
                    float      rectHeight = 10f;
                    RectangleF rect       = new RectangleF(x - rectWidth / 2, y + y_f_QtyOffset, rectWidth, rectHeight);
                    string     text       = string.Format("{0}/{1}", firstSubTask.TradeQty, firstSubTask.PlanOrderQty);
                    g.DrawString(text, m_font, firstTaskBrush, rect, m_centerStringFormat);
                }

                //反手任务点
                g.FillEllipse(secondTaskBrush, x - m_taskDotDiameter / 2, y + y_s_taskOffset, m_taskDotDiameter, m_taskDotDiameter);

                //g.DrawRectangle(tmpPen, x, y + s_y_taskOffset, m_taskDotWidth, m_taskDotHeight);

                {
                    float      rectWidth  = 30f;
                    float      rectHeight = 10f;
                    RectangleF rect       = new RectangleF(x - rectWidth / 2, y + y_s_QtyOffset, rectWidth, rectHeight);
                    string     text       = string.Format("{0}/{1}", secondSubTask.TradeQty, secondSubTask.PlanOrderQty);
                    g.DrawString(text, m_font, secondTaskBrush, rect, m_centerStringFormat);
                }
            }
        }