private StockTickTransaction onTick(int seconds, List <StockTickTransaction> data)
        {
            StockTickTransaction tick = new StockTickTransaction();
            int secondsIndex          = DataTimeStampExtension.GetStockSecondsIndex(data[0].TransactionDateTime);

            for (int i = 0; i < data.Count(); i++)
            {
                secondsIndex = DataTimeStampExtension.GetStockSecondsIndex(data[i].TransactionDateTime);
                if (secondsIndex <= seconds)
                {
                    tick = data[i];
                }
                else
                {
                    break;
                }
            }
            return(tick);
        }
Пример #2
0
        public void computeImbalanceInfactor(DateTime startDate, DateTime endDate)
        {
            var tradedays = dateRepo.GetStockTransactionDate(startDate, endDate);

            foreach (var date in tradedays)
            {
                double[] imbalanceInfactor = new double[28802];
                double[] priceChange       = new double[28802];
                var      stockData         = stockRepo.GetStockTransaction(code, date, date.AddHours(17));
                var      stock             = DataTimeStampExtension.ModifyStockTickData(stockData);
                for (int i = 0; i < 28802; i++)
                {
                    if (stock[i] != null)
                    {
                        imbalanceInfactor[i] = stock[i].BidV1 / (stock[i].AskV1 + stock[i].BidV1);
                    }
                    if (i < 28801 && stock[i] != null && stock[i + 1] != null)
                    {
                        priceChange[i] = Math.Round(stock[i + 1].Bid1 - stock[i].Bid1, 4);
                    }
                }
                double total = 0;
                double right = 0;
                for (int i = 0; i < 28802; i++)
                {
                    //if (priceChange[i]!=0 && Math.Abs(imbalanceInfactor[i]-0.5)>=0)
                    {
                        total += 1;
                        if (priceChange[i] > 0 && imbalanceInfactor[i] > 0.75)
                        {
                            right += 1;
                        }
                        if (priceChange[i] < 0 && imbalanceInfactor[i] < 0.25)
                        {
                            right += 1;
                        }
                    }
                }
                Console.WriteLine(Math.Round(right / total, 3));
            }
        }
        public void computeTWAP(DateTime startDate, DateTime endDate, int totalVolume = 10000000, int newOrderTimeInterval = 15, int oldOrderTimeInterval = 15, int oldOrderFrequency = 10, int newOrderPriceMode = -1, int oldOrderPriceMode = -1, int cancelTimeInterval = 120)
        {
            var tradedays = dateRepo.GetStockTransactionDate(startDate, endDate);

            foreach (var date in tradedays)
            {
                List <StockTickTransaction> data = new List <StockTickTransaction>();
                try
                {
                    data = stockRepo.GetStockTransaction(code, date, date);
                }
                catch (Exception)
                {
                    Console.WriteLine("code:{0},date:{1} No Data!!", code, date);
                }
                if (data.Count() == 0)
                {
                    Console.WriteLine("code:{0},date:{1} No Data!!", code, date);
                    continue;
                }
                double           vol        = getVolatilityMinutly(code, date, 10);
                double           mean       = 0;
                double           marketMean = 0;
                int              seconds    = 0;
                int              dataIndex  = 0;
                int              dataSeconds;
                int              untradeVolume = totalVolume;
                List <OrderBook> orderBook     = new List <OrderBook>();
                List <TradeBook> tradeBook     = new List <TradeBook>();
                //初始化每个周期的挂单量和补单量
                int    period = totalTime / newOrderTimeInterval;
                int    orderVolumePerTimeInterval      = getVolumeOfTimeInterval(untradeVolume, period);
                int    stockNeedToTradePerTimeInterval = untradeVolume / period;
                int    oldOrderVolumePerTimeInterval   = 0;
                int    orderNeedToTrade  = 0;
                int    orderAlreadyTrade = 0;
                int    counting          = 0;
                double lastNewOrderPrice = 0;
                //逐秒进行判断成交以及策略挂单
                for (seconds = 0; seconds <= 14221; seconds++)
                {
                    DateTime time = date.Date + DataTimeStampExtension.GetStockSecondsTimeByIndex(seconds);
                    //获取市场数据部分
                    var lastTick = onTick(seconds, data);
                    if (lastTick.Bid1 == 0)
                    {
                        continue;
                    }
                    counting  += 1;
                    marketMean = (marketMean * (counting - 1) + lastTick.LastPrice) / counting;//计算市场的平均价格
                    //根据最新盘口数据调整orderbook中waitingValume字段
                    modifyOrderBookByTickData(ref orderBook, lastTick);
                    //策略挂单撤单部分
                    double newOrderPrice = getOrderPrice(newOrderPriceMode, lastTick);
                    double oldOrderPrice = getOrderPrice(oldOrderPriceMode, lastTick);
                    if (counting % newOrderTimeInterval == 1)//每个新挂单周期的第1秒进行挂单
                    {
                        orderNeedToTrade = orderNeedToTrade + stockNeedToTradePerTimeInterval;
                        if (orderVolumePerTimeInterval > 0)
                        {
                            orderId += 1;
                            double price = getOrderPrice(newOrderPriceMode, lastTick);
                            placeAnOrder(ref orderBook, lastTick, price, time, orderVolumePerTimeInterval, orderId);
                            lastNewOrderPrice = price;
                        }
                        //如果价格跳涨,单位时间内多挂1倍的单
                        if (lastNewOrderPrice > 0 && (lastTick.Ask1 / lastNewOrderPrice - 1) > 1 * vol * Math.Sqrt(newOrderTimeInterval / 60.0))
                        {
                            orderId += 1;
                            placeAnOrder(ref orderBook, lastTick, lastTick.Ask1, time, orderVolumePerTimeInterval, orderId);
                            lastNewOrderPrice = lastTick.Ask1;
                        }
                    }

                    if (counting % oldOrderTimeInterval == 5)//每个补单周期的第5秒进行补单
                    {
                        int activeOrderNumbers = getActivieOrderNumbers(orderBook);
                        int volumeNow          = (int)(Math.Round((orderNeedToTrade - orderAlreadyTrade - activeOrderNumbers) / 100.0) * 100);
                        volumeNow = Math.Min(oldOrderVolumePerTimeInterval, volumeNow);
                        if (volumeNow > 0)
                        {
                            orderId += 1;
                            double price = getOrderPrice(oldOrderPriceMode, lastTick);
                            placeAnOrder(ref orderBook, lastTick, price, time, volumeNow, orderId);
                        }
                    }


                    if (counting % cancelTimeInterval == 0) //每个撤单周期进行撤单,并计算需要补挂的单子
                    {
                        int activeOrderNumbers = getActivieOrderNumbers(orderBook);
                        cancelDeviateOrders(ref orderBook, lastTick);
                        if (orderAlreadyTrade / Convert.ToDouble(orderNeedToTrade) < tradingRate)
                        {
                            cancelPartialDeviateOrders(ref orderBook, lastTick);
                            activeOrderNumbers = getActivieOrderNumbers(orderBook);
                        }
                        //计算后续补单每次挂单量
                        int oldOrderUntrade = orderNeedToTrade - orderAlreadyTrade - activeOrderNumbers;
                        oldOrderVolumePerTimeInterval = getVolumeOfTimeInterval(oldOrderUntrade, oldOrderFrequency);
                    }
                    //判断成交部分
                    dataSeconds = DataTimeStampExtension.GetStockSecondsIndex(data[dataIndex].TransactionDateTime);
                    if (dataSeconds == seconds)
                    {
                        //根据该tick的盘口数据,进行成交判断
                        transactionSimulation(ref orderBook, ref tradeBook, data[dataIndex]);
                        //根据成交信息更新数据
                        orderAlreadyTrade = getTradedNumbers(tradeBook);
                        untradeVolume     = totalVolume - orderAlreadyTrade;
                        //移到下一个tick的数据
                        if (dataIndex + 1 < data.Count())
                        {
                            dataIndex = dataIndex + 1;
                        }
                    }
                    //输出最后的交易情况
                    if (seconds == 14220)
                    {
                        mean = getTradeAveragePrice(tradeBook);
                        int orderVolume = getOrderBookVolume(orderBook);
                        Console.WriteLine("{0}: 市场均价 {1} 成交均价 {2} 成交量 {3} 需成交 {4} 挂单 {5}", time, marketMean, mean, orderAlreadyTrade, orderNeedToTrade, orderVolume);
                    }
                }
            }
        }
