コード例 #1
0
ファイル: DataClass.cs プロジェクト: LaoKpa/HFT-3
        //重载OnRecvDataMsg方法,接收行情数据
        // 请注意:
        //  1. 不要在这个函数里做耗时操作
        //  2. 只在这个函数里做数据获取工作 -- 将数据复制到其它数据缓存区,由其它线程做业务逻辑处理
        public override void OnRecvDataMsg(TDFMSG msg)
        {
            try
            {
                if (msg.MsgID == TDFMSGID.MSG_DATA_MARKET)
                {
                    //行情消息
                    TDFMarketData[] marketDataArr = msg.Data as TDFMarketData[];

                    foreach (TDFMarketData data in marketDataArr)
                    {
                        //if (data.Code.Contains("10000015"))
                        //    continue;
                        lock (this.dataDict)
                        {
                            if (dataDict.Keys.Contains(data.Code))
                            {
                                SingleStockData sd = dataDict[data.Code];

                                //数据获取部分
                                if (data.Match != 0)
                                {
                                    sd.LastPrice = (double)data.Match / 10000;     //最新成交价
                                }
                                sd.PrevClose    = (double)data.PreClose / 10000;
                                sd.AskPrices[0] = (double)data.AskPrice[0] / 10000;
                                sd.BidPrices[0] = (double)data.BidPrice[0] / 10000;

                                for (int i = 0; i < 10; i++)
                                {
                                    sd.BidPrices[i] = (double)data.BidPrice[i] / 10000;
                                    sd.AskPrices[i] = (double)data.AskPrice[i] / 10000;
                                    sd.BidVol[i]    = data.BidVol[i];
                                    sd.AskVol[i]    = data.AskVol[i];
                                }

                                if ((sd.ShortPriceListed != sd.AskPrices[0]) && (sd.StatusTrending == StrategyStatus.ShortListedOnly)) //最新卖一已变动,需改价重挂
                                {
                                    sd.bAskPriceChanged = true;                                                                        //测试,按卖五挂单
                                }
                                # region Fishing Strategies
                                //业务逻辑部分,只有对FishingStrategy这样时效要求极高的放在此处,其余均放入EngineClass
                                if (sd.StatusCBFishing != StrategyStatus.None)     //此ticker需要跑CBFishing Strategy
                                {
                                    if (sd.StatusCBFishing == StrategyStatus.New)  //首次挂买单,或上一轮结束后重新挂单
                                    {
                                        //sd.LongPriceListed = sd.BidPrices[0] - sd.CBBuyPriceOffset; //挂在卖五,后续可以参数化
                                        sd.LongPriceListed = sd.BidPrices[4];     //挂在卖五,后续可以参数化
                                        sd.StatusCBFishing = StrategyStatus.LongListedOnly;

                                        //下一步考虑在EngineClass或TradeClass中生成Order,只需有strategy和ticker,即可在dataDict中取到生成order所需数据
                                        FIXApi.OrderBookEntry entry = new OrderBookEntry();
                                        entry.strategies     = TradingStrategies.CBFishing;
                                        entry.action         = OrderAction.Buy;
                                        entry.type           = FIXApi.OrderType.CreditBuy;
                                        entry.ticker         = data.Code;
                                        entry.quantityListed = sd.Quantity;
                                        entry.priceListed    = sd.LongPriceListed;

                                        sd.StatusCBFishing = StrategyStatus.Pending;     //获得成交回报后再改变状态,避免重复执行
                                        Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_CBFishing));
                                        orderThread.IsBackground = true;
                                        orderThread.Start(entry);
                                    }
                                    else if (sd.StatusCBFishing == StrategyStatus.LongListedOnly)                               //买单已挂,根据最新价格检查是否需要撤单重挂
                                    {
                                        if ((sd.LongPriceListed >= sd.BidPrices[3]) || (sd.LongPriceListed <= sd.BidPrices[5])) //大于卖三或小于卖七时重挂
                                        {
                                            sd.LongPriceListed = sd.BidPrices[0] - sd.CBBuyPriceOffset;
                                            FIXApi.OrderBookEntry entry = new OrderBookEntry();
                                            entry.strategies     = TradingStrategies.CBFishing;
                                            entry.action         = OrderAction.CancelAndBuy;
                                            entry.type           = FIXApi.OrderType.CreditBuy;
                                            entry.ticker         = data.Code;
                                            entry.quantityListed = sd.Quantity;
                                            entry.priceListed    = sd.LongPriceListed;

                                            sd.StatusCBFishing = StrategyStatus.Pending;     //获得成交回报后再改变状态,避免重复执行
                                            Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_CBFishing));
                                            orderThread.IsBackground = true;
                                            orderThread.Start(entry);
                                        }
                                        //if ((sd.ShortPriceListed<data.AskPrice[4]) || (sd.ShortPriceListed>data.AskPrice[6]) ) //低于卖五或者高于卖七时撤单重挂,避免撤单过于频繁
                                        //    sd.ShortPriceListed = sd.AskPrices[4];
                                        ////cancel and resend
                                    }
                                    else if (sd.StatusCBFishing == StrategyStatus.ShortListedOnly)       //卖单已挂,根据最新价格检查是否需要撤单重挂
                                    {
                                        if (sd.ShortPriceListed > sd.AskPrices[0])
                                        {
                                            sd.ShortPriceListed = sd.AskPrices[0] - sd.CBSellPriceOffset;      //一直挂在比卖一低0.01的位置
                                            FIXApi.OrderBookEntry entry = new OrderBookEntry();
                                            entry.strategies     = TradingStrategies.CBFishing;
                                            entry.action         = OrderAction.CancelAndSell_CF;
                                            entry.type           = FIXApi.OrderType.CreditSell;
                                            entry.ticker         = data.Code;
                                            entry.quantityListed = sd.Quantity;
                                            entry.priceListed    = sd.ShortPriceListed;
                                            entry.strategies     = TradingStrategies.CBFishing;
                                            sd.StatusCBFishing   = StrategyStatus.Pending;   //获得成交回报后再改变状态,避免重复执行
                                            Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_CBFishing));
                                            orderThread.IsBackground = true;
                                            orderThread.Start(entry);
                                        }
                                        //if ((sd.ShortPriceListed<data.AskPrice[4]) || (sd.ShortPriceListed>data.AskPrice[6]) ) //低于卖五或者高于卖七时撤单重挂,避免撤单过于频繁
                                        //    sd.ShortPriceListed = sd.AskPrices[4];
                                        ////cancel and resend
                                    }
                                    else if (sd.StatusStockFishing != StrategyStatus.None)     //此ticker需要跑StockFishing Strategy
                                    {
                                    }
                                }
                                # endregion
                            }
                        }
                    }
                    //极其耗时,轻易不要打开
                    //RecvDataReport(this, null);
                }
                else if (msg.MsgID == TDFMSGID.MSG_DATA_FUTURE)
                {
                    //期货行情消息
                    TDFFutureData[] futureDataArr = msg.Data as TDFFutureData[];
                    foreach (TDFFutureData data in futureDataArr)
                    {
                        ;
                    }
                    return;
                }
                else if (msg.MsgID == TDFMSGID.MSG_DATA_INDEX)
                {
                    //指数消息
                    TDFIndexData[] indexDataArr = msg.Data as TDFIndexData[];
                    foreach (TDFIndexData data in indexDataArr)
                    {
                        return;
                    }
                }
                else if (msg.MsgID == TDFMSGID.MSG_DATA_TRANSACTION)
                {
                    //逐笔成交
                    TDFTransaction[] transactionDataArr = msg.Data as TDFTransaction[];
                    foreach (TDFTransaction data in transactionDataArr)
                    {
                        //每一data变量包含最底层的一笔逐笔成交数据
                        lock (this.dataDict)
                        {
                            if (dataDict.Keys.Contains(data.Code))
                            {
                                //数据获取部分
                                int timeStamp = Convert.ToInt32((double)data.Time / 1000 - 0.5); //去掉毫秒部分;

                                if (timeStamp == 93524)
                                {
                                    timeStamp = 93524;
                                }

                                int direction = 0;
                                if (data.BSFlag == 66)
                                {
                                    direction = 1;
                                }
                                else if (data.BSFlag == 83)
                                {
                                    direction = -1;
                                }
                                int    volume = data.Volume;
                                double price  = (double)data.Price / 10000;

                                if (dataDict[data.Code].zbDataList.Count == 0) //第一次添加
                                {
                                    ZBTickData zbdata = new ZBTickData();
                                    zbdata.timeStamp = timeStamp;

                                    if (direction == 1)
                                    {
                                        zbdata.volumeB     = volume;
                                        zbdata.priceTotalB = price;
                                        zbdata.countB      = 1;
                                        zbdata.priceB      = zbdata.priceTotalB / (double)zbdata.countB;//计算该秒、买方向的平均价格
                                    }
                                    else if (direction == -1)
                                    {
                                        zbdata.volumeS     = volume;
                                        zbdata.priceTotalS = price;
                                        zbdata.countS      = 1;
                                        zbdata.priceS      = zbdata.priceTotalS / (double)zbdata.countS;//计算该秒、买方向的平均价格
                                    }

                                    if ((zbdata.priceB > 0) && (zbdata.priceS > 0))
                                    {
                                        zbdata.price = (zbdata.priceB + zbdata.priceS) / 2;
                                    }
                                    else
                                    {
                                        zbdata.price = (zbdata.priceB + zbdata.priceS);
                                    }
                                    zbdata.volume = zbdata.volumeB + zbdata.volumeS;

                                    if ((zbdata.volume == 0) || (zbdata.price == 0))
                                    {
                                        continue;                                             //空记录
                                    }
                                    dataDict[data.Code].zbDataList.Add(zbdata);

                                    dataDict[data.Code].ZBFirstIndex = 0;
                                    dataDict[data.Code].ZBLastIndex  = 0;
                                }
                                else
                                {
                                    int currLastIndex = dataDict[data.Code].ZBLastIndex;

                                    if (dataDict[data.Code].zbDataList[currLastIndex].timeStamp == timeStamp) //同一时间戳存在,只需更新价格与成交量,不需插入新纪录
                                    {
                                        ZBTickData zbdata = dataDict[data.Code].zbDataList[currLastIndex];    //取出字典中的元素并进行修改,由于是引用,对zbdata的修改会自动在字典中更新

                                        if (direction == 1)
                                        {
                                            zbdata.priceTotalB = zbdata.priceTotalB + price;
                                            zbdata.countB      = zbdata.countB + 1;
                                            zbdata.priceB      = zbdata.priceTotalB / (double)zbdata.countB;//计算该秒、该方向的平均价格
                                            zbdata.volumeB     = zbdata.volumeB + volume;
                                        }
                                        else if (direction == -1)
                                        {
                                            zbdata.priceTotalS = zbdata.priceTotalS + price;
                                            zbdata.countS      = zbdata.countS + 1;
                                            zbdata.priceS      = zbdata.priceTotalS / (double)zbdata.countS;//计算该秒、该方向的平均价格
                                            zbdata.volumeS     = zbdata.volumeS + volume;
                                        }

                                        if ((zbdata.priceB > 0) && (zbdata.priceS > 0))
                                        {
                                            zbdata.price = (zbdata.priceB + zbdata.priceS) / 2;
                                        }
                                        else
                                        {
                                            zbdata.price = (zbdata.priceB + zbdata.priceS);
                                        }
                                        zbdata.volume = zbdata.volumeB + zbdata.volumeS;

                                        dataDict[data.Code].zbDataList.RemoveAt(currLastIndex);
                                        dataDict[data.Code].zbDataList.Add(zbdata);
                                    }
                                    else //不存在此时间戳,需添加新纪录
                                    {
                                        ZBTickData zbdata = new ZBTickData();
                                        zbdata.timeStamp = timeStamp;

                                        if (direction == 1)
                                        {
                                            zbdata.volumeB     = volume;
                                            zbdata.priceTotalB = price;
                                            zbdata.countB      = 1;
                                            zbdata.priceB      = zbdata.priceTotalB / (double)zbdata.countB;//计算该秒、买方向的平均价格
                                        }
                                        else if (direction == -1)
                                        {
                                            zbdata.volumeS     = volume;
                                            zbdata.priceTotalS = price;
                                            zbdata.countS      = 1;
                                            zbdata.priceS      = zbdata.priceTotalS / (double)zbdata.countS;//计算该秒、买方向的平均价格
                                        }

                                        if ((zbdata.priceB > 0) && (zbdata.priceS > 0))
                                        {
                                            zbdata.price = (zbdata.priceB + zbdata.priceS) / 2;
                                        }
                                        else
                                        {
                                            zbdata.price = (zbdata.priceB + zbdata.priceS);
                                        }
                                        zbdata.volume = zbdata.volumeB + zbdata.volumeS;

                                        //dataDict[data.Code].totalVolTillNow += zbdata.volume;
                                        if ((zbdata.volume == 0) || (zbdata.price == 0))
                                        {
                                            continue;                                             //空记录
                                        }
                                        dataDict[data.Code].zbDataList.Add(zbdata);

                                        dataDict[data.Code].ZBLastIndex = dataDict[data.Code].ZBLastIndex + 1;
                                    }
                                }

                                /*
                                 * //数据获取部分
                                 * ZBTickData zbdata = new ZBTickData();
                                 * zbdata.timeStamp = Convert.ToInt32((double)data.Time / 1000); //去掉毫秒部分
                                 *
                                 * //if (zbdata.timeStamp > 93850) { int i = 0; i++; }
                                 *
                                 * zbdata.price = (double)data.Price / 10000;
                                 * if (data.BSFlag == 66)
                                 *  zbdata.direction = 1;
                                 * else if (data.BSFlag == 83)
                                 *  zbdata.direction = -1;
                                 * else
                                 *  zbdata.direction = 0;
                                 * zbdata.volume = data.Volume;
                                 * dataDict[data.Code].totalVolTillNow += zbdata.volume;
                                 *
                                 * dataDict[data.Code].zbDataList.Add(zbdata);
                                 *
                                 * if (dataDict[data.Code].zbDataList.Count == 1) //第一次添加
                                 * {
                                 *  dataDict[data.Code].ZBFirstIndex = 0;
                                 *  dataDict[data.Code].ZBLastIndex = 0;
                                 * }
                                 * else
                                 * {
                                 *  dataDict[data.Code].ZBLastIndex = dataDict[data.Code].ZBLastIndex + 1;
                                 * }
                                 */
                            }
                        }
                        //极其耗时,轻易不要打开
                        //RecvDataReport(this, null);
                    }
                }
                else if (msg.MsgID == TDFMSGID.MSG_DATA_ORDER)
                {
                    //逐笔委托
                    TDFOrder[] orderDataArr = msg.Data as TDFOrder[];
                    foreach (TDFOrder data in orderDataArr)
                    {
                        return;
                    }
                }
                else if (msg.MsgID == TDFMSGID.MSG_DATA_ORDERQUEUE)
                {
                    //委托队列
                    TDFOrderQueue[] orderQueueArr = msg.Data as TDFOrderQueue[];
                    foreach (TDFOrderQueue data in orderQueueArr)
                    {
                        return;
                    }
                }
            }
