Exemple #1
0
        public void ShortSellTest()
        {
            //OrderList = new Dictionary<string, int>();
            //OrderList.Add("000768", 1000);
            //OrderList.Add("600893", 600);
            //OrderList.Add("300070", 1200);
            //OrderList.Add("300024", 1000);
            //OrderList.Add("300124", 700);
            //OrderList.Add("300058", 800);
            //OrderList.Add("300002", 1000);
            //OrderList.Add("300003", 800);

            if (OrderList == null)
            {
                return;
            }

            foreach (KeyValuePair <string, int> kvp in OrderList)
            {
                try
                {
                    SingleStockData sd = dataDict[kvp.Key];

                    FIXApi.OrderBookEntry entry = new OrderBookEntry();
                    entry.strategies     = TradingStrategies.StockTrending;
                    entry.action         = OrderAction.ShortSell;
                    entry.type           = FIXApi.OrderType.CreditMarginSell;
                    entry.ticker         = kvp.Key;
                    entry.quantityListed = kvp.Value;

                    int tCount = 0;
                    while (sd.AskPrices[0] == 0)
                    {
                        tCount++;
                        Thread.Sleep(100);
                        if (tCount > 100)
                        {
                            break;
                        }
                    }

                    if (sd.AskPrices[0] == 0)
                    {
                        continue;
                    }

                    entry.priceListed = sd.AskPrices[0];

                    Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_StockTrending));
                    orderThread.IsBackground = true;
                    orderThread.Start(entry);
                }
                catch (Exception ex)
                {
                    strListLog.Add(ex.Message);
                }
            }
        }
Exemple #2
0
        public void PrevLockAll()
        {
            foreach (string ticker in dc.TickerList)
            {
                SingleStockData sd = dataDict[ticker];

                FIXApi.OrderBookEntry entry = new OrderBookEntry();
                entry.strategies     = TradingStrategies.StockTrending;
                entry.action         = OrderAction.PrevLock;
                entry.type           = FIXApi.OrderType.CreditMarginSell;
                entry.ticker         = ticker;
                entry.quantityListed = sd.Quantity;

                entry.priceListed = Math.Round(sd.PrevClose * 1.098, 2);

                //entry.orderTime = sd.BuyTime;
                //entry.orderDate = sd.DateStamp;
                Thread orderThread = new Thread(new ParameterizedThreadStart(tc.OrderSender_StockTrending));
                orderThread.IsBackground = true;
                orderThread.Start(entry);
                Thread.Sleep(1000); //避免堵塞
            }
        }
Exemple #3
0
        //重载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;
                    }
                }
            }