Пример #4
0
        public void compute(DateTime startDate, DateTime endDate)
        {
            var tradedays = dateRepo.GetStockTransactionDate(startDate, endDate);
            List <ETFConsitituent> etfInfo    = new List <ETFConsitituent>();
            List <double>          amountList = getAmount(code, startDate, endDate);

            double[] arbitraryPurchase = new double[28802];
            double[] arbitraryRedeem   = new double[28802];
            bool[]   isNan             = new bool[28802];
            for (int i = 0; i < 28802; i++)
            {
                isNan[i] = true;
            }
            for (int k = 0; k < tradedays.Count(); k++)
            {
                DateTime date = tradedays[k];
                etfInfo = getETFInfo(code, date);
                foreach (var item in etfInfo)
                {
                    if (item.cash_substitution_mark == "必须")
                    {
                        for (int i = 0; i < 28802; i++)
                        {
                            if (isNan[i] == true)
                            {
                                arbitraryPurchase[i] += -item.substitution_amout;
                            }
                        }
                    }
                    else
                    {
                        var stockData = stockRepo.GetStockTransaction(item.code, date, date.AddHours(17));
                        if (stockData != null && stockData.Count > 0)
                        {
                            var stock = DataTimeStampExtension.ModifyStockTickData(stockData);
                            for (int i = 0; i < stock.Count(); i++)
                            {
                                if (isNan[i] == true && stock[i] != null && stock[i].AskV1 != 0 && stock[i].BidV1 != 0)
                                {
                                    arbitraryPurchase[i] += -item.volume * stock[i].Ask1;
                                    //arbitraryRedeem[i] += item.volume * stock[i].Bid1;
                                }
                                if (stock[i] == null)
                                {
                                    isNan[i]             = false;
                                    arbitraryPurchase[i] = 0;
                                    //arbitraryRedeem[i] = 0;
                                }
                            }
                        }
                        else
                        {
                            if (item.cash_substitution_mark == "禁止")
                            {
                                for (int i = 0; i < 28802; i++)
                                {
                                    arbitraryPurchase[i] = 0;
                                    isNan[i]             = false;
                                }
                            }
                            else
                            {
                                var stock = stockDailyRepo.GetStockTransaction(item.code, date, date);
                                for (int i = 0; i < 28802; i++)
                                {
                                    if (isNan[i] == true)
                                    {
                                        arbitraryPurchase[i] += -item.volume * stock[stock.Count() - 1].Close * (1 + item.premium_ratio / 100.0);
                                    }
                                }
                            }
                        }
                    }
                }
                var etf = DataTimeStampExtension.ModifyStockTickData(stockRepo.GetStockTransaction(code, date, date.AddHours(17)));
                for (int i = 0; i < etf.Count(); i++)
                {
                    if (isNan[i] == true && etf[i] != null && etf[i].AskV1 != 0 && etf[i].BidV1 != 0)
                    {
                        arbitraryPurchase[i] += amountList[k] * etf[i].Bid1;
                        // arbitraryRedeem[i] += -amountList[k] * etf[i].Ask1;
                    }
                    if (etf[i] == null)
                    {
                        isNan[i]             = false;
                        arbitraryPurchase[i] = 0;
                        //arbitraryRedeem[i] = 0;
                    }
                }
                Console.WriteLine("today {0} change {1}", date, arbitraryPurchase.Max());
            }
        }
Пример #5
0
        private List <StockTransaction> tranferTickToMinuteDayByDay(string code, DateTime date, double openData, List <StockTickTransaction> tickData)
        {
            List <StockTransaction> minuteList = new List <StockTransaction>();

            //构造时间间隔的左闭右开区间利用9点30分的分钟线包含时间[9:30:00,9:31:00)
            List <Interval> timeList = new List <Interval>();

            for (int index = 0; index < 240; index++)
            {
                TimeSpan startTime = DataTimeStampExtension.GetStockMinuteTimeByIndex(index);
                TimeSpan endTime   = startTime.Add(new TimeSpan(0, 0, 60));
                if (index == 119 || index == 239)
                {
                    endTime = startTime.Add(new TimeSpan(0, 0, 61));
                }
                Interval interval = new Interval(startTime, endTime, new TimeSpan(0, 0, 60));
                timeList.Add(interval);
            }
            double high        = openData;
            double open        = openData;
            double low         = openData;
            double close       = openData;
            double amount      = 0;
            double volume      = 0;
            double startAmount = 0;
            double endAmount   = 0;
            double startVolume = 0;
            double endVolume   = 0;

            foreach (var item in timeList)
            {
                int num = 0;
                for (int i = 0; i < tickData.Count(); i++)
                {
                    if (tickData[i].TransactionDateTime.TimeOfDay >= item.Begin && tickData[i].TransactionDateTime.TimeOfDay < item.End)
                    {
                        num       = num + 1;
                        endAmount = tickData[i].Amount;
                        endVolume = tickData[i].Volume;
                        close     = tickData[i].LastPrice;
                        if (num == 1)
                        {
                            open = tickData[i].LastPrice;
                            high = open;
                            low  = open;
                        }
                        if (tickData[i].LastPrice > high)
                        {
                            high = tickData[i].LastPrice;
                        }
                        if (tickData[i].LastPrice < low)
                        {
                            low = tickData[i].LastPrice;
                        }
                    }
                }
                if (num == 0) //这一分钟没有成交
                {
                    amount = 0;
                    volume = 0;
                    open   = close;
                    high   = close;
                    low    = close;
                }
                else
                {
                    amount      = endAmount - startAmount;
                    volume      = endVolume - startVolume;
                    startAmount = endAmount;
                    startVolume = endVolume;
                }
                StockTransaction kLines = new StockTransaction();
                kLines.Open     = open;
                kLines.High     = high;
                kLines.Low      = low;
                kLines.Close    = close;
                kLines.Amount   = amount;
                kLines.Volume   = volume;
                kLines.Code     = code;
                kLines.DateTime = date.Date + item.Begin;
                kLines.Level    = StockTransactionLevel.Minute;
                minuteList.Add(kLines);
                open = close;
                high = close;
                low  = close;
            }
            return(minuteList);
        }