コード例 #2
0
        public void ComputeOneTick(string ticker, int firstIndex, int lastIndex)
        {
            int test;

            double pctChgThreshold   = 0.003, //涨幅指标
                   volThreshold      = 3,     //放量指标
                   bsThreshold       = 0.66,  //内外盘指标
                   priceVolThreshold = 0.01;

            bool cPriceVol = true, cWithDraw = true, cSingleHugeOrder = true;

            bool cPriceLevel = false, cVolume = false, cBuySellRatio = false, cPriceTrend = true;
            bool cNoSuddenUp = true;//暂不加涨速过快指标,先用内外盘指标控制

            //CuScore常数
            int MALength = 60; //过去一分钟均价


            SingleStockData sd = dataDict[ticker];


            int midIndex = firstIndex;

            ////统计预观察期交易量和价格
            //double p0 = sd.zbDataList[firstIndex].price, p2 = sd.zbDataList[midIndex].price;

            //for (int i = firstIndex; i < midIndex; i++) //遍历过去10分钟逐笔数据,计算相应指标
            //{
            //    ZBTickData zbData = sd.zbDataList[i];

            //    double t1 = Convert.ToDouble(ComputeIntTimeDiff(sd.zbDataList[firstIndex].timeStamp, sd.zbDataList[i].timeStamp));
            //    double p1 = (p2 - p0) / t0 * t1 + p0;

            //    if (Math.Abs(zbData.price / p1 - 1) > priceVolThreshold)
            //    {
            //        cPriceVol = false; //一旦预观察期价格波动幅度过大,则不符合要求
            //        return; //直接退出,该段不符合要求
            //    }

            //    totalPreVolume += zbData.volume;
            //}


            if (sd.zbDataList[lastIndex].timeStamp > 94600)
            {
                cPriceLevel = false;
            }

            double zbMinPrice = sd.zbDataList[midIndex].price;
            double zbMaxPrice = sd.zbDataList[midIndex].price;

            int zbMinIndex = midIndex, zbMaxIndex = midIndex;

            int totalBuyVolume = 0, totalSellVolume = 0, totalBuyCount = 0, totalSellCount = 0;
            int totalObsVolume  = 0;
            int maxSingleVolume = 0;

            double timeToLast = 0;

            double maPriceSum = 0, maCountSum = 0, maPrice = 0;

            for (int i = lastIndex; i > midIndex; i--) //遍历过去观察期内逐笔数据,计算相应指标
            {
                ZBTickData zbData = sd.zbDataList[i];

                if (sd.bComputeCuscore)
                {
                    maPriceSum = maPriceSum + zbData.price;
                    maCountSum = maCountSum + 1;
                }



                if (sd.StatusTrending == StrategyStatus.LongExecuted)
                {
                    if (zbData.price > sd.MaxPriceAfterBuy)
                    {
                        sd.MaxPriceAfterBuy = zbData.price;
                    }
                }

                //if (zbData.direction != 1) continue; //必须是买盘成交

                totalObsVolume += zbData.volume;
                if (zbData.volume > maxSingleVolume)
                {
                    maxSingleVolume = zbData.volume;
                }

                //if (zbData.price < zbMinPrice) //寻找最小值
                //{
                //    zbMinPrice = zbData.price; //寻找2分钟内的最低价格
                //    zbMinIndex = i; //寻找2分钟内最低价格的索

                //    if (sd.StatusTrending == StrategyStatus.New)  //以免影响卖出逻辑
                //    {
                //        totalObsVolume = 0;
                //        totalBuyVolume = 0; totalSellVolume = 0; totalBuyCount = 0; totalSellCount = 0; //清零,只计算从最低点开始的成交量
                //    }
                //}

                //if (zbData.price > zbMaxPrice) //寻找最大值
                //{
                //    zbMaxPrice = zbData.price; //寻找2分钟内的最低价格
                //    zbMaxIndex = i; //寻找2分钟内最低价格的索引
                //}


                //unable to compute huge order for now
                //if (zbData.price * zbData.volume > 100000) //只统计大单
                //{
                //    if (zbData.direction == 1)
                //    {
                //        totalBuyCount = totalBuyCount + 1;
                //        totalBuyVolume = totalBuyVolume + zbData.volume;
                //    }
                //    else if (zbData.direction == -1)
                //    {
                //        totalSellCount = totalSellCount + 1;
                //        totalSellVolume = totalSellVolume + zbData.volume;
                //    }
                //}


                totalBuyCount  = totalBuyCount + zbData.countB;
                totalBuyVolume = totalBuyVolume + zbData.volumeB;

                totalSellCount  = totalSellCount + zbData.countS;
                totalSellVolume = totalSellVolume + zbData.volumeS;

                double pctChg = (sd.zbDataList[lastIndex].price - zbData.price) / zbData.price;

                if (zbData.price > 5)
                {
                    if (pctChg > pctChgThreshold)
                    {
                        cPriceLevel = true;
                    }
                }
                else
                {
                    if (pctChg > pctChgThreshold * 2)
                    {
                        cPriceLevel = true;
                    }
                }

                if (cPriceLevel) //涨幅条件满足,检测其它条件
                {
                    double timeToLast1 = 0;
                    zbMinIndex  = i;
                    timeToLast1 = Convert.ToDouble(ComputeIntTimeDiff(sd.zbDataList[zbMinIndex].timeStamp, sd.zbDataList[lastIndex].timeStamp)); //时间,以秒计

                    if (timeToLast1 < 10)
                    {
                        continue;                   //跳涨,不符合要求,继续往前搜索,看是否上涨趋势
                    }
                    break;
                }

                //if (i > midIndex)
                //{
                //    double oneTickPctChg = (zbData.price - sd.zbDataList[i - 1].price) / sd.zbDataList[i - 1].price;

                //    ////条件1: 要求2分钟内没有某一笔拉升很大涨幅,即5块钱以下的不能有一笔的涨幅不超过0.5%,5块钱以上的不能有一笔超过0.25%
                //    if (zbMinPrice > 5)
                //    {
                //        if (oneTickPctChg > pctChgThreshold*0.5) cNoSuddenUp = false;
                //    }
                //    else
                //    { if (oneTickPctChg > 2*pctChgThreshold*0.5) cNoSuddenUp = false; }

                //    //最大回撤不超过涨幅的一半
                //    double pctWithDraw = (zbData.price - zbMaxPrice) / zbMaxPrice;
                //    if (pctWithDraw < - 0.5 * pctChgThreshold) cWithDraw = false;
                //}
            }
            //观察期遍历结束

            //计算CuScore
            if ((sd.zbDataList[lastIndex].timeStamp > 112955) && (ticker == "601628"))
            {
                //if (sd.zbDataList[lastIndex].timeStamp > 112930)
                test = 0;
            }

            if (sd.bComputeCuscore)
            {
                if (maCountSum == 0)
                {
                    throw new Exception("maSum=0");
                }

                double cuT        = ComputeIntTimeDiff(sd.BuyTime, sd.zbDataList[lastIndex].timeStamp);
                double cuScoreNew = 0;
                maPrice = maPriceSum / maCountSum;

                if (sd.zbDataList[lastIndex].timeStamp > sd.cuScoreLastTimeStamp)
                {
                    if ((sd.zbDataList[lastIndex].timeStamp > 93541) && (ticker == "600015"))
                    {
                        test = 0;
                    }

                    if (sd.cuScoreLastIndex == -1) //首次计算
                    {
                        cuScoreNew = (sd.zbDataList[lastIndex].price - maPrice) * cuT;
                    }
                    else
                    {
                        cuScoreNew = sd.CuScoreList[sd.cuScoreLastIndex] + (sd.zbDataList[lastIndex].price - maPrice) * cuT;
                    }

                    sd.CuScoreList.Add(cuScoreNew);
                    sd.cuScoreLastIndex     = sd.cuScoreLastIndex + 1;
                    sd.cuScoreLastTimeStamp = sd.zbDataList[lastIndex].timeStamp;
                }

                sd.bCuScoreSell = false;
                if (sd.cuScoreLastIndex > 60)
                {
                    double minScore = sd.CuScoreList[sd.cuScoreLastIndex - 1];
                    for (int iCu = sd.cuScoreLastIndex - 1; iCu > (sd.cuScoreLastIndex - 60); iCu--)
                    {
                        if (sd.CuScoreList[iCu] < minScore)
                        {
                            minScore = sd.CuScoreList[iCu];
                        }
                    }
                    if (sd.CuScoreList[sd.cuScoreLastIndex] < minScore)
                    {
                        sd.bCuScoreSell = true;

                        //if (ticker == "600015")
                        //    sd.bCuScoreSell = true;
                    }
                }
            }

            //检查单笔大单
            //if (((double)maxSingleVolume / (double)totalObsVolume) > 0.5) cSingleHugeOrder = false; ; // 一笔大单占交易量一半以上

            //检查趋势
            //for (int k = zbMinIndex; k < lastIndex - 1; k++)
            //{
            //    if ((sd.zbDataList[k + 1].price / sd.zbDataList[k].price - 1) < -0.002) cPriceTrend = false;

            //    if ((!cPriceTrend)&&(sd.zbDataList[lastIndex].timeStamp > 94550)) Thread.Sleep(1);
            //}


            //2 - Volume:2分钟成交量均超过过去一周平均水平的3倍。后续再加上成交笔数要求


            //if (Convert.ToDouble((lastIndex - zbMinIndex)) / (double)t < 0.3) return; //数据点过少,平均超过2秒才有一次成交

            double avgVolume1 = (double)sd.PrevVolume / (4 * 3600); //每秒平均成交量

            //double avgVolume1 = sd.avgVolTillNow; //每秒平均成交量

            timeToLast = Convert.ToDouble(ComputeIntTimeDiff(sd.zbDataList[firstIndex].timeStamp, sd.zbDataList[lastIndex].timeStamp)); //时间,以秒计
            if (totalObsVolume > volThreshold * avgVolume1 * timeToLast)
            {
                cVolume = true;
            }

            if ((totalBuyCount + totalSellCount) == 0)
            {
                return;                                        //盘前数据,无交易量
            }
            //3 - 内外盘:2分钟内内外盘指标,买盘的交易量和交易笔数占比都要超过75%

            //if ((totalBuyVolume > bsThreshold * (totalBuyVolume + totalSellVolume)) && (totalBuyCount > bsThreshold * (totalBuyCount + totalSellCount)))
            if (totalBuyVolume > bsThreshold * (totalBuyVolume + totalSellVolume))
            {
                cBuySellRatio = true;
            }


            ////条件3为要求前10分钟振幅不能太高,不超过2.5%
            //double range=(priceArray.Max() - priceArray.Min())/priceArray.Min();
            //if (range<0.025) c3=true;

            ////条件5要求当时涨幅不能超过0.05,且必须是上涨的 //此处为固定区间涨幅,并非区间振幅
            //double pctChgFromStart = (dd.tickData[obsEndIndex].LastPrice - startingPrice) / startingPrice;
            //if ((pctChgFromStart > 0) && (pctChgFromStart < 0.05)) c5 = true;


            if ((sd.zbDataList[lastIndex].timeStamp > 93739) && (ticker == "600015"))
            {
                test = 0;
            }


            //if (sd.zbDataList[lastIndex].direction != 1) return; //必须是买盘成交

            /*涨停撤单逻辑,暂停使用
             * if (sd.zbDataList[lastIndex].price > sd.PrevClose*1.08)
             * {
             *  FIXApi.OrderBookEntry entry = new OrderBookEntry();
             *  entry.strategies = TradingStrategies.StockTrending;
             *  entry.action = OrderAction.CancelLock;
             *  entry.ticker = ticker;
             *  entry.quantityListed = 0;//没有必要输入Quantity
             *  entry.priceListed = 0;
             *  entry.orderTime = sd.BuyTime;
             *  entry.orderDate = sd.DateStamp;
             *
             *  sd.StatusTrending = StrategyStatus.Pending; //获得成交回报后再改变状态,避免重复执行
             *  Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_StockTrending));
             *  orderThread.IsBackground = true;
             *  orderThread.Start(entry);
             * }
             */

            if (sd.StatusTrending == StrategyStatus.New) //尚未下过单
            {
                //判断是否需要下买单
                if ((cPriceLevel && cVolume && cBuySellRatio && cNoSuddenUp && cWithDraw && cPriceVol && cPriceTrend && cSingleHugeOrder) || bTestEngine)
                {
                    //到达此处即条件符合,下买单
                    sd.BuyTime              = sd.zbDataList[lastIndex].timeStamp; //用逐笔时间,此处修改Dictionary,如发生线程冲突可能出现问题,后续把所有涉及修改zbDataList的逻辑全部去掉,engine中只读
                    sd.bComputeCuscore      = true;                               //开始计算CuScore;
                    sd.CuScoreList          = new List <double>();
                    sd.cuScoreLastIndex     = -1;
                    sd.cuScoreLastTimeStamp = sd.BuyTime;

                    if ((tc.mode == TradeMode.Backtest) || (tc.mode == TradeMode.Debug))
                    {
                        sd.StatusTrending = StrategyStatus.LongExecuted;
                        if (sd.BuyTime > 144500)
                        {
                            return;                      //14:45分后不再下单
                        }
                        FIXApi.OrderBookEntry entry = new OrderBookEntry();
                        entry.strategies     = TradingStrategies.StockTrending;
                        entry.action         = OrderAction.Buy;
                        entry.type           = FIXApi.OrderType.CashBuy;
                        entry.ticker         = ticker;
                        entry.quantityListed = sd.Quantity;
                        entry.priceListed    = sd.zbDataList[lastIndex].price;

                        entry.lockPrice = Math.Round(sd.PrevClose * 1.09, 2);


                        entry.orderTime = sd.BuyTime;
                        entry.orderDate = sd.DateStamp;

                        tc.OrderSender_StockTrending(entry);
                    }
                    else if (tc.mode == TradeMode.Production)
                    {
                        if (sd.BuyTime > 144500)
                        {
                            return;                      //14:45分后不再下单
                        }
                        FIXApi.OrderBookEntry entry = new OrderBookEntry();
                        entry.strategies = TradingStrategies.StockTrending;
                        entry.action     = OrderAction.Buy;
                        //entry.type = FIXApi.OrderType.CreditMarginBuy; //融资买入
                        entry.type   = FIXApi.OrderType.CashBuy; //信用账户现金买入
                        entry.ticker = ticker;

                        //double maxAmount = 20000;
                        //int quantityListed = 100;
                        //if (sd.PrevClose > 0)
                        //{
                        //    quantityListed = Math.Min(sd.MaxQuantity, Convert.ToInt32(maxAmount / sd.PrevClose / 100) * 100);
                        //}
                        //entry.quantityListed = quantityListed;
                        entry.quantityListed = sd.Quantity; //DEBUG

                        if (bTestEngine)
                        {
                            entry.priceListed = sd.AskPrices[4];//测试用,挂买五 DEBUG
                        }
                        else
                        {
                            entry.priceListed = sd.AskPrices[4];//直接按卖五下限价买单,以保证成交
                        }
                        entry.lockPrice = Math.Round(sd.PrevClose * 1.098, 2);

                        entry.orderTime = sd.BuyTime;
                        entry.orderDate = sd.DateStamp;

                        sd.StatusTrending = StrategyStatus.Pending; //获得成交回报后再改变状态,避免重复执行

                        OrderRouter(entry);
                    }
                }
            }
            else if (sd.StatusTrending == StrategyStatus.LongExecuted) //买单已下,下卖单
            {
                //判断是否需要下卖单
                int s = ComputeIntTimeDiff(sd.BuyTime, sd.zbDataList[lastIndex].timeStamp);

                int sellTime = 120;//最多5分钟后卖出

                if (s < sellTime)
                {
                    return;               //5分钟内无论如何不卖
                }
                if (!sd.bCuScoreSell)
                {
                    return;
                }

                //if (bTestEngine) sellTime = 10; //测试下单用,10秒后即卖出 DEBUG

                //if ((s < sellTime) && (!sd.bCuScoreSell))
                //{
                //    //double bsSellThreshold = 0.5;
                //    //根据内外盘指标决定卖出时间,
                //    //if ((totalBuyVolume > bsSellThreshold * (totalBuyVolume + totalSellVolume)) && (totalBuyCount > bsSellThreshold * (totalBuyCount + totalSellCount))) //只要买盘足够大就继续持有
                //    //if (totalBuyVolume > bsSellThreshold * (totalBuyVolume + totalSellVolume))
                //    return;
                //}



                //条件通过,下卖单
                if ((tc.mode == TradeMode.Backtest) || (tc.mode == TradeMode.Debug))
                {
                    FIXApi.OrderBookEntry entry = new OrderBookEntry();
                    entry.strategies     = TradingStrategies.StockTrending;
                    entry.action         = OrderAction.Sell;
                    entry.type           = FIXApi.OrderType.CashSell;
                    entry.ticker         = ticker;
                    entry.quantityListed = sd.Quantity;
                    entry.priceListed    = sd.zbDataList[lastIndex].price;
                    entry.orderTime      = sd.zbDataList[lastIndex].timeStamp;
                    entry.orderDate      = sd.DateStamp;

                    sd.StatusTrending = StrategyStatus.None; //不重复执行
                    //sd.StatusTrending = StrategyStatus.New; //重复执行
                    tc.OrderSender_StockTrending(entry);

                    tc.CalcPnL();
                }
                else if (tc.mode == TradeMode.Production)
                {
                    FIXApi.OrderBookEntry entry = new OrderBookEntry();
                    entry.strategies = TradingStrategies.StockTrending;
                    //entry.action = OrderAction.ShortSell;
                    //entry.type = FIXApi.OrderType.CreditMarginSell;
                    entry.action         = OrderAction.Sell;
                    entry.type           = FIXApi.OrderType.CashSell;
                    entry.ticker         = ticker;
                    entry.quantityListed = sd.Quantity;
                    //entry.quantityListed = 0;//没有必要输入Quantity, 完全依赖锁券和预先锁券
                    //if (bTestEngine)
                    //    entry.priceListed = sd.AskPrices[5];//测试,按卖五挂单
                    //else
                    //    entry.priceListed = sd.AskPrices[0];//按卖一挂单
                    entry.priceListed = sd.BidPrices[4];                    //按卖五挂单,等同市价
                    entry.orderTime   = sd.zbDataList[lastIndex].timeStamp; //SellTime
                    entry.orderDate   = sd.DateStamp;

                    sd.StatusTrending = StrategyStatus.Pending; //获得成交回报后再改变状态,避免重复执行

                    OrderRouter(entry);
                }
            }
        }