Exemple #4
0
        //此版本为高频策略使用

        /*
         * public string LoadDataDict()
         * {
         *  string ticker = "", tickerWithMarket = "", tickerListStr = "";
         *
         *  SqlConnection conn = new SqlConnection(connStr);
         *
         *  //string sql = "select Ticker, ShortQuantity, prevClose, Volume from v_Ticker_Trending where prevClose>0 and volume>0 and shortquantity*prevClose>20000 Order by ticker";
         *  //string sql = "select Ticker, ShortQuantity, prevClose, Volume from v_Ticker_Trending where prevClose>0 and volume>0 and shortquantity*prevClose>2000 Order by ticker";//DEBUG
         *  //string sql = "select Ticker, QuantityHolding, prevClose, PrevVolume from v_Ticker_Trending where ticker='600316' Order by ticker"; //测试用
         *  string sql = "select Ticker, Quantity, prevClose, PrevVolume from TickerList_HighFreq Order by ticker";
         *
         *  conn.Open();
         *  SqlCommand cmd = new SqlCommand(sql, conn);
         *  SqlDataReader sqldr = cmd.ExecuteReader();
         *
         *  int count = 0;
         *  while (sqldr.Read())
         *  {
         *      ticker = sqldr.GetString(0);
         *      ticker = ticker.Trim();
         *
         *      if (ticker.StartsWith("60") || ticker.StartsWith("51"))
         *      {
         *          tickerWithMarket = ticker + ".sh";   // 上海
         *      }
         *      else if (ticker.StartsWith("00") || ticker.StartsWith("30") || ticker.StartsWith("15"))
         *      {
         *          tickerWithMarket = ticker + ".sz";    // 深圳
         *      }
         *
         *
         *      TickerList.Add(ticker);
         *      tickerListStr = tickerListStr + ";" + tickerWithMarket;
         *
         *      SingleStockData sd = new SingleStockData(ticker);
         *
         *      sd.MaxQuantity = Convert.ToInt32(sqldr.GetInt32(1));
         *
         *      sd.PrevClose = Convert.ToDouble(sqldr.GetDouble(2));
         *      sd.PrevVolume = Convert.ToInt64(sqldr.GetInt64(3));
         *
         *      sd.Quantity = 100; //DEBUG
         *
         *      sd.StatusTrending = StrategyStatus.New;
         *
         *      dataDict.Add(ticker, sd);
         *  }
         *
         *  return tickerListStr;
         * }
         */

        //此版本为分级基金套利使用

        public string LoadDataDict()
        {
            string ticker = "", tickerWithMarket = "", tickerListStr = "";

            connStr = "server=192.168.0.169,1433;database=HedgeHogDB;User ID=wg;Password=Pass@word;Connection Timeout=30";
            SqlConnection conn = new SqlConnection(connStr);

            if (intDate == 0)
            {
                intDate = Convert.ToInt32(DateTime.Today.ToString("yyyyMMdd"));
            }
            string sql = "select Ticker, Quantity, prevClose, PrevVolume from v_HFT_PrevCloseData  where NowDate =" + intDate.ToString() + " and prevvolume>0 Order by ticker";//融券卖空用

            // string sql = "select top 100 Ticker, Quantity, prevClose, PrevVolume from v_HFT_PrevCloseData  where NowDate =" + intDate.ToString() + "  and ticker='000933' and prevvolume>0 Order by ticker";//融券卖空用


            conn.Open();
            SqlCommand    cmd   = new SqlCommand(sql, conn);
            SqlDataReader sqldr = cmd.ExecuteReader();

            while (sqldr.Read())
            {
                ticker = sqldr.GetString(0);
                ticker = ticker.Trim();

                if (ticker.StartsWith("60") || ticker.StartsWith("51"))
                {
                    tickerWithMarket = ticker + ".sh";   // 上海
                }
                else if (ticker.StartsWith("00") || ticker.StartsWith("30") || ticker.StartsWith("15"))
                {
                    tickerWithMarket = ticker + ".sz";    // 深圳
                }

                if (!TickerList.Contains(ticker))
                {
                    TickerList.Add(ticker);
                    tickerListStr = tickerListStr + ";" + tickerWithMarket;
                }

                SingleStockData sd = new SingleStockData(ticker);

                sd.MaxQuantity = Convert.ToInt32(sqldr.GetInt32(1));

                sd.PrevClose  = Convert.ToDouble(sqldr.GetDouble(2));
                sd.PrevVolume = Convert.ToInt64(sqldr.GetInt64(3));

                sd.Quantity = sd.MaxQuantity;
                //sd.Quantity = 100;

                sd.StatusTrending = StrategyStatus.New;
                sd.StatusReverse  = StrategyStatus.New;

                sd.DateStamp = intDate;

                if (!dataDict.ContainsKey(ticker))
                {
                    dataDict.Add(ticker, sd);
                }
            }

            return(tickerListStr);
        }