Пример #6
0
        private void BulkLoadStockMinuteToSqlFromSource(string code, DateTime currentTime)
        {
            IdentifyOrCreateDBAndTable(currentTime);
            var latestTime = GetLatestTimeFromSql(code, currentTime);

            latestTime = latestTime == default(DateTime) ? new DateTime(currentTime.Year, currentTime.Month, 1) : latestTime.AddMinutes(1);
            if (latestTime.TimeOfDay >= new TimeSpan(14, 59, 00))
            {
                latestTime = latestTime.Date.AddDays(1);
            }
            var endTime = GetEndTime(currentTime);

            if (latestTime < endTime)
            {
                var dataTable = tickRepo.GetStockTransaction(code, latestTime, endTime);
                var days      = dateTimeRepo.GetStockTransactionDate(latestTime.Date, endTime.Date);
                var timelist  = DataTimeStampExtension.GetStockMinuteTimeList();
                List <StockMinuteTransaction> minuteAll = new List <StockMinuteTransaction>();
                foreach (var day in days)
                {
                    //Console.WriteLine("date:{0} start!!", day);
                    List <StockMinuteTransaction> minuteNow = new List <StockMinuteTransaction>();
                    var dtToday = (from data in dataTable where data.TransactionDateTime.Date == day.Date select data).ToList();
                    if (dtToday[dtToday.Count() - 1].Volume <= 0)
                    {
                        continue;
                    }
                    if (dtToday.Count() != 0)
                    {
                        //处理开盘前的价格和成交量
                        double totalVolume = 0;
                        double totalAmount = 0;
                        double high        = 0;
                        double low         = 0;
                        double close       = 0;
                        double open        = 0;
                        var    preOpen     = (from data in dtToday where (data.TransactionDateTime.TimeOfDay < timelist[0]) select data).ToList();
                        if (preOpen.Count != 0)
                        {
                            var last = preOpen[preOpen.Count() - 1];
                            totalVolume = last.Volume;
                            totalAmount = last.Amount;
                            close       = last.LastPrice;
                            open        = close;
                            high        = close;
                            low         = close;
                        }

                        for (int i = 0; i < timelist.Count() - 1; i++)
                        {
                            var dtNow = (from data in dtToday where (data.TransactionDateTime.TimeOfDay >= timelist[i]) && (data.TransactionDateTime.TimeOfDay <= timelist[i + 1]) select data).ToList();
                            if (dtNow.Count() != 0)
                            {
                                high = dtNow.Max(x => x.LastPrice);
                                low  = dtNow.Min(x => x.LastPrice);
                                var listNow   = dtNow.ToList();
                                var startData = listNow[0];
                                var endData   = listNow[listNow.Count() - 1];
                                open  = startData.LastPrice;
                                close = endData.LastPrice;
                                double volumeNew = endData.Volume;
                                double amountNew = endData.Amount;
                                double volume    = volumeNew - totalVolume;
                                double amount    = amountNew - totalAmount;
                                totalAmount = amountNew;
                                totalVolume = volumeNew;
                                StockMinuteTransaction KLine = new StockMinuteTransaction();
                                KLine.Amount   = amount;
                                KLine.Volume   = volume;
                                KLine.Open     = open;
                                KLine.Close    = close;
                                KLine.High     = high;
                                KLine.Low      = low;
                                KLine.Code     = code;
                                KLine.DateTime = day.Date + timelist[i];
                                minuteNow.Add(KLine);
                            }
                            else
                            {
                                StockMinuteTransaction KLine = new StockMinuteTransaction();
                                KLine.Amount   = 0;
                                KLine.Volume   = 0;
                                KLine.Open     = close;
                                KLine.Close    = close;
                                KLine.High     = close;
                                KLine.Low      = close;
                                KLine.Code     = code;
                                KLine.DateTime = day.Date + timelist[i];
                                minuteNow.Add(KLine);
                            }
                        }
                        var nearClose = (from data in dtToday where (data.TransactionDateTime.TimeOfDay > timelist[timelist.Count() - 1]) select data).ToList();
                        if (nearClose.Count() != 0)
                        {
                            high = nearClose.Max(x => x.LastPrice);
                            low  = nearClose.Min(x => x.LastPrice);
                            var listNow   = nearClose.ToList();
                            var startData = listNow[0];
                            var endData   = listNow[listNow.Count() - 1];
                            open  = startData.LastPrice;
                            close = endData.LastPrice;
                            double volumeNew = endData.Volume;
                            double amountNew = endData.Amount;
                            double volume    = volumeNew - totalVolume;
                            double amount    = amountNew - totalAmount;
                            totalAmount = amountNew;
                            totalVolume = volumeNew;
                            StockMinuteTransaction KLine = new StockMinuteTransaction();
                            KLine.Amount   = amount;
                            KLine.Volume   = volume;
                            KLine.Open     = open;
                            KLine.Close    = close;
                            KLine.High     = high;
                            KLine.Low      = low;
                            KLine.Code     = code;
                            KLine.DateTime = day.Date + timelist[timelist.Count() - 1];
                            minuteNow.Add(KLine);
                        }
                        else
                        {
                            StockMinuteTransaction KLine = new StockMinuteTransaction();
                            KLine.Amount   = 0;
                            KLine.Volume   = 0;
                            KLine.Open     = close;
                            KLine.Close    = close;
                            KLine.High     = close;
                            KLine.Low      = close;
                            KLine.Code     = code;
                            KLine.DateTime = day.Date + timelist[timelist.Count() - 1];
                            minuteNow.Add(KLine);
                        }
                    }
                    else
                    {
                        //for (int i = 0; i < timelist.Count(); i++)
                        //{
                        //    StockMinuteTransaction KLine = new StockMinuteTransaction();
                        //    KLine.Amount = 0;
                        //    KLine.Volume = 0;
                        //    KLine.Open =0;
                        //    KLine.Close = 0;
                        //    KLine.High = 0;
                        //    KLine.Low = 0;
                        //    KLine.Code = code;
                        //    KLine.DateTime = day.Date + timelist[i];
                        //    minuteNow.Add(KLine);
                        //}
                        Console.WriteLine("date:{0},no tickData!!!", day);
                    }
                    minuteAll.AddRange(minuteNow);
                }
                if (minuteAll.Count() != 0)
                {
                    var dt = transactionListToDataTable(minuteAll);
                    WriteToSql(dt);
                }
            }
        }