Exemple #5
0
        private void comboBoxIfArb_SelectedIndexChanged(object sender, EventArgs e)
        {
            string account = "";

            //单一账户对应的position,也可以写成将多个账户汇总
            if (checkBoxGuosenHedge1.Checked)
            {
                account = "dj1";
            }
            else if (checkBoxCiccSeed1.Checked)
            {
                account = "zj1";
            }
            else if (checkBoxCiccSeed2.Checked)
            {
                account = "zj2";
            }
            else if (checkBoxHY.Checked)
            {
                account = "hy1";
            }
            else
            { //MessageBox.Show("请选择账户!");
                return;
            }


            dtPosition = new DataTable();
            if ((!radioButtonSell.Checked) && (!radioButtonBuy.Checked))
            {
                //MessageBox.Show("请选择买或者卖");
                return;
            }



            string Strategy = Convert.ToString(comboBoxIfArb.Text);

            if (string.IsNullOrEmpty(Strategy))
            {
                //MessageBox.Show("Please Select Index!");
                return;
            }

            //买时从basketlist读取
            if (radioButtonBuy.Checked)
            {
                string         sql = "select * from v_arbitrage where Strategy='" + Strategy + "'";
                SqlDataAdapter SDA = new SqlDataAdapter("select * from v_arbitrage where Strategy='" + Strategy + "'", MF.conn);
                SDA.Fill(dtPosition);
                //dtPosition中会包含数量为0的股票,下单注意剔除
                //第一列为Strategy,第二列为Ticker,第三列为Position,
                dtPosition.Columns.Add("Account");
                for (int i = 0; i < dtPosition.Rows.Count; i++)
                {
                    dtPosition.Rows[i]["Account"] = account;
                }


                double   capital  = 0;
                string[] strvalue = Strategy.Split('_');
                string   sql1     = "select SUM(Position*Price_Close) from (select A.Ticker,Position,TotalAHist.Price_Close from (select * from BasketList where SubStrategy1='" + strvalue[1] + "' and SubStrategy2='" + strvalue[2] + "') A " +
                                    "left join TotalAHist on A.Ticker=TotalAHist.Ticker and A.HistDate=TotalAHist.HistDate) C";

                SqlCommand    cmd = new SqlCommand(sql1, MF.conn);
                SqlDataReader sdr = cmd.ExecuteReader();
                while (sdr.Read())
                {
                    if (sdr.IsDBNull(0))
                    {
                        capital = 0;
                    }
                    else
                    {
                        capital = sdr.GetDouble(0);
                    }
                }
                sdr.Close();
                textBoxCiccLog2.Text = "篮子总市值为:" + capital;
            }
            //卖时从Inventory读取
            else
            {
                //每次卖时需要根据当日成交回报更新Inventory,
                //tc.OrderBookUpdate(conn);
                //PositionUpdate();

                int weight = GetWeight(MF.conn, account, Strategy);

                //每篮子对应个股持仓数
                string         sql = "select Strategy + '_' + SubStrategy1 + '_' + SubStrategy2 as Strategy,Ticker,(PrePosition+TodayBuy-TodaySell) as Position,Account from Inventory where Strategy + '_' + SubStrategy1 + '_' + SubStrategy2='" + Strategy + "' and account='" + account + "'";
                SqlDataAdapter SDA = new SqlDataAdapter(sql, MF.conn);
                SDA.Fill(dtPosition);
                for (int i = 0; i < dtPosition.Rows.Count; i++)
                {
                    DataRow dr = dtPosition.Rows[i];
                    if (weight > 0)
                    {
                        dr["Position"] = Math.Round(Convert.ToDouble(dr["Position"]) / weight / 100) * 100;
                    }
                }

                //计算篮子市值
                double   capital  = 0;
                string[] strvalue = Strategy.Split('_');
                string   subsql   = "";

                if (weight == 0)
                {
                    subsql = "select SUM(Position*Price_Close)";
                }
                else
                {
                    subsql = "select SUM(floor(Position/(" + weight + "*100))*100*Price_Close)";
                }
                string sql1 = subsql + " from (select A.Position,B.Price_Close from (select Ticker,PrePosition as Position,Account from Inventory where Strategy + '_' + SubStrategy1 + '_' + SubStrategy2='" + Strategy + "' and account='" + account + "') A " +
                              " left join" +
                              "(select * from TotalAHist where HistDate= (select MAX(HistDate) from TotalAHist)) B on A.Ticker=B.Ticker) C";

                SqlCommand    cmd = new SqlCommand(sql1, MF.conn);
                SqlDataReader sdr = cmd.ExecuteReader();
                while (sdr.Read())
                {
                    if (sdr.IsDBNull(0))
                    {
                        capital = 0;
                    }
                    else
                    {
                        capital = sdr.GetDouble(0);
                    }
                }
                sdr.Close();
                textBoxCiccLog2.Text = "篮子总市值为:" + capital;
            }

            //订阅行情
            string TickerList = "";
            string ticker = "", tickerWithMarket = "", tickerListStr = "";

            for (int i = 0; i < dtPosition.Rows.Count; i++)
            {
                DataRow dr = dtPosition.Rows[i];
                ticker = Convert.ToString(dr["Ticker"]);
                ticker = ticker.Trim();

                if (ticker.StartsWith("60") || ticker.StartsWith("51"))
                {
                    tickerWithMarket = ticker + ".sh";   // 上海
                }
                else if (ticker.StartsWith("00") || ticker.StartsWith("30") || ticker.StartsWith("15"))
                {
                    tickerWithMarket = ticker + ".sz";    // 深圳
                }

                if (!TickerList.Contains(ticker))
                {
                    tickerListStr = tickerListStr + ";" + tickerWithMarket;
                }

                SingleStockData sd = new SingleStockData(ticker);
                sd.StatusTrending = StrategyStatus.New;
                sd.StatusReverse  = StrategyStatus.New;

                if (!dataDict.ContainsKey(ticker))
                {
                    dataDict.Add(ticker, sd);
                }
            }
            dc.SetSubscription(tickerListStr, SubscriptionType.SUBSCRIPTION_ADD);
            //将行情输入dtPosition
            dtPosition.Columns.Add("OrderPrice");
            //刷新datagridview
            System.Timers.Timer t = new System.Timers.Timer(5000);       //实例化Timer类,设置间隔时间为5000毫秒;
            t.Elapsed  += new System.Timers.ElapsedEventHandler(theout); //到达时间的时候执行事件;
            t.AutoReset = true;                                          //设置是执行一次(false)还是一直执行(true);
            t.Enabled   = true;

            G_position.DataSource = dtPosition;
        }