Пример #7
0
        private List <StockMinuteTransaction> LoadStockMinuteToSqlFromSouceDaily(string code, DateTime currentTime, bool record = true)
        {
            List <StockMinuteTransaction> list = new List <StockMinuteTransaction>();

            IdentifyOrCreateDBAndTable(currentTime);
            var dtToday = tickRepo.GetStockTransaction(code, currentTime, currentTime, record);

            dtToday = (from data in dtToday where (data.TransactionDateTime.TimeOfDay <= new TimeSpan(15, 0, 1)) select data).ToList();
            var timelist = DataTimeStampExtension.GetStockMinuteTimeList();
            List <StockMinuteTransaction> minuteNow = new List <StockMinuteTransaction>();
            bool exists = true;

            if (dtToday.Count() == 0 || dtToday[dtToday.Count() - 1].Volume <= 0)
            {
                exists = false;
            }
            if (exists == true)
            {
                //处理开盘前的价格和成交量
                var    day         = currentTime.Date;
                double totalVolume = 0;
                double totalAmount = 0;
                double high        = 0;
                double low         = 0;
                double close       = 0;
                double open        = 0;
                var    preOpen     = (from data in dtToday where (data.TransactionDateTime.TimeOfDay < timelist[0]) select data).ToList();
                if (preOpen.Count != 0)
                {
                    var last = preOpen[preOpen.Count() - 1];
                    totalVolume = last.Volume;
                    totalAmount = last.Amount;
                    close       = last.LastPrice;
                    open        = close;
                    high        = close;
                    low         = close;
                }

                for (int i = 0; i < timelist.Count() - 1; i++)
                {
                    var dtNow = (from data in dtToday where (data.TransactionDateTime.TimeOfDay >= timelist[i]) && (data.TransactionDateTime.TimeOfDay <= timelist[i + 1]) select data).ToList();
                    if (dtNow.Count() != 0)
                    {
                        high = dtNow.Max(x => x.LastPrice);
                        low  = dtNow.Min(x => x.LastPrice);
                        var listNow   = dtNow.ToList();
                        var startData = listNow[0];
                        var endData   = listNow[listNow.Count() - 1];
                        open  = startData.LastPrice;
                        close = endData.LastPrice;
                        double volumeNew = endData.Volume;
                        double amountNew = endData.Amount;
                        double volume    = volumeNew - totalVolume;
                        double amount    = amountNew - totalAmount;
                        totalAmount = amountNew;
                        totalVolume = volumeNew;
                        StockMinuteTransaction KLine = new StockMinuteTransaction();
                        KLine.Amount   = amount;
                        KLine.Volume   = volume;
                        KLine.Open     = open;
                        KLine.Close    = close;
                        KLine.High     = high;
                        KLine.Low      = low;
                        KLine.Code     = code;
                        KLine.DateTime = day.Date + timelist[i];
                        minuteNow.Add(KLine);
                    }
                    else
                    {
                        StockMinuteTransaction KLine = new StockMinuteTransaction();
                        KLine.Amount   = 0;
                        KLine.Volume   = 0;
                        KLine.Open     = close;
                        KLine.Close    = close;
                        KLine.High     = close;
                        KLine.Low      = close;
                        KLine.Code     = code;
                        KLine.DateTime = day.Date + timelist[i];
                        minuteNow.Add(KLine);
                    }
                }
                var nearClose = (from data in dtToday where (data.TransactionDateTime.TimeOfDay > timelist[timelist.Count() - 1]) select data).ToList();
                if (nearClose.Count() != 0)
                {
                    high = nearClose.Max(x => x.LastPrice);
                    low  = nearClose.Min(x => x.LastPrice);
                    var listNow   = nearClose.ToList();
                    var startData = listNow[0];
                    var endData   = listNow[listNow.Count() - 1];
                    open  = startData.LastPrice;
                    close = endData.LastPrice;
                    double volumeNew = endData.Volume;
                    double amountNew = endData.Amount;
                    double volume    = volumeNew - totalVolume;
                    double amount    = amountNew - totalAmount;
                    totalAmount = amountNew;
                    totalVolume = volumeNew;
                    StockMinuteTransaction KLine = new StockMinuteTransaction
                    {
                        Amount   = amount,
                        Volume   = volume,
                        Open     = open,
                        Close    = close,
                        High     = high,
                        Low      = low,
                        Code     = code,
                        DateTime = day.Date + timelist[timelist.Count() - 1]
                    };
                    minuteNow.Add(KLine);
                }
                else
                {
                    StockMinuteTransaction KLine = new StockMinuteTransaction();
                    KLine.Amount   = 0;
                    KLine.Volume   = 0;
                    KLine.Open     = close;
                    KLine.Close    = close;
                    KLine.High     = close;
                    KLine.Low      = close;
                    KLine.Code     = code;
                    KLine.DateTime = day.Date + timelist[timelist.Count() - 1];
                    minuteNow.Add(KLine);
                }
                list = minuteNow;
            }
            else
            {
                // Console.WriteLine("date:{0},no tickData!!!", currentTime);
            }
            return(list);
        }
        public void computeImpv(DateTime startDate, DateTime endDate)
        {
            var start = startDate;
            //while (start < endDate)
            //{
            //    if (!ExistInSqlServer(start))
            //    {
            //        CreateDBOrTableIfNecessary(start);
            //    }
            //    start = start.AddYears(1);
            //}
            //if (!ExistInSqlServer(endDate))
            //{
            //    CreateDBOrTableIfNecessary(endDate);
            //}
            var tradedays = dateRepo.GetStockTransactionDate(startDate, endDate);

            //逐日进行计算
            foreach (var date in tradedays)
            {
                if (!ExistInSqlServer(date))
                {
                    CreateDBOrTableIfNecessary(date);
                }
                double[,] myFuture = new double[4, 28802];
                var tickdata = new Dictionary <string, List <StockOptionTickTransaction> >();
                var etf      = DataTimeStampExtension.ModifyStockTickData(stockRepo.GetStockTransaction("510050.SH", date, date.AddHours(17)));
                var list     = infoRepo.GetStockOptionInfo(underlying, date, date).Where(x => x.unit == 10000);
                Dictionary <StockOptionProperty, string> optionCode = new Dictionary <StockOptionProperty, string>();
                //给出所有的strike信息
                List <double> strikeList = new List <double>();
                foreach (var item in list)
                {
                    if (strikeList.Contains(item.strike) == false)
                    {
                        strikeList.Add(item.strike);
                    }
                }
                strikeList = strikeList.OrderBy(x => x).ToList();
                //给出所有的duration信息
                List <DateTime> expireDateList = new List <DateTime>();
                foreach (var item in list)
                {
                    if (expireDateList.Contains(item.expireDate) == false)
                    {
                        expireDateList.Add(item.expireDate);
                    }
                }
                expireDateList = expireDateList.OrderBy(x => x).ToList();
                foreach (var item in list)
                {
                    var option0 = optionRepo.GetStockTransaction(item.code, date, date.AddHours(17));
                    if (option0.Count == 0)
                    {
                        continue;
                    }
                    var option = DataTimeStampExtension.ModifyOptionTickData(option0);
                    StockOptionProperty property = new StockOptionProperty {
                        strike = item.strike, call_or_put = item.type, expireDate = item.expireDate
                    };
                    optionCode.Add(property, item.code);
                    tickdata.Add(item.code, option);
                }
                //计算合约的合成远期价格

                for (int k = 0; k < 3; k++)                   //k遍历了到期时间
                {
                    double[,] futures = new double[4, 28802]; //futures[选取的strike,时间下标]
                    double[,] weights = new double[4, 28802];
                    for (int i = 0; i < 28802; i++)
                    {
                        var etfMid = getStockMidPrice(etf[i], volumeTarget * 100);
                        if (etfMid == 0)
                        {
                            continue;
                        }
                        var expireDate    = expireDateList[k];
                        var strikeListNow = strikeList.OrderBy(x => Math.Abs(x - etfMid * Math.Exp(rate * dateRepo.GetDuration(date, expireDate) / 252.0))).ToList();

                        for (int j = 0; j <= 3; j++)
                        {
                            StockOptionProperty call = new StockOptionProperty {
                                strike = strikeListNow[j], call_or_put = "认购", expireDate = expireDate
                            };
                            StockOptionProperty put = new StockOptionProperty {
                                strike = strikeListNow[j], call_or_put = "认沽", expireDate = expireDate
                            };
                            bool callExists = false, putExists = false;
                            foreach (var key in optionCode.Keys)
                            {
                                if (key.call_or_put == call.call_or_put && key.strike == call.strike && key.expireDate == call.expireDate)
                                {
                                    callExists = true;
                                    call       = key;
                                }
                                if (key.call_or_put == put.call_or_put && key.strike == put.strike && key.expireDate == put.expireDate)
                                {
                                    putExists = true;
                                    put       = key;
                                }
                            }
                            if (callExists && putExists)
                            {
                                var callTick = tickdata[optionCode[call]];
                                var putTick  = tickdata[optionCode[put]];
                                var callMid  = getOptionMidPrice(callTick[i], volumeTarget);
                                var putMid   = getOptionMidPrice(putTick[i], volumeTarget);
                                if (callMid > 0 && putMid > 0)
                                {
                                    var callSpread = getOptionSpread(callTick[i], volumeTarget);
                                    var putSpread  = getOptionSpread(putTick[i], volumeTarget);
                                    futures[j, i] = (callMid - putMid) * Math.Exp(rate * dateRepo.GetDuration(date, expireDate) / 252.0) + strikeListNow[j];
                                    weights[j, i] = 1 / ((Math.Pow(callSpread, 2) + Math.Pow(putSpread, 2)) / 2);
                                }
                            }
                        }
                        myFuture[k, i] = 0;
                        double weightsAll = 0;
                        for (int j = 0; j < 3; j++)
                        {
                            myFuture[k, i] += futures[j, i] * weights[j, i];
                            weightsAll     += weights[j, i];
                        }
                        if (weightsAll != 0)
                        {
                            myFuture[k, i] /= weightsAll;
                        }
                    }
                    int firstNonZero = 0;
                    for (int i = 0; i < 28802; i++)
                    {
                        if (myFuture[k, i] != 0)
                        {
                            firstNonZero = i;
                            break;
                        }
                    }
                    for (int i = firstNonZero + 1; i < 28802; i++)
                    {
                        if (myFuture[k, i] == 0)
                        {
                            myFuture[k, i] = myFuture[k, i - 1];
                        }
                    }
                    for (int i = firstNonZero + 1; i < 28802; i++)
                    {
                        myFuture[k, i] = emaCoeff * myFuture[k, i] + (1 - emaCoeff) * myFuture[k, i - 1];
                    }
                    //计算隐含波动率

                    foreach (var item in list)
                    {
                        if (item.expireDate != expireDateList[k])
                        {
                            continue;
                        }
                        DataTable dt = new DataTable();
                        dt.Columns.Add("code");
                        dt.Columns.Add("tdatetime", typeof(DateTime));
                        dt.Columns.Add("expiredate");
                        dt.Columns.Add("futurePrice");
                        dt.Columns.Add("futurePrice0");
                        dt.Columns.Add("duration");
                        dt.Columns.Add("maturitydate");
                        dt.Columns.Add("etfPrice");
                        dt.Columns.Add("strike");
                        dt.Columns.Add("call_or_put");
                        dt.Columns.Add("ask");
                        dt.Columns.Add("bid");
                        dt.Columns.Add("ask_impv");
                        dt.Columns.Add("bid_impv");
                        StockOptionProperty option = new StockOptionProperty {
                            strike = item.strike, call_or_put = item.type, expireDate = item.expireDate
                        };
                        foreach (var key in optionCode.Keys)
                        {
                            if (key.call_or_put == option.call_or_put && key.strike == option.strike && key.expireDate == option.expireDate)
                            {
                                option = key;
                            }
                        }
                        if (optionCode.ContainsKey(option) == true)
                        {
                            for (int i = 0; i < 28802; i++)
                            {
                                if (myFuture[k, i] == 0)
                                {
                                    continue;
                                }
                                var etfMid = getStockMidPrice(etf[i], volumeTarget * 100);
                                if (etfMid == 0)
                                {
                                    continue;
                                }
                                var strikeListNow = strikeList.OrderBy(x => Math.Abs(x - etfMid * Math.Exp(rate * dateRepo.GetDuration(date, item.expireDate) / 252.0))).ToList();
                                var optionTick    = tickdata[optionCode[option]];
                                if (optionTick[i] == null)
                                {
                                    continue;
                                }
                                double etfprice  = etf[i].LastPrice;
                                double ask       = optionTick[i].Ask1;
                                double bid       = optionTick[i].Bid1;
                                double duration  = dateRepo.GetDuration(date, option.expireDate) / 252.0;
                                double strike    = item.strike;
                                string callorput = item.type;
                                double askvol    = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(myFuture[k, i], ask, strike, duration, rate, callorput), 4);
                                double bidvol    = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(myFuture[k, i], bid, strike, duration, rate, callorput), 4);
                                double future0   = 0;
                                for (int m = 0; m <= 3; m++)
                                {
                                    if (strikeListNow[m] == item.strike)
                                    {
                                        future0 = futures[m, i];
                                        break;
                                    }
                                }
                                DataRow dr = dt.NewRow();
                                dr["code"]         = item.code;
                                dr["tdatetime"]    = Convert.ToDateTime(date + timelist[i]);//etf[i].TransactionDateTime;
                                dr["maturitydate"] = item.expireDate;
                                dr["futurePrice"]  = Math.Round(myFuture[k, i], 4);
                                dr["futurePrice0"] = Math.Round(future0, 4);
                                dr["strike"]       = Math.Round(strike, 4);
                                dr["expiredate"]   = dateRepo.GetDuration(date, option.expireDate);
                                dr["duration"]     = Math.Round(duration, 5);
                                dr["etfPrice"]     = etfprice;
                                dr["call_or_put"]  = item.type;
                                dr["ask"]          = ask;
                                dr["bid"]          = bid;
                                if (askvol > 0 && askvol < 3)
                                {
                                    dr["ask_impv"] = askvol;
                                }
                                else
                                {
                                    dr["ask_impv"] = null;
                                }
                                if (bidvol > 0 && bidvol < 3)
                                {
                                    dr["bid_impv"] = bidvol;
                                }
                                else
                                {
                                    dr["bid_impv"] = null;
                                }
                                if (optionTick[i].TransactionDateTime < date.Date + new TimeSpan(14, 57, 00))
                                {
                                    dt.Rows.Add(dr);
                                }
                            }
                        }

                        SaveResultToMssql(date, dt, item.strike, dateRepo.GetDuration(date, item.expireDate), item.type, item.code);
                    }
                }
            }
        }
        private void compute(DateTime date)
        {
            List <StockTickTransaction> etf = new List <StockTickTransaction>();

            etf = DataTimeStampExtension.ModifyStockTickData(stockRepo.GetStockTransaction("510050.SH", date, date.AddHours(17)));
            foreach (var item in parityList)
            {
                DataTable dt = new DataTable();
                dt.Columns.Add("tdatetime");
                dt.Columns.Add("expiredate");
                dt.Columns.Add("maturitydate");
                dt.Columns.Add("annualizedReturn");
                dt.Columns.Add("annualizedCloseCost");
                dt.Columns.Add("etfPrice");
                dt.Columns.Add("strike");
                dt.Columns.Add("callPrice");
                dt.Columns.Add("putPrice");
                dt.Columns.Add("callMinutelyPrice");
                dt.Columns.Add("putMinutelyPrice");
                dt.Columns.Add("minutelyVolume");
                double strike     = item.strike;
                int    expiredate = 0;
                List <StockOptionTickTransaction> call = new List <StockOptionTickTransaction>();
                List <StockOptionTickTransaction> put  = new List <StockOptionTickTransaction>();
                call = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.call, date, date.AddHours(17)));
                put  = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.put, date, date.AddHours(17)));
                //计算套利空间
                myList = new List <StockOptionParityProfit>();
                TimeSpan span = item.expireDate - date;
                // var multiple = item.unit/10000.0;
                for (int i = 0; i < 28802; i++)
                {
                    StockOptionParityProfit result = new StockOptionParityProfit();
                    double callMinutelyVolume      = 0;
                    double putMinutelyVolume       = 0;
                    double callPrice = 0;
                    double putPrice  = 0;
                    if (etf[i] != null && call != null && put != null && call[i] != null && put[i] != null && etf[i].LastPrice != 0 && call[i].LastPrice != 0 && put[i].LastPrice != 0 && call[i].Ask1 != 0 && put[i].Bid1 != 0 && call[i].Bid1 != 0 && put[i].Ask1 != 0)
                    {
                        result.date         = etf[i].TransactionDateTime;
                        result.strike       = item.strike;
                        result.etfPrice     = etf[i].LastPrice;
                        result.expiredate   = span.Days + 1;
                        expiredate          = result.expiredate;
                        result.maturitydate = item.expireDate;
                        double profit              = result.strike - (etf[i].Ask1 - call[i].Bid1 + put[i].Ask1);
                        double margin              = (etf[i].Ask1 - call[i].Bid1 + put[i].Ask1) + (call[i].LastPrice + Math.Max(0.12 * etf[i].LastPrice - Math.Max(result.strike - etf[i].LastPrice, 0), 0.07 * etf[i].LastPrice));
                        double annualizedReturn    = (profit - etf[i].Ask1 * 0.0001 - 1.6 / 10000.0) / margin / (double)result.expiredate * 365.0;
                        double annualizedCloseCost = (-result.strike + (etf[i].Bid1 - call[i].Ask1 + put[i].Bid1) - etf[i].Bid1 * 0.0001 - 3.2 / 10000.0) / margin / (double)result.expiredate * 365.0;
                        result.profit    = annualizedReturn;
                        result.cost      = annualizedCloseCost;
                        result.callPrice = call[i].LastPrice;
                        result.putPrice  = put[i].LastPrice;
                        if (i > 120 && call[i - 120] != null)
                        {
                            callMinutelyVolume = call[i].Volume - call[i - 120].Volume;
                            if (callMinutelyVolume != 0)
                            {
                                callPrice = (call[i].Amount - call[i - 120].Amount) / callMinutelyVolume / item.unit;
                            }
                        }
                        else
                        {
                            callMinutelyVolume = Math.Round(call[i].Volume / Convert.ToDouble(i + 1) * 120.0, 0);
                            if (callMinutelyVolume != 0)
                            {
                                callPrice = call[i].Amount / call[i].Volume / item.unit;
                            }
                        }
                        if (i > 120 && put[i - 120] != null)
                        {
                            putMinutelyVolume = put[i].Volume - put[i - 120].Volume;
                            if (putMinutelyVolume != 0)
                            {
                                putPrice = (put[i].Amount - put[i - 120].Amount) / putMinutelyVolume / item.unit;
                            }
                        }
                        else
                        {
                            putMinutelyVolume = Math.Round(put[i].Volume / Convert.ToDouble(i + 1) * 120.0, 0);
                            if (putMinutelyVolume != 0)
                            {
                                putPrice = put[i].Amount / put[i].Volume / item.unit;
                            }
                        }
                        myList.Add(result);
                        DataRow dr = dt.NewRow();
                        dr["tdatetime"]           = result.date;
                        dr["maturitydate"]        = result.maturitydate;
                        dr["strike"]              = Math.Round(result.strike, 4);
                        dr["annualizedReturn"]    = Math.Round(result.profit, 4);
                        dr["annualizedCloseCost"] = Math.Round(result.cost, 4);
                        dr["expiredate"]          = result.expiredate;
                        dr["etfPrice"]            = result.etfPrice;
                        dr["callPrice"]           = result.callPrice;
                        dr["putPrice"]            = result.putPrice;
                        dr["callMinutelyPrice"]   = Math.Round(Convert.ToDecimal(callPrice), 6);
                        dr["putMinutelyPrice"]    = Math.Round(Convert.ToDecimal(putPrice), 6);
                        dr["minutelyVolume"]      = Math.Min(Convert.ToDecimal(callMinutelyVolume), Convert.ToDecimal(putMinutelyVolume));
                        if (result.date < result.date.Date + new TimeSpan(14, 57, 00))
                        {
                            dt.Rows.Add(dr);
                        }
                    }
                }
                SaveResultToMssql(date, dt, strike, expiredate);
                //SaveResultToMssql(date, dt,expiredate);
            }
        }
        public void record(DateTime startDate, DateTime endDate)
        {
            var tradedays = dateRepo.GetStockTransactionDate(startDate, endDate);

            CreateDBOrTableIfNecessary(startDate);
            CreateDBOrTableIfNecessary(startDate.AddYears(1));
            var start = startDate;

            while (start < endDate)
            {
                if (!ExistInSqlServer(start))
                {
                    CreateDBOrTableIfNecessary(start);
                }
                start = start.AddYears(1);
            }
            if (!ExistInSqlServer(endDate))
            {
                CreateDBOrTableIfNecessary(endDate);
            }

            foreach (var date in tradedays)
            {
                DataTable dt = new DataTable();
                dt = initializeDataTable(dt);
                double[] sigma1Ask = new double[28802];
                double[] sigma1Bid = new double[28802];
                double[] sigma2Ask = new double[28802];
                double[] sigma2Bid = new double[28802];
                double[] vixAsk    = new double[28802];
                double[] vixBid    = new double[28802];

                var list = infoRepo.GetStockOptionInfo(underlying, date, date);
                list = OptionUtilities.modifyOptionListByETFBonus(list, date);
                List <StockOptionInformation> callListThisMonth = new List <StockOptionInformation>();
                List <StockOptionInformation> callListNextMonth = new List <StockOptionInformation>();
                List <StockOptionInformation> putListThisMonth  = new List <StockOptionInformation>();
                List <StockOptionInformation> putListNextMonth  = new List <StockOptionInformation>();
                var    durationList      = OptionUtilities.getDurationStructure(list, date);
                double durationThisMonth = 0;
                double durationNextMonth = 0;
                if (durationList[0] > 7)
                {
                    durationThisMonth = durationList[0];
                    durationNextMonth = durationList[1];
                }
                else
                {
                    durationThisMonth = durationList[1];
                    durationNextMonth = durationList[2];
                }
                foreach (var item in list)
                {
                    if (OptionUtilities.getDuration(item, date) == durationThisMonth && item.unit == 10000)
                    {
                        if (item.type == "认购")
                        {
                            callListThisMonth.Add(item);
                        }
                        else
                        {
                            putListThisMonth.Add(item);
                        }
                    }
                    else if (OptionUtilities.getDuration(item, date) == durationNextMonth && item.unit == 10000)
                    {
                        if (item.type == "认购")
                        {
                            callListNextMonth.Add(item);
                        }
                        else
                        {
                            putListNextMonth.Add(item);
                        }
                    }
                }
                callListThisMonth = callListThisMonth.OrderBy(x => x.strike).ToList();
                callListNextMonth = callListNextMonth.OrderBy(x => x.strike).ToList();
                putListThisMonth  = putListThisMonth.OrderBy(x => x.strike).ToList();
                putListNextMonth  = putListNextMonth.OrderBy(x => x.strike).ToList();
                //获取当日ETF及期权数据
                List <StockTickTransaction> etf = new List <StockTickTransaction>();
                etf = DataTimeStampExtension.ModifyStockTickData(stockRepo.GetStockTransaction("510050.SH", date, date.AddHours(17)));
                Dictionary <double, List <StockOptionTickTransaction> > callDataThisMonth = new Dictionary <double, List <StockOptionTickTransaction> >();
                Dictionary <double, List <StockOptionTickTransaction> > putDataThisMonth  = new Dictionary <double, List <StockOptionTickTransaction> >();
                Dictionary <double, List <StockOptionTickTransaction> > callDataNextMonth = new Dictionary <double, List <StockOptionTickTransaction> >();
                Dictionary <double, List <StockOptionTickTransaction> > putDataNextMonth  = new Dictionary <double, List <StockOptionTickTransaction> >();
                List <double> strikeListThisMonth = new List <double>();
                List <double> strikeListNextMonth = new List <double>();
                foreach (var item in callListThisMonth)
                {
                    strikeListThisMonth.Add(item.strike);
                    var call = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.code, date, date.AddHours(17)));
                    callDataThisMonth.Add(item.strike, call);
                }
                foreach (var item in putListThisMonth)
                {
                    var put = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.code, date, date.AddHours(17)));
                    putDataThisMonth.Add(item.strike, put);
                }
                foreach (var item in callListNextMonth)
                {
                    strikeListNextMonth.Add(item.strike);
                    var call = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.code, date, date.AddHours(17)));
                    callDataNextMonth.Add(item.strike, call);
                }
                foreach (var item in putListNextMonth)
                {
                    //2016-2-17数据有缺失
                    var put = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.code, date, date.AddHours(17)));
                    putDataNextMonth.Add(item.strike, put);
                }
                strikeListThisMonth = strikeListThisMonth.OrderBy(x => x).ToList();
                strikeListNextMonth = strikeListNextMonth.OrderBy(x => x).ToList();
                for (int index = 0; index < 28802; index++)
                {
                    bool hasData = true;
                    foreach (var item in strikeListThisMonth)
                    {
                        if (callDataThisMonth[item] == null || putDataThisMonth[item] == null || callDataThisMonth[item][index] == null || putDataThisMonth[item][index] == null || (callDataThisMonth[item][index].AskV1 == 0 && callDataThisMonth[item][index].BidV1 == 0) || (putDataThisMonth[item][index].AskV1 == 0 && putDataThisMonth[item][index].BidV1 == 0))
                        {
                            hasData = false;
                            break;
                        }
                    }
                    //if (durationThisMonth <= 30)
                    {
                        foreach (var item in strikeListNextMonth)
                        {
                            if (callDataNextMonth[item] == null || putDataNextMonth[item] == null || callDataNextMonth[item][index] == null || putDataNextMonth[item][index] == null || callDataNextMonth[item][index].AskV1 == 0 || putDataNextMonth[item][index].AskV1 == 0 || callDataNextMonth[item][index].BidV1 == 0 || putDataNextMonth[item][index].BidV1 == 0)
                            {
                                hasData = false;
                                break;
                            }
                        }
                    }
                    if (hasData == false)
                    {
                        continue;
                    }
                    //初始化记录合约信息的列表
                    List <iVixInfo> thisMonthInfo = new List <iVixInfo>();
                    List <iVixInfo> nextMonthInfo = new List <iVixInfo>();
                    DataRow         dr            = dt.NewRow();
                    var             now           = callDataThisMonth[strikeListThisMonth[0]][index].TransactionDateTime;
                    var             expiredate1   = callListThisMonth[0].expireDate;
                    var             expiredate2   = callListNextMonth[0].expireDate;
                    var             span          = date.AddHours(15) - now;
                    //计算时间T NT:近月合约剩余到期时间(以分钟计) T:NT/365
                    double T1 = (durationThisMonth - 1 + (span.Hours * 60 + span.Minutes) / 840.0) / 365.0;
                    //找到认购期权价格与认沽期权价格相差最小的执行价的K
                    //计算远期价格F S+exp(RT)×[认购期权价格 S −认沽期权价格 S ]
                    double distance1  = 100;
                    double kThisMonth = 0;
                    double F          = 0;
                    for (int i = 0; i < strikeListThisMonth.Count(); i++)
                    {
                        double distance0 = Math.Abs((callDataThisMonth[strikeListThisMonth[i]][index].Ask1 + callDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2 - (putDataThisMonth[strikeListThisMonth[i]][index].Ask1 + putDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2);
                        if (distance0 < distance1)
                        {
                            distance1 = distance0;
                            F         = strikeListThisMonth[i] + Math.Exp(rate * T1) * ((callDataThisMonth[strikeListThisMonth[i]][index].Ask1 + callDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2 - (putDataThisMonth[strikeListThisMonth[i]][index].Ask1 + putDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2);
                        }
                    }
                    //找到K0
                    for (int i = 0; i < strikeListThisMonth.Count() - 1; i++)
                    {
                        kThisMonth = strikeListThisMonth[i];
                        if (strikeListThisMonth[i + 1] > F)
                        {
                            break;
                        }
                    }
                    //计算近月ivix
                    for (int i = 0; i < strikeListThisMonth.Count(); i++)
                    {
                        iVixInfo info = new iVixInfo();
                        double   ask  = 0;
                        double   bid  = 0;
                        double   dK   = 0;
                        double   k    = strikeListThisMonth[i];
                        if (i == strikeListThisMonth.Count() - 1)
                        {
                            dK = strikeListThisMonth[strikeListThisMonth.Count() - 1] - strikeListThisMonth[strikeListThisMonth.Count() - 2];
                        }
                        else
                        {
                            dK = strikeListThisMonth[i + 1] - strikeListThisMonth[i];
                        }
                        info.strike      = k;
                        info.duration    = T1;
                        info.coefficient = 2 / info.duration * dK / Math.Pow(info.strike, 2) * Math.Exp(rate * info.duration);
                        if (strikeListThisMonth[i] < kThisMonth)
                        {
                            ask = putDataThisMonth[strikeListThisMonth[i]][index].Ask1;
                            bid = putDataThisMonth[strikeListThisMonth[i]][index].Bid1;
                            var mid = (ask + bid) / 2;
                            info.sigma          = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid, info.strike, info.duration, rate, "认沽"), 4);
                            info.vega           = ImpliedVolatilityExtension.ComputeOptionVega(info.strike, info.duration, rate, 0, info.sigma, F * Math.Exp(-rate * info.duration)) / 100.0;
                            info.ask            = ask;
                            info.askv           = putDataThisMonth[strikeListThisMonth[i]][index].AskV1;
                            info.bid            = bid;
                            info.bidv           = putDataThisMonth[strikeListThisMonth[i]][index].BidV1;
                            info.minutelyVolume = ComputeMinutelyVolume(putDataThisMonth[strikeListThisMonth[i]], index);
                        }
                        else if (strikeListThisMonth[i] == kThisMonth)
                        {
                            ask = (putDataThisMonth[strikeListThisMonth[i]][index].Ask1 + callDataThisMonth[strikeListThisMonth[i]][index].Ask1) / 2;
                            bid = (putDataThisMonth[strikeListThisMonth[i]][index].Bid1 + callDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2;
                            var mid1   = (putDataThisMonth[strikeListThisMonth[i]][index].Ask1 + putDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2;
                            var mid2   = (callDataThisMonth[strikeListThisMonth[i]][index].Ask1 + callDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2;
                            var sigma1 = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid1, info.strike, info.duration, rate, "认沽"), 4);
                            var sigma2 = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid2, info.strike, info.duration, rate, "认购"), 4);
                            var vega1  = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, sigma1, F * Math.Exp(-rate * info.duration)) / 100.0;
                            var vega2  = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, sigma2, F * Math.Exp(-rate * info.duration)) / 100.0;
                            info.sigma = (sigma1 + sigma2) / 2;
                            info.vega  = (vega1 + vega2) / 2;
                            info.ask   = ask;
                            info.askv  = Math.Min(putDataThisMonth[strikeListThisMonth[i]][index].AskV1, callDataThisMonth[strikeListThisMonth[i]][index].AskV1) * 2;
                            info.bid   = bid;
                            info.bidv  = Math.Min(putDataThisMonth[strikeListThisMonth[i]][index].BidV1, callDataThisMonth[strikeListThisMonth[i]][index].BidV1) * 2;
                            var volumeCall = ComputeMinutelyVolume(callDataThisMonth[strikeListThisMonth[i]], index);
                            var volumePut  = ComputeMinutelyVolume(putDataThisMonth[strikeListThisMonth[i]], index);
                            info.minutelyVolume = Math.Min(volumeCall, volumePut) * 2;
                        }
                        else
                        {
                            ask = callDataThisMonth[strikeListThisMonth[i]][index].Ask1;
                            bid = callDataThisMonth[strikeListThisMonth[i]][index].Bid1;
                            var mid = (ask + bid) / 2;
                            info.sigma          = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid, info.strike, info.duration, rate, "认购"), 4);
                            info.vega           = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, info.sigma, F * Math.Exp(-rate * info.duration)) / 100.0;
                            info.ask            = ask;
                            info.askv           = callDataThisMonth[strikeListThisMonth[i]][index].AskV1;
                            info.bid            = bid;
                            info.bidv           = callDataThisMonth[strikeListThisMonth[i]][index].BidV1;
                            info.minutelyVolume = ComputeMinutelyVolume(callDataThisMonth[strikeListThisMonth[i]], index);
                        }
                        sigma1Ask[index] += (2 / T1) * dK / (k * k) * Math.Exp(rate * T1) * ask;
                        sigma1Bid[index] += (2 / T1) * dK / (k * k) * Math.Exp(rate * T1) * bid;
                        thisMonthInfo.Add(info);
                    }

                    sigma1Ask[index] += -1 / T1 * Math.Pow((F / kThisMonth) - 1, 2);
                    sigma1Bid[index] += -1 / T1 * Math.Pow((F / kThisMonth) - 1, 2);
                    sigma1Ask[index]  = Math.Sqrt(sigma1Ask[index]);
                    sigma1Bid[index]  = Math.Sqrt(sigma1Bid[index]);
                    if (durationThisMonth > 30)
                    {
                        vixAsk[index] = sigma1Ask[index];
                        vixBid[index] = sigma1Bid[index];
                    }
                    //计算时间T NT:近月合约剩余到期时间(以分钟计) T:NT/365
                    double T2 = (durationNextMonth - 1 + (span.Minutes) / 840) / 365.0;
                    //找到认购期权价格与认沽期权价格相差最小的执行价的K
                    //计算远期价格F S+exp(RT)×[认购期权价格 S −认沽期权价格 S ]
                    distance1 = 100;
                    double kNextMonth = 0;
                    F = 0;
                    for (int i = 0; i < strikeListNextMonth.Count(); i++)
                    {
                        double distance0 = Math.Abs((callDataNextMonth[strikeListNextMonth[i]][index].Ask1 + callDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2 - (putDataNextMonth[strikeListNextMonth[i]][index].Ask1 + putDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2);
                        if (distance0 < distance1)
                        {
                            distance1 = distance0;
                            F         = strikeListNextMonth[i] + Math.Exp(rate * T2) * ((callDataNextMonth[strikeListNextMonth[i]][index].Ask1 + callDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2 - (putDataNextMonth[strikeListNextMonth[i]][index].Ask1 + putDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2);
                        }
                    }
                    //找到K0
                    for (int i = 0; i < strikeListNextMonth.Count() - 1; i++)
                    {
                        kNextMonth = strikeListNextMonth[i];
                        if (strikeListNextMonth[i + 1] > F)
                        {
                            break;
                        }
                    }
                    //计算远月ivix
                    for (int i = 0; i < strikeListNextMonth.Count(); i++)
                    {
                        iVixInfo info = new iVixInfo();
                        double   ask  = 0;
                        double   bid  = 0;
                        double   dK   = 0;
                        double   k    = strikeListNextMonth[i];
                        if (i == strikeListNextMonth.Count() - 1)
                        {
                            dK = strikeListNextMonth[strikeListNextMonth.Count() - 1] - strikeListNextMonth[strikeListNextMonth.Count() - 2];
                        }
                        else
                        {
                            dK = strikeListNextMonth[i + 1] - strikeListNextMonth[i];
                        }
                        info.strike      = k;
                        info.duration    = T2;
                        info.coefficient = 2 / info.duration * dK / Math.Pow(info.strike, 2) * Math.Exp(rate * info.duration);


                        if (strikeListNextMonth[i] < kNextMonth)
                        {
                            ask = putDataNextMonth[strikeListNextMonth[i]][index].Ask1;
                            bid = putDataNextMonth[strikeListNextMonth[i]][index].Bid1;
                            var mid = (ask + bid) / 2;
                            info.sigma          = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid, info.strike, info.duration, rate, "认沽"), 4);
                            info.vega           = ImpliedVolatilityExtension.ComputeOptionVega(info.strike, info.duration, rate, 0, info.sigma, F * Math.Exp(-rate * info.duration)) / 100.0;
                            info.ask            = ask;
                            info.askv           = putDataNextMonth[strikeListNextMonth[i]][index].AskV1;
                            info.bid            = bid;
                            info.bidv           = putDataNextMonth[strikeListNextMonth[i]][index].BidV1;
                            info.minutelyVolume = ComputeMinutelyVolume(putDataNextMonth[strikeListNextMonth[i]], index);
                        }
                        else if (strikeListNextMonth[i] == kNextMonth)
                        {
                            ask = (putDataNextMonth[strikeListNextMonth[i]][index].Ask1 + callDataNextMonth[strikeListNextMonth[i]][index].Ask1) / 2;
                            bid = (putDataNextMonth[strikeListNextMonth[i]][index].Bid1 + callDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2;
                            var mid1   = (putDataNextMonth[strikeListNextMonth[i]][index].Ask1 + putDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2;
                            var mid2   = (callDataNextMonth[strikeListNextMonth[i]][index].Ask1 + callDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2;
                            var sigma1 = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid1, info.strike, info.duration, rate, "认沽"), 4);
                            var sigma2 = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid2, info.strike, info.duration, rate, "认购"), 4);
                            var vega1  = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, sigma1, F * Math.Exp(-rate * info.duration)) / 100.0;
                            var vega2  = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, sigma2, F * Math.Exp(-rate * info.duration)) / 100.0;
                            info.sigma = (sigma1 + sigma2) / 2;
                            info.vega  = (vega1 + vega2) / 2;
                            info.ask   = ask;
                            info.askv  = Math.Min(putDataNextMonth[strikeListNextMonth[i]][index].AskV1, callDataNextMonth[strikeListNextMonth[i]][index].AskV1) * 2;
                            info.bid   = bid;
                            info.bidv  = Math.Min(putDataNextMonth[strikeListNextMonth[i]][index].BidV1, callDataNextMonth[strikeListNextMonth[i]][index].BidV1) * 2;
                            var volumeCall = ComputeMinutelyVolume(callDataNextMonth[strikeListNextMonth[i]], index);
                            var volumePut  = ComputeMinutelyVolume(putDataNextMonth[strikeListNextMonth[i]], index);
                            info.minutelyVolume = Math.Min(volumeCall, volumePut) * 2;
                        }
                        else
                        {
                            ask = callDataNextMonth[strikeListNextMonth[i]][index].Ask1;
                            bid = callDataNextMonth[strikeListNextMonth[i]][index].Bid1;
                            var mid = (ask + bid) / 2;
                            info.sigma          = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid, info.strike, info.duration, rate, "认购"), 4);
                            info.vega           = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, info.sigma, F * Math.Exp(-rate * info.duration)) / 100.0;
                            info.ask            = ask;
                            info.askv           = callDataNextMonth[strikeListNextMonth[i]][index].AskV1;
                            info.bid            = bid;
                            info.bidv           = callDataNextMonth[strikeListNextMonth[i]][index].BidV1;
                            info.minutelyVolume = ComputeMinutelyVolume(callDataNextMonth[strikeListNextMonth[i]], index);
                        }
                        sigma2Ask[index] += (2 / T2) * dK / (k * k) * Math.Exp(rate * T2) * ask;
                        sigma2Bid[index] += (2 / T2) * dK / (k * k) * Math.Exp(rate * T2) * bid;
                        nextMonthInfo.Add(info);
                    }
                    sigma2Ask[index] += -1 / T2 * Math.Pow((F / kNextMonth) - 1, 2);
                    sigma2Bid[index] += -1 / T2 * Math.Pow((F / kNextMonth) - 1, 2);
                    sigma2Ask[index]  = Math.Sqrt(sigma2Ask[index]);
                    sigma2Bid[index]  = Math.Sqrt(sigma2Bid[index]);
                    if (durationThisMonth <= 30)
                    {
                        vixAsk[index] = Math.Sqrt((T1 * Math.Pow(sigma1Ask[index], 2) * (T2 - 30.0 / 365.0) / (T2 - T1) + T2 * Math.Pow(sigma2Ask[index], 2) * (30.0 / 365.0 - T1) / (T2 - T1)) * 365.0 / 30.0);
                        vixBid[index] = Math.Sqrt((T1 * Math.Pow(sigma1Bid[index], 2) * (T2 - 30.0 / 365.0) / (T2 - T1) + T2 * Math.Pow(sigma2Bid[index], 2) * (30.0 / 365.0 - T1) / (T2 - T1)) * 365.0 / 30.0);
                        foreach (var item in thisMonthInfo)
                        {
                            item.coefficient *= T1 * (T2 - 30.0 / 365.0) / (T2 - T1) * 365.0 / 30.0;
                        }
                        foreach (var item in nextMonthInfo)
                        {
                            item.coefficient *= T2 * (30.0 / 365.0 - T1) / (T2 - T1) * 365.0 / 30.0;
                        }
                    }
                    //计算整体的vega,以及盘口的量
                    double vegaTotal        = 0;
                    double number           = 0;
                    double percentAskMax    = 0;
                    double percentAskMin    = 1;
                    double percentBidMax    = 0;
                    double percentBidMin    = 1;
                    double percentVolumeMax = 0;
                    double percentVolumeMin = 1;
                    if (durationThisMonth > 30)
                    {
                        foreach (var item in thisMonthInfo)
                        {
                            vegaTotal += item.vega * item.coefficient * 10000;
                        }
                        number = cashVega / vegaTotal;
                        foreach (var item in thisMonthInfo)
                        {
                            double percentAsk    = item.askv / number;
                            double percentBid    = item.bidv / number;
                            double percentVolume = item.minutelyVolume / number;

                            if (percentAsk > percentAskMax)
                            {
                                percentAskMax = percentAsk;
                            }
                            if (percentAsk < percentAskMin)
                            {
                                percentAskMin = percentAsk;
                            }
                            if (percentBid > percentBidMax)
                            {
                                percentBidMax = percentBid;
                            }
                            if (percentBid < percentBidMin)
                            {
                                percentBidMin = percentBid;
                            }
                            if (percentVolume > percentVolumeMax)
                            {
                                percentVolumeMax = percentVolume;
                            }
                            if (percentVolume < percentVolumeMin)
                            {
                                percentVolumeMin = percentVolume;
                            }
                        }
                    }
                    else
                    {
                        foreach (var item in thisMonthInfo)
                        {
                            vegaTotal += item.vega * item.coefficient * 10000;
                        }
                        foreach (var item in nextMonthInfo)
                        {
                            vegaTotal += item.vega * item.coefficient * 10000;
                        }
                        number = cashVega / 2 / vegaTotal;
                        foreach (var item in thisMonthInfo)
                        {
                            double percentAsk    = item.askv / number / item.coefficient;
                            double percentBid    = item.bidv / number / item.coefficient;
                            double percentVolume = item.minutelyVolume / number;
                            if (percentAsk > percentAskMax)
                            {
                                percentAskMax = percentAsk;
                            }
                            if (percentAsk < percentAskMin)
                            {
                                percentAskMin = percentAsk;
                            }
                            if (percentBid > percentBidMax)
                            {
                                percentBidMax = percentBid;
                            }
                            if (percentBid < percentBidMin)
                            {
                                percentBidMin = percentBid;
                            }
                            if (percentVolume > percentVolumeMax)
                            {
                                percentVolumeMax = percentVolume;
                            }
                            if (percentVolume < percentVolumeMin)
                            {
                                percentVolumeMin = percentVolume;
                            }
                        }
                        foreach (var item in nextMonthInfo)
                        {
                            double percentAsk    = item.askv / number / item.coefficient;
                            double percentBid    = item.bidv / number / item.coefficient;
                            double percentVolume = item.minutelyVolume / number;
                            if (percentAsk > percentAskMax)
                            {
                                percentAskMax = percentAsk;
                            }
                            if (percentAsk < percentAskMin)
                            {
                                percentAskMin = percentAsk;
                            }
                            if (percentBid > percentBidMax)
                            {
                                percentBidMax = percentBid;
                            }
                            if (percentBid < percentBidMin)
                            {
                                percentBidMin = percentBid;
                            }
                            if (percentVolume > percentVolumeMax)
                            {
                                percentVolumeMax = percentVolume;
                            }
                            if (percentVolume < percentVolumeMin)
                            {
                                percentVolumeMin = percentVolume;
                            }
                        }
                    }

                    dr["tdatetime"]        = now;
                    dr["expiredate1"]      = expiredate1;
                    dr["expiredate2"]      = expiredate2;
                    dr["duration1"]        = Math.Round(T1, 6);
                    dr["duration2"]        = Math.Round(T2, 6);
                    dr["sigma1Ask"]        = Math.Round(sigma1Ask[index] * 100, 4);
                    dr["sigma1Bid"]        = Math.Round(sigma1Bid[index] * 100, 4);
                    dr["sigma2Ask"]        = Math.Round(sigma2Ask[index] * 100, 4);
                    dr["sigma2Bid"]        = Math.Round(sigma2Bid[index] * 100, 4);
                    dr["sigmaAsk"]         = Math.Round(vixAsk[index] * 100, 4);
                    dr["sigmaBid"]         = Math.Round(vixBid[index] * 100, 4);
                    dr["vegaTotal"]        = Math.Round(vegaTotal, 4);
                    dr["number"]           = Math.Round(number, 4);
                    dr["percentAskMax"]    = Math.Round(percentAskMax, 4);
                    dr["percentAskMin"]    = Math.Round(percentAskMin, 4);
                    dr["percentBidMax"]    = Math.Round(percentBidMax, 4);
                    dr["percentBidMin"]    = Math.Round(percentBidMin, 4);
                    dr["percentVolumeMax"] = Math.Round(percentVolumeMax, 4);
                    dr["percentVolumeMin"] = Math.Round(percentVolumeMin, 4);
                    if (now < date.Date + new TimeSpan(14, 57, 00))
                    {
                        dt.Rows.Add(dr);
                    }
                }
                SaveResultToMssql(date, dt);
            }
        }