Exemple #6
0
        public void RunReverseStrategy()
        {
            //实时是第一层每秒重新计算一次,第二层对每只股票代码循环,每只股票此时只需计算一次
            //PrevLockAll();

            bRunning = true;
            while (bRunning)
            {
                foreach (string ticker in dc.TickerList)  //注意不能直接对dict用foreach,否则任何修改都会抛出异常
                {
                    lock (this.dataDict)
                    {
                        if (!dataDict.Keys.Contains(ticker))
                        {
                            continue;
                        }

                        SingleStockData sd = dataDict[ticker];

                        if (sd.StatusReverse == StrategyStatus.None)
                        {
                            continue;                                          //该股票已交易过,当日只交易一次
                        }
                        if (((sd.ZBFirstIndex) < 0) || ((sd.ZBLastIndex) < 0))
                        {
                            continue;
                        }

                        if (sd.zbDataList[sd.ZBLastIndex].timeStamp < 93000)
                        {
                            continue;
                        }

                        if (sd.zbDataList[sd.ZBLastIndex].timeStamp > 145900)
                        {
                            bRunning = false;
                            break;
                        }

                        int tDiff = ComputeIntTimeDiff(sd.zbDataList[sd.ZBFirstIndex].timeStamp, sd.zbDataList[sd.ZBLastIndex].timeStamp);

                        int obsTime = bTestEngine?2:600;

                        if ((sd.ZBFirstIndex == 0) && tDiff < obsTime)
                        {
                            continue;                                                                                                       //已读取数据长度不满2分钟 DEBUG
                        }
                        while (ComputeIntTimeDiff(sd.zbDataList[sd.ZBFirstIndex].timeStamp, sd.zbDataList[sd.ZBLastIndex].timeStamp) > 120) //保持内存中时间序列长度在2分钟左右
                        {
                            sd.zbDataList.RemoveAt(sd.ZBFirstIndex);
                            sd.ZBLastIndex = sd.ZBLastIndex - 1;

                            //sd.ZBFirstIndex++;
                        }
                        ComputeOneTick(ticker, sd.ZBFirstIndex, sd.ZBLastIndex);
                    }
                }

                if (tc.mode == TradeMode.Debug)
                {
                    Thread.Sleep(10); //每秒计算一次
                }
                else if (tc.mode == TradeMode.Production)
                {
                    Thread.Sleep(1000); //每秒计算一次
                }
            }
        }
Exemple #7
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);
                }
            }
        }
Exemple #8
0
        public void Run()
        {
            bTestEngine = false;

            int tLength = 60;                  //只使用过去一分钟数据

            if (tc.mode == TradeMode.Backtest) //回测模式包括TDF和数据库两种回测
            {
                //回测时是第一层对每只股票代码循环,第二层对每只股票的日期做循环,第三层对每只股票的时间序列循环
                foreach (string ticker in dc.TickerList)
                {
                    if (!dataDict.Keys.Contains(ticker))
                    {
                        continue;
                    }

                    SingleStockData sd = dataDict[ticker];

                    //if (sd.zbDataList.Count < 2000) continue;

                    int iStart = 0, iEnd;
                    for (iEnd = 1; iEnd < sd.zbDataList.Count; iEnd++)
                    {
                        sd.totalVolTillNow += sd.zbDataList[iEnd].volume;
                        int timeTillNow = ComputeIntTimeDiff(sd.zbDataList[0].timeStamp, sd.zbDataList[iEnd].timeStamp);
                        sd.avgVolTillNow = (double)sd.totalVolTillNow / (double)timeTillNow;

                        if (sd.zbDataList[iEnd].timeStamp < 94500)
                        {
                            continue;
                        }

                        if (timeTillNow < tLength)
                        {
                            continue;
                        }
                        while (ComputeIntTimeDiff(sd.zbDataList[iStart].timeStamp, sd.zbDataList[iEnd].timeStamp) > tLength) //保持内存中时间序列长度固定
                        {
                            iStart++;
                        }

                        if (sd.StatusTrending == StrategyStatus.None)
                        {
                            continue;                                           //该股票已交易过,当日只交易一次
                        }
                        ComputeOneTick(ticker, iStart, iEnd);
                    }
                }
            }
            else
            {
                //实时时是第一层每秒重新计算一次,第二层对每只股票代码循环,每只股票此时只需计算一次

                //PrevLockAll();

                bRunning = true;

                while (bRunning)
                {
                    int timeStamp = 0;
                    foreach (string ticker in dc.TickerList)  //注意不能直接对dict用foreach,否则任何修改都会抛出异常
                    {
                        lock (this.dataDict)
                        {
                            if (!dataDict.Keys.Contains(ticker))
                            {
                                continue;
                            }

                            SingleStockData sd = dataDict[ticker];

                            if (sd.StatusTrending == StrategyStatus.None)
                            {
                                continue;                                           //该股票已交易过,当日只交易一次
                            }
                            if (((sd.ZBFirstIndex) < 0) || ((sd.ZBLastIndex) < 0))
                            {
                                continue;
                            }

                            timeStamp = sd.zbDataList[sd.ZBLastIndex].timeStamp;

                            if (timeStamp > sd.prevTimeStamp)
                            {
                                sd.prevTimeStamp = timeStamp;
                            }
                            else
                            {
                                continue;  //时间尚未更新,无需后续计算
                            }
                            if (timeStamp < 93130)
                            {
                                continue;                    //盘前30秒的数据暂不使用
                            }
                            int tDiff = ComputeIntTimeDiff(sd.zbDataList[sd.ZBFirstIndex].timeStamp, sd.zbDataList[sd.ZBLastIndex].timeStamp);

                            int timeTillNow = ComputeIntTimeDiff(93000, sd.zbDataList[sd.ZBLastIndex].timeStamp);


                            sd.avgVolTillNow = (double)sd.totalVolTillNow / (double)timeTillNow;

                            if (bTestEngine)
                            {
                                if ((sd.ZBFirstIndex == 0) && tDiff < 2)
                                {
                                    continue;
                                }
                            }                                                      //已读取数据长度不满2分钟
                            else
                            {
                                if ((sd.ZBFirstIndex == 0) && tDiff < tLength)
                                {
                                    continue;
                                }
                            }                                                           //已读取数据长度不满2分钟 DEBUG

                            if (sd.zbDataList[sd.ZBLastIndex].timeStamp < 93500)
                            {
                                continue;
                            }

                            while (ComputeIntTimeDiff(sd.zbDataList[sd.ZBFirstIndex].timeStamp, sd.zbDataList[sd.ZBLastIndex].timeStamp) > tLength) //保持内存中时间序列长度固定
                            {
                                if (sd.zbDataList.Count < 30)
                                {
                                    break;                          //交易不活跃,距离太短,保留至少30个tick
                                }
                                if ((sd.zbDataList[sd.ZBFirstIndex].timeStamp > 93500) && ((sd.ZBLastIndex - sd.ZBFirstIndex) > tLength))
                                {
                                    ComputeOneTick(ticker, sd.ZBFirstIndex, sd.ZBFirstIndex + tLength - 1); //以秒为tick单位,以后需修改
                                }
                                sd.zbDataList.RemoveAt(sd.ZBFirstIndex);
                                sd.ZBLastIndex = sd.ZBLastIndex - 1;


                                //sd.ZBFirstIndex++;
                            }


                            ComputeOneTick(ticker, sd.ZBFirstIndex, sd.ZBLastIndex);
                        }
                    }
                    if (tc.mode == TradeMode.Debug)
                    {
                        Thread.Sleep(10); //每秒计算一次
                    }
                    else if (tc.mode == TradeMode.Production)
                    {
                        Thread.Sleep(500); //每秒计算一次
                    }
                    if (timeStamp > 145900)
                    {
                        break;
                    }
                }
            }

            dc.WriteToDatabase(tc.dt_PnL);
            WriteLog(this, null);
        }