/// <summary>
        /// 跨式期权开仓
        /// </summary>
        /// <param name="dataToday"></param>
        /// <param name="signal"></param>
        /// <param name="positions"></param>
        /// <param name="myAccount"></param>
        /// <param name="pairs"></param>
        /// <param name="today"></param>
        /// <param name="index"></param>
        /// <param name="duration"></param>
        private void openStrangle(ref Dictionary <string, List <KLine> > dataToday, ref Dictionary <string, MinuteSignal> signal, ref SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> > positions, ref BasicAccount myAccount, ref SortedDictionary <DateTime, List <StranglePair> > pairs, DateTime today, int index, double duration)
        {
            DateTime now            = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(today), index);
            double   etfPriceNow    = dataToday[targetVariety][index].open;
            var      optionInfoList = OptionUtilities.getUnmodifiedOptionInfoList(this.optionInfoList, today);
            //选取指定的看涨期权
            var        list = OptionUtilities.getOptionListByDate(OptionUtilities.getOptionListByStrike(OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认购"), etfPriceNow, etfPriceNow + 0.5), Kit.ToInt_yyyyMMdd(today)).OrderBy(x => x.strike).ToList();
            OptionInfo call = list[0];
            //根据给定的看涨期权选取对应的看跌期权
            OptionInfo put = OptionUtilities.getCallByPutOrPutByCall(optionInfoList, call);

            if (call.strike != 0 && put.strike != 0 && (call.modifiedDate > today.AddDays(10) || call.modifiedDate < today)) //跨式期权组合存在进行开仓
            {
                tradeAssistant(ref dataToday, ref signal, call.optionCode, call.contractMultiplier, today, now, index);
                tradeAssistant(ref dataToday, ref signal, put.optionCode, put.contractMultiplier, today, now, index);
                StranglePair openPair = new StranglePair()
                {
                    callCode = call.optionCode, putCode = put.optionCode, callPosition = call.contractMultiplier, putPosition = put.contractMultiplier, endDate = call.endDate, etfPrice = etfPriceNow, callStrike = call.strike, putStrike = put.strike, modifiedDate = now, strangleOpenPrice = dataToday[call.optionCode][index].open + dataToday[put.optionCode][index].open, closeDate = new DateTime(), closePrice = 0
                };
                List <StranglePair> pairList = new List <StranglePair>();
                pairList.Add(openPair);
                pairs.Add(now, pairList);
                MinuteTransactionWithBar.ComputePosition(signal, dataToday, ref positions, ref myAccount, slipPoint: slipPoint, now: now, nowIndex: index);
            }
        }
예제 #2
0
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="todayInt"></param>
        /// <param name="riskFreeRate"></param>
        public VolSurface(int todayInt = 0, double riskFreeRate = 0.027)
        {
            if (todayInt == 0)
            {
                today = DateTime.Now;
            }
            else
            {
                today = Kit.ToDate(todayInt);
            }
            optionList = getExistingOption(today);
            //获取今日期权的到期日期
            var dateStructure = OptionUtilities.getDurationStructure(optionList, today);

            //存储今日期权的基本信息
            optionInfo = optionList.ToDictionary(x => x.optionCode, y => y);
            rate       = riskFreeRate;
            duartion   = dateStructure[0];
            getOptionData(dateStructure[0], today);
            while (DateTime.Now.TimeOfDay <= new TimeSpan(15, 00, 0))
            {
                DateTime now1 = DateTime.Now;
                computeVol();
                DateTime now2 = DateTime.Now;
                Console.WriteLine(now2 - now1);
                Thread.Sleep(5000);
            }
        }
        /// <summary>
        /// 获取对应的期权合约
        /// </summary>
        /// <param name="duration"></param>
        /// <param name="strike"></param>
        /// <param name="etfPriceNow"></param>
        /// <param name="type"></param>
        /// <param name="today"></param>
        /// <returns></returns>
        private OptionInfo getOptionCode(double duration, double etfPriceNow, string type, DateTime today)
        {
            OptionInfo option         = new OptionInfo();
            var        optionInfoList = OptionUtilities.getUnmodifiedOptionInfoList(this.optionInfoList, today);

            if (type == "认购")
            {
                //选取指定的看涨期权
                var list = OptionUtilities.getOptionListByDate(OptionUtilities.getOptionListByStrike(OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认购"), etfPriceNow, etfPriceNow + 0.5), Kit.ToInt_yyyyMMdd(today)).OrderBy(x => x.strike).ToList();
                if (list.Count > 0)
                {
                    option = list[0];
                }
            }
            else if (type == "认沽")
            {
                //选取指定的看跌期权
                var list = OptionUtilities.getOptionListByDate(OptionUtilities.getOptionListByStrike(OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认沽"), etfPriceNow - 0.5, etfPriceNow), Kit.ToInt_yyyyMMdd(today)).OrderBy(x => x.strike).ToList();
                if (list.Count > 0)
                {
                    option = list[0];
                }
            }
            return(option);
        }
예제 #4
0
        protected void Page_Load(object sender, EventArgs e)
        {
            this.ShowTransactions();
            OptionUtilities optionUtilities = new OptionUtilities();

            pspName.Items.AddRange(optionUtilities.GetPSPOptions());
        }
        /// <summary>
        /// 估算未来的期权价格
        /// </summary>
        /// <param name="days"></param>
        /// <param name="code"></param>
        /// <param name="etfPrice"></param>
        /// <returns></returns>
        private double computeFuturePrice(int days, string code, double etfPrice)
        {
            double price  = 0;
            var    option = OptionUtilities.getOptionByCode(optionList, code);
            int    x      = Convert.ToInt32(optionPrice[code].duration - days);
            int    y      = Convert.ToInt32(Math.Round(1000 * Math.Log(option.strike / etfPrice), 0) + 500);
            double vol    = volSurface[x, y];

            price = ImpliedVolatilityUtilities.ComputeOptionPrice(option.strike, (optionPrice[code].duration - days) / 252.0, riskFreeRate, 0, option.optionType, vol, etfPrice);
            return(price);
        }
예제 #6
0
        public void getOptionData(double duration, DateTime today)
        {
            var           optionListNow = OptionUtilities.getOptionListByDuration(getExistingOption(today), today, duration);
            var           list = from OptionInfo in optionListNow orderby OptionInfo.optionType ascending, OptionInfo.strike ascending select OptionInfo;
            List <string> code = new List <string>();

            dataListKey = code;
            foreach (var item in list)
            {
                code.Add(item.optionCode);
            }
            code.Add(ETF);
            Execute(code);
        }
        /// <summary>
        /// 以收益损失比给期权组合打分
        /// </summary>
        /// <param name="code1"></param>
        /// <param name="code2"></param>
        /// <param name="days"></param>
        /// <param name="upperPrice"></param>
        /// <param name="lowerPrice"></param>
        /// <param name="up"></param>
        /// <param name="low"></param>
        /// <returns></returns>
        private double computeMarkOfPairs(string code1, string code2, int days, double upperPrice, double lowerPrice, ref double up, ref double low)
        {
            double marks           = -100;
            double initialValue    = optionPrice[code1].lastPrice - optionPrice[code2].lastPrice;
            double upperValue      = computeFuturePrice(days, code1, upperPrice) - computeFuturePrice(days, code2, upperPrice);
            double lowerValue      = computeFuturePrice(days, code1, lowerPrice) - computeFuturePrice(days, code2, lowerPrice);
            var    option2         = OptionUtilities.getOptionByCode(optionList, code2);
            double margin          = OptionMargin.ComputeOpenMargin(etfPrice, optionPrice[code2].lastPrice, option2.strike, option2.optionType, 1, etfPrice) + (upperPrice - lowerPrice) / 2;
            double capitalOccupied = margin - initialValue;

            up    = (upperValue - initialValue) / capitalOccupied;
            low   = (lowerValue - initialValue) / capitalOccupied;
            marks = up / low;
            return(marks);
        }
        public void recorddata(DateTime startDate, DateTime endDate)
        {
            var tradedays = dateRepo.GetStockTransactionDate(startDate, endDate);

            foreach (var date in tradedays)
            {
                stockRepo.GetStockTransaction("510050.SH", date, date.AddHours(17));
                var list = infoRepo.GetStockOptionInfo(underlying, date, date);
                list = OptionUtilities.modifyOptionListByETFBonus(list, date);
                foreach (var item in list)
                {
                    optionRepo.GetStockTransaction(item.code, date, date.AddHours(17));
                }
            }
        }
 private void displayPairs()
 {
     foreach (var item in pairs)
     {
         var    option1 = OptionUtilities.getOptionByCode(optionList, item.option1);
         var    option2 = OptionUtilities.getOptionByCode(optionList, item.option2);
         var    price1  = optionPrice[option1.optionCode];
         var    price2  = optionPrice[option2.optionCode];
         double delta   = price1.delta - price2.delta;
         double gamma   = price1.gamma - price2.gamma;
         double vega    = price1.vega - price2.vega;
         double theta   = price1.theta - price2.theta;
         Console.WriteLine("代码:{0}, 名称:{1}, 价格:{2} ask:{3}  bid:{4}, 波动率:{5}", option1.optionCode, option1.optionName, optionPrice[option1.optionCode].lastPrice, optionPrice[option1.optionCode].ask, optionPrice[option1.optionCode].bid, price1.impv);
         Console.WriteLine("代码:{0}, 名称:{1}, 价格:{2} ask:{3}  bid:{4}, 波动率:{5}", option2.optionCode, option2.optionName, optionPrice[option2.optionCode].lastPrice, optionPrice[option2.optionCode].ask, optionPrice[option2.optionCode].bid, price2.impv);
         Console.WriteLine("mark:{0}, delta:{1}, gamma:{2}, vega:{3}, theta:{4}, profit:{5}, loss:{6}", item.mark, delta, gamma, vega, theta, item.profit, item.loss);
         Console.WriteLine("==============================================");
     }
 }
예제 #10
0
        private StraddlePairCode getStraddlePairCode(List <OptionInfo> optionInfoList, double durationFront, double durationNext, double etfPrice, DateTime today)
        {
            StraddlePairCode pair = new StraddlePairCode();
            var call = OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, durationFront), "认购").OrderBy(x => Math.Abs(x.strike - etfPrice)).Where(x => x.startDate <= today).ToList();

            pair.callCodeFront = call[0].optionCode;
            var callATM = call[0];
            var put     = OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, durationFront), "认沽").OrderBy(x => Math.Abs(x.strike - callATM.strike)).ToList();

            pair.putCodeFront = put[0].optionCode;
            var callNext = OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, durationNext), "认购").OrderBy(x => Math.Abs(x.strike - callATM.strike)).Where(x => x.startDate <= today).ToList();

            pair.callCodeNext = callNext[0].optionCode;
            var putNext = OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, durationNext), "认沽").OrderBy(x => Math.Abs(x.strike - callATM.strike)).ToList();

            pair.putCodeNext = putNext[0].optionCode;
            return(pair);
        }
        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)
            {
                var list = infoRepo.GetStockOptionInfo(underlying, date, date);
                list       = OptionUtilities.modifyOptionListByETFBonus(list, date);
                parityList = new List <StockOptionParity>();
                foreach (var item in list)
                {
                    if (item.type == "认购" && item.expireDate <= date.AddDays(180) && item.listedDate <= date)
                    {
                        var parity = StockOptionExtension.GetParity(list, item);
                        Console.WriteLine("Date {0}: strike {1} expireDate {2} option1 {3} option2 {4}", date, item.strike, item.expireDate, item.name, parity.name);
                        var pair = new StockOptionParity {
                            call = item.code, put = parity.code, strike = item.strike, expireDate = item.expireDate, unit = item.unit
                        };
                        parityList.Add(pair);
                    }
                }
                compute(date);
            }
        }
예제 #12
0
        protected void Page_Load(object sender, EventArgs e)
        {
            RoleUtilities   roleUtilities   = new RoleUtilities();
            OptionUtilities optionUtilities = new OptionUtilities();

            if (Request.HttpMethod == "POST")
            {
                string roleName    = rolename.Value;
                string groupOption = groupoptions.Value;
                string roleType    = Request.Form["type"];
                string roleLink    = rolelink.Value;
                if (!string.IsNullOrEmpty(roleName) || !string.IsNullOrEmpty(groupOption) || !string.IsNullOrEmpty(roleType))
                {
                    string result = roleUtilities.InsertRole(roleName, groupOption, roleType, roleLink);
                    if (result == "Success")
                    {
                        ClearFields();
                        toastrUtilities.SessionPush("toast", new KeyValuePair <string, string>("success", $"{roleName} Successfully Added."));
                    }
                    else
                    {
                        toastrUtilities.SessionPush("toast", new KeyValuePair <string, string>("error", $"An Error Occured Please Contact System Administrator."));
                    }
                }
                else
                {
                    toastrUtilities.SessionPush("toast", new KeyValuePair <string, string>("error", $"Please fill up all Fields."));
                }
            }
            ListItem[] gOptions = optionUtilities.GetGroupOptions();
            groupoptions.Items.Clear();
            groupoptions.Items.AddRange(gOptions);
            sgroupoptions.Items.Clear();
            sgroupoptions.Items.AddRange(gOptions);
            editgroupoptions.Items.Clear();
            editgroupoptions.Items.AddRange(gOptions);
            ShowRoles(roleUtilities.GetRoles());
        }
예제 #13
0
        public void compute()
        {
            log.Info("开始回测(回测期{0}到{1})", Kit.ToInt_yyyyMMdd(startdate), Kit.ToInt_yyyyMMdd(endDate));
            var repo           = Platforms.container.Resolve <OptionInfoRepository>();
            var OptionInfoList = repo.fetchFromLocalCsvOrWindAndSaveAndCache(1);

            Caches.put("OptionInfo", OptionInfoList);
            List <DateTime> tradeDays = DateUtils.GetTradeDays(startdate, endDate);

            //var ETFDaily = Platforms.container.Resolve<StockDailyRepository>().fetchFromLocalCsvOrWindAndSave("510050.SH", Kit.ToDate(20150101),Kit.ToDate(20160731));
            foreach (var day in tradeDays)
            {
                Dictionary <string, List <KLine> > data = new Dictionary <string, List <KLine> >();
                var             list        = OptionUtilities.getOptionListByDate(OptionInfoList, Kit.ToInt_yyyyMMdd(day));
                List <DateTime> durationArr = OptionUtilities.getEndDateListByAscending(list);
                var             ETFtoday    = Platforms.container.Resolve <StockMinuteRepository>().fetchFromLocalCsvOrWindAndSave("510050.SH", day);
                data.Add("510050.SH", ETFtoday.Cast <KLine>().ToList());
                foreach (var info in list)
                {
                    string IHCode      = OptionUtilities.getCorrespondingIHCode(info, Kit.ToInt_yyyyMMdd(day));
                    var    repoOption  = Platforms.container.Resolve <OptionMinuteRepository>();
                    var    optionToday = repoOption.fetchFromLocalCsvOrWindAndSave(info.optionCode, day);
                    data.Add(info.optionCode, optionToday.Cast <KLine>().ToList());
                }
                int index = 0;
                SortedDictionary <DateTime, Dictionary <string, MinutePositions> > positions = new SortedDictionary <DateTime, Dictionary <string, MinutePositions> >();
                while (index < 240)
                {
                    int      nextIndex = index + 1;
                    DateTime now       = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(day), index);
                    Dictionary <string, MinuteSignal> signal = new Dictionary <string, MinuteSignal>();
                    double        etfPrice       = ETFtoday[index].close;
                    List <double> strikeTodayArr = OptionUtilities.getStrikeListByAscending(list).OrderBy(x => Math.Abs(x - etfPrice)).ToList();
                    try
                    {
                        OptionInfo   callCandidateFront = OptionUtilities.getSpecifiedOption(list, durationArr[0], "认购", strikeTodayArr[0])[0];
                        OptionInfo   putCandidateFront  = OptionUtilities.getSpecifiedOption(list, durationArr[0], "认沽", strikeTodayArr[0])[0];
                        OptionInfo   callCandidateNext  = OptionUtilities.getSpecifiedOption(list, durationArr[1], "认购", strikeTodayArr[0])[0];
                        OptionInfo   putCandidateNext   = OptionUtilities.getSpecifiedOption(list, durationArr[1], "认沽", strikeTodayArr[0])[0];
                        MinuteSignal callFront          = new MinuteSignal()
                        {
                            code = callCandidateFront.optionCode, volume = -1, time = now, tradingVarieties = "option", price = data[callCandidateFront.optionCode][index].close, minuteIndex = index
                        };
                        MinuteSignal putFront = new MinuteSignal()
                        {
                            code = putCandidateFront.optionCode, volume = -1, time = now, tradingVarieties = "option", price = data[putCandidateFront.optionCode][index].close, minuteIndex = index
                        };
                        MinuteSignal callNext = new MinuteSignal()
                        {
                            code = callCandidateNext.optionCode, volume = 1, time = now, tradingVarieties = "option", price = data[callCandidateNext.optionCode][index].close, minuteIndex = index
                        };
                        MinuteSignal putNext = new MinuteSignal()
                        {
                            code = putCandidateNext.optionCode, volume = 1, time = now, tradingVarieties = "option", price = data[putCandidateNext.optionCode][index].close, minuteIndex = index
                        };
                        signal.Add(callFront.code, callFront);
                        signal.Add(putFront.code, putFront);
                        signal.Add(callNext.code, callNext);
                        signal.Add(putNext.code, putNext);
                        DateTime next = MinuteTransactionWithSlip.computeMinutePositions(signal, data, ref positions, slipPoint: 0.01, now: now);
                        nextIndex = Math.Max(nextIndex, TimeListUtility.MinuteToIndex(next));
                    }
                    catch (Exception)
                    {
                        throw;
                    }

                    index = nextIndex;
                }
            }
        }
 private void computeImpv()
 {
     optionVol = new double[etfDailyData.Count()];
     for (int i = startIndex; i < etfDailyData.Count(); i++)
     {
         DateTime today    = etfDailyData[i].time;
         double   etfPrice = etfDailyData[i].close;
         double   volThisMonth;
         double   volNextMonth;
         double   duration;
         //获取当日期限结构,选取当月合约
         List <double> dateStructure = OptionUtilities.getDurationStructure(optionInfoList, today);
         double        duration0     = dateStructure[0] == 0 ? dateStructure[1] : dateStructure[0];
         duration = duration0;
         var    call      = OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认购").OrderBy(x => Math.Abs(x.strike - etfPrice)).Where(x => x.startDate <= today).ToList();
         var    callATM   = call[0];
         var    callPrice = Platforms.container.Resolve <OptionDailyRepository>().fetchFromLocalCsvOrWindAndSave(callATM.optionCode, today, today);
         double callImpv  = ImpliedVolatilityUtilities.ComputeImpliedVolatility(callATM.strike, duration / 252.0, 0.04, 0, callATM.optionType, callPrice[0].close, etfPrice);
         var    put       = OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认沽").OrderBy(x => Math.Abs(x.strike - callATM.strike)).ToList();
         var    putATM    = put[0];
         var    putPrice  = Platforms.container.Resolve <OptionDailyRepository>().fetchFromLocalCsvOrWindAndSave(putATM.optionCode, today, today);
         double putImpv   = ImpliedVolatilityUtilities.ComputeImpliedVolatility(putATM.strike, duration / 252.0, 0.04, 0, putATM.optionType, putPrice[0].close, etfPrice);
         if (callImpv * putImpv == 0)
         {
             volThisMonth = callImpv + putImpv;
         }
         else
         {
             volThisMonth = (callImpv + putImpv) / 2;
         }
         //获取当日期限结构,选取下月合约,若下月合约不存在,就获取季月合约
         double duration1 = dateStructure[0] == 0 ? dateStructure[2] : dateStructure[1];
         duration  = duration1;
         call      = OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认购").OrderBy(x => Math.Abs(x.strike - etfPrice)).Where(x => x.startDate <= today).ToList();
         callATM   = call[0];
         callPrice = Platforms.container.Resolve <OptionDailyRepository>().fetchFromLocalCsvOrWindAndSave(callATM.optionCode, today, today);
         callImpv  = ImpliedVolatilityUtilities.ComputeImpliedVolatility(callATM.strike, duration / 252.0, 0.04, 0, callATM.optionType, callPrice[0].close, etfPrice);
         put       = OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认沽").OrderBy(x => Math.Abs(x.strike - callATM.strike)).ToList();
         putATM    = put[0];
         putPrice  = Platforms.container.Resolve <OptionDailyRepository>().fetchFromLocalCsvOrWindAndSave(putATM.optionCode, today, today);
         putImpv   = ImpliedVolatilityUtilities.ComputeImpliedVolatility(putATM.strike, duration / 252.0, 0.04, 0, putATM.optionType, putPrice[0].close, etfPrice);
         if (callImpv * putImpv == 0)
         {
             volNextMonth = callImpv + putImpv;
         }
         else
         {
             volNextMonth = (callImpv + putImpv) / 2;
         }
         if (duration0 >= step)
         {
             optionVol[i] = Math.Sqrt(step / duration0) * volThisMonth;
         }
         else if ((duration0 < step && duration1 > step))
         {
             optionVol[i] = Math.Sqrt((duration1 - step) / (duration1 - duration0)) * volThisMonth + Math.Sqrt((step - duration0) / (duration1 - duration0)) * volNextMonth;
         }
         else if (duration1 <= step)
         {
             optionVol[i] = volNextMonth;
         }
     }
 }
        public void compute()
        {
            log.Info("开始回测(回测期{0}到{1})", Kit.ToInt_yyyyMMdd(startDate), Kit.ToInt_yyyyMMdd(endDate));
            var repo = Platforms.container.Resolve <OptionInfoRepository>();

            optionInfoList = repo.fetchFromLocalCsvOrWindAndSaveAndCache(1);
            Caches.put("OptionInfo", optionInfoList);
            //初始化头寸信息
            SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> > positions = new SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> >();
            //初始化(宽)跨式组合信息
            SortedDictionary <DateTime, List <StranglePair> > pairs = new SortedDictionary <DateTime, List <StranglePair> >();
            //初始化Account信息
            BasicAccount myAccount = new BasicAccount();

            myAccount.initialAssets = initialCapital;
            myAccount.totalAssets   = initialCapital;
            myAccount.freeCash      = myAccount.totalAssets;
            //记录历史账户信息
            List <BasicAccount> accountHistory = new List <BasicAccount>();
            List <double>       benchmark      = new List <double>();

            //50ETF的日线数据准备,从回测期开始之前100个交易开始取
            int number = 100;
            List <StockDaily> dailyData = new List <StockDaily>();

            dailyData = Platforms.container.Resolve <StockDailyRepository>().fetchFromLocalCsvOrWindAndSave(targetVariety, DateUtils.PreviousTradeDay(startDate, number), endDate);
            var closePrice = dailyData.Select(x => x.close).ToArray();

            //按交易日回测
            for (int day = 0; day < tradeDays.Count(); day++)
            {
                benchmark.Add(closePrice[day + number]);
                double lastETFPrice = dailyData[number + day - 1].close;
                var    today        = tradeDays[day];
                //获取当日上市的期权合约列表
                var optionInfoList2 = OptionUtilities.getUnmodifiedOptionInfoList(this.optionInfoList, today);
                //初始化信号的数据结构
                Dictionary <string, MinuteSignal> signal = new Dictionary <string, MinuteSignal>();
                //获取今日日内50ETF数据
                var etfData = Platforms.container.Resolve <StockMinuteRepository>().fetchFromLocalCsvOrWindAndSave(targetVariety, tradeDays[day]);
                //初始化行情信息,将50ETF的价格放入dataToday
                Dictionary <string, List <KLine> > dataToday = new Dictionary <string, List <KLine> >();
                dataToday.Add(targetVariety, etfData.Cast <KLine>().ToList());
                //记录今日账户信息
                myAccount.time = today;

                //获取今日期权的到期日期
                var dateStructure = OptionUtilities.getDurationStructure(optionInfoList2, tradeDays[day]);
                //选定到日期在40个交易日至60个交易日的合约
                double duration = 0;
                for (int i = 0; i < dateStructure.Count(); i++)
                {
                    if (dateStructure[i] >= 40 && dateStructure[i] <= 80)
                    {
                        duration = dateStructure[i];
                        break;
                    }
                }
                for (int index = 0; index < 234; index++) //遍历日内的逐个分钟(不包括最后5分钟)
                {
                    signal = new Dictionary <string, MinuteSignal>();
                    DateTime now         = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(tradeDays[day]), index);
                    double   etfPriceNow = etfData[index].open;
                    //策略思路,当前没有持仓的时候开仓,如果有持仓就判断需不需要止盈或者换月
                    if (pairs.Count == 0 || (pairs.Count > 0 && pairs.Last().Value.Last().closePrice != 0)) //没有持仓则开仓,简单的在开盘1分钟的时候开仓
                    {
                        signal = new Dictionary <string, MinuteSignal>();
                        //今日没有合适的期权合约
                        if (duration == 0)
                        {
                            continue;
                        }
                        openStrangle(ref dataToday, ref signal, ref positions, ref myAccount, ref pairs, today, index, duration);
                    }

                    StranglePair pair        = pairs.Last().Value.Last();
                    double       durationNow = DateUtils.GetSpanOfTradeDays(today, pair.endDate);
                    //如果有持仓,通过以下手段记录每日分钟信息
                    if ((pairs.Count > 0 && pairs.Last().Value.Last().closePrice == 0) && (dataToday.ContainsKey(pair.callCode) == false || dataToday.ContainsKey(pair.putCode) == false))
                    {
                        tradeAssistant(ref dataToday, ref signal, pair.callCode, 0, today, now, index);
                        tradeAssistant(ref dataToday, ref signal, pair.putCode, 0, today, now, index);
                        var callInfo = OptionUtilities.getOptionByCode(optionInfoList2, pair.callCode);
                        if (today.AddDays(1) >= callInfo.modifiedDate && !(today.AddDays(-10000) > callInfo.modifiedDate))
                        {
                            closeStrangle(ref dataToday, ref signal, ref positions, ref myAccount, ref pairs, today, index);
                        }
                    }

                    //检查每一个跨式或者宽跨式组合,看看需不需要调整
                    if (durationNow < 10 && etfPriceNow < pair.callStrike + motion && etfPriceNow > pair.putStrike - motion) //不用调仓直接平仓
                    {
                        closeStrangle(ref dataToday, ref signal, ref positions, ref myAccount, ref pairs, today, index);
                    }
                    else if (durationNow < 20 && !(etfPriceNow < pair.callStrike + motion && etfPriceNow > pair.putStrike - motion)) //跨期调仓
                    {
                        //先进行平仓,然后开仓
                        closeStrangle(ref dataToday, ref signal, ref positions, ref myAccount, ref pairs, today, index);//平仓
                        signal = new Dictionary <string, MinuteSignal>();
                        StranglePair newPair = new StranglePair();
                        if (etfPriceNow > pair.callStrike + motion)
                        {
                            OptionInfo call = getOptionCode(duration, etfPriceNow, "认购", today);
                            OptionInfo put  = getOptionCode(duration, pair.putStrike, "认沽", today);
                            if (call.strike != 0 && put.strike != 0) //开仓
                            {
                                newPair = new StranglePair()
                                {
                                    callCode = call.optionCode, callStrike = call.strike, callPosition = call.contractMultiplier, putCode = put.optionCode, putStrike = put.strike, putPosition = put.contractMultiplier, closeDate = new DateTime(), closePrice = 0, endDate = call.endDate, etfPrice = etfPriceNow, modifiedDate = today, strangleOpenPrice = dataToday[call.optionCode][index].open + dataToday[put.optionCode][index].open
                                };
                                modifyStrangle(ref dataToday, ref signal, ref positions, ref myAccount, ref pairs, ref newPair, today, index);
                            }
                        }
                        else if (etfPriceNow < pair.putStrike - motion)
                        {
                            OptionInfo call = getOptionCode(duration, pair.callStrike, "认购", today);
                            OptionInfo put  = getOptionCode(duration, etfPriceNow, "认沽", today);
                            if (call.strike != 0 && put.strike != 0) //开仓
                            {
                                newPair = new StranglePair()
                                {
                                    callCode = call.optionCode, callStrike = call.strike, callPosition = call.contractMultiplier, putCode = put.optionCode, putStrike = put.strike, putPosition = put.contractMultiplier, closeDate = new DateTime(), closePrice = 0, endDate = call.endDate, etfPrice = etfPriceNow, modifiedDate = today, strangleOpenPrice = dataToday[call.optionCode][index].open + dataToday[put.optionCode][index].open
                                };
                                modifyStrangle(ref dataToday, ref signal, ref positions, ref myAccount, ref pairs, ref newPair, today, index);
                            }
                        }
                    }
                    else if (durationNow >= 20 && !(etfPriceNow < pair.callStrike + motion && etfPriceNow > pair.putStrike - motion)) //不跨期调仓
                    {
                        if (etfPriceNow > pair.callStrike + motion)
                        {
                            //认购期权向上移仓
                            OptionInfo call = getOptionCode(durationNow, etfPriceNow, "认购", today);
                            if (call.strike != 0)
                            {
                                tradeAssistant(ref dataToday, ref signal, pair.putCode, 0, today, now, index);
                                tradeAssistant(ref dataToday, ref signal, pair.callCode, -pair.callPosition, today, now, index);
                                tradeAssistant(ref dataToday, ref signal, call.optionCode, call.contractMultiplier, today, now, index);
                                pair.closeDate  = now;
                                pair.closePrice = dataToday[pair.callCode][index].open + dataToday[pair.putCode][index].open;
                                StranglePair newPair = new StranglePair()
                                {
                                    callCode = call.optionCode, callStrike = call.strike, callPosition = call.contractMultiplier, putCode = pair.putCode, putStrike = pair.putStrike, putPosition = pair.putPosition, closeDate = new DateTime(), closePrice = 0, endDate = call.endDate, etfPrice = etfPriceNow, modifiedDate = now, strangleOpenPrice = dataToday[call.optionCode][index].open + dataToday[pair.putCode][index].open
                                };
                                pairs.Last().Value.Add(newPair);
                                MinuteTransactionWithBar.ComputePosition(signal, dataToday, ref positions, ref myAccount, slipPoint: slipPoint, now: now, nowIndex: index);
                            }
                        }
                        else if (etfPriceNow < pair.putStrike - motion)
                        {
                            //认沽期权向下移仓
                            OptionInfo put = getOptionCode(durationNow, etfPriceNow, "认沽", today);
                            if (put.strike != 0)
                            {
                                tradeAssistant(ref dataToday, ref signal, pair.callCode, 0, today, now, index);
                                tradeAssistant(ref dataToday, ref signal, pair.putCode, -pair.putPosition, today, now, index);
                                tradeAssistant(ref dataToday, ref signal, put.optionCode, put.contractMultiplier, today, now, index);
                                pair.closeDate  = now;
                                pair.closePrice = dataToday[pair.callCode][index].open + dataToday[pair.putCode][index].open;
                                StranglePair newPair = new StranglePair()
                                {
                                    callCode = pair.callCode, callStrike = pair.callStrike, callPosition = pair.callPosition, putCode = put.optionCode, putStrike = put.strike, putPosition = put.contractMultiplier, closeDate = new DateTime(), closePrice = 0, endDate = put.endDate, etfPrice = etfPriceNow, modifiedDate = now, strangleOpenPrice = dataToday[pair.callCode][index].open + dataToday[put.optionCode][index].open
                                };
                                pairs.Last().Value.Add(newPair);
                                MinuteTransactionWithBar.ComputePosition(signal, dataToday, ref positions, ref myAccount, slipPoint: slipPoint, now: now, nowIndex: index);
                            }
                        }
                    }
                }
                if (etfData.Count > 0)
                {
                    //更新当日属性信息

                    AccountOperator.Minute.maoheng.AccountUpdatingWithMinuteBar.computeAccount(ref myAccount, positions, etfData.Last().time, etfData.Count() - 1, dataToday);

                    //记录历史仓位信息
                    accountHistory.Add(new BasicAccount(myAccount.time, myAccount.totalAssets, myAccount.freeCash, myAccount.positionValue, myAccount.margin, myAccount.initialAssets));
                    benchmark.Add(etfData.Last().close);
                    if (netValue.Count() == 0)
                    {
                        netValue.Add(new NetValue {
                            time = today, netvalueReturn = 0, benchmarkReturn = 0, netvalue = myAccount.totalAssets, benchmark = etfData.Last().close
                        });
                    }
                    else
                    {
                        var netValueLast = netValue.Last();
                        netValue.Add(new NetValue {
                            time = today, netvalueReturn = myAccount.totalAssets / netValueLast.netvalue - 1, benchmarkReturn = etfData.Last().close / netValueLast.benchmark - 1, netvalue = myAccount.totalAssets, benchmark = etfData.Last().close
                        });
                    }
                }
            }
            //策略绩效统计及输出
            PerformanceStatisics myStgStats = new PerformanceStatisics();

            myStgStats = PerformanceStatisicsUtils.compute(accountHistory, positions);
            //画图
            Dictionary <string, double[]> line = new Dictionary <string, double[]>();

            double[] netWorth = accountHistory.Select(a => a.totalAssets / initialCapital).ToArray();
            line.Add("NetWorth", netWorth);
            //记录净值数据
            RecordUtil.recordToCsv(accountHistory, GetType().FullName, "account", parameters: "strangle", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //记录持仓变化
            var positionStatus = OptionRecordUtil.Transfer(positions);

            RecordUtil.recordToCsv(positionStatus, GetType().FullName, "positions", parameters: "strangle", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //记录统计指标
            var performanceList = new List <PerformanceStatisics>();

            performanceList.Add(myStgStats);
            RecordUtil.recordToCsv(performanceList, GetType().FullName, "performance", parameters: "strangle", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //统计指标在console 上输出
            Console.WriteLine("--------Strategy Performance Statistics--------\n");
            Console.WriteLine(" netProfit:{0,5:F4} \n totalReturn:{1,-5:F4} \n anualReturn:{2,-5:F4} \n anualSharpe :{3,-5:F4} \n winningRate:{4,-5:F4} \n PnLRatio:{5,-5:F4} \n maxDrawDown:{6,-5:F4} \n maxProfitRatio:{7,-5:F4} \n informationRatio:{8,-5:F4} \n alpha:{9,-5:F4} \n beta:{10,-5:F4} \n averageHoldingRate:{11,-5:F4} \n", myStgStats.netProfit, myStgStats.totalReturn, myStgStats.anualReturn, myStgStats.anualSharpe, myStgStats.winningRate, myStgStats.PnLRatio, myStgStats.maxDrawDown, myStgStats.maxProfitRatio, myStgStats.informationRatio, myStgStats.alpha, myStgStats.beta, myStgStats.averageHoldingRate);
            Console.WriteLine("-----------------------------------------------\n");

            //benchmark净值
            List <double> netWorthOfBenchmark = benchmark.Select(x => x / benchmark[0]).ToList();

            line.Add("Base", netWorthOfBenchmark.ToArray());
            string[] datestr = accountHistory.Select(a => a.time.ToString("yyyyMMdd")).ToArray();

            //maoheng 画图
            //Application.Run(new PLChart(line, datestr));

            //cuixun 画图
            //绘制图形的标题
            string formTitle = this.startDate.ToShortDateString() + "--" + this.endDate.ToShortDateString() + "  " + this.targetVariety + " 净值曲线"
                               + "\r\n" + "\r\n" + "净利润:" + myStgStats.netProfit + "  " + "夏普率:" + myStgStats.anualSharpe + "  " + "最大回撤:" + myStgStats.maxDrawDown
                               + "\r\n" + "\r\n";
            //生成图像
            PLChart plc = new PLChart(line, datestr, formTitle: formTitle);

            //运行图像
            //Application.Run(plc);
            plc.LoadForm();
            //保存图像
            plc.SaveZed(GetType().FullName, this.targetVariety, this.startDate, this.endDate, myStgStats.netProfit.ToString(), myStgStats.anualSharpe.ToString(), myStgStats.maxDrawDown.ToString());
        }
예제 #16
0
        public void compute()
        {
            //初始化头寸信息
            SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> > positions = new SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> >();
            //初始化Account信息
            BasicAccount myAccount = new BasicAccount(initialAssets: initialCapital, totalAssets: initialCapital, freeCash: initialCapital);
            //记录历史账户信息
            List <BasicAccount> accountHistory = new List <BasicAccount>();
            List <double>       benchmark      = new List <double>();
            //标记当日跨式组合多空信号。1表示多头,0表示无信号,-1表示空头。
            double       orignalSignal = 0;
            StraddlePair holdingStatus = new StraddlePair();

            //统计历史波动率分位数,从回测期开始前一天,统计到最后一天
            double[][] fractile = new double[backTestingDuration + 1][];
            fractile = computeRollingFractile(startIndex - 1, etfDailyData.Count() - 1, 100);
            //统计隐含波动率
            computeImpv();
            //统计隐含波动率和历史波动率之差 epsilon=max[E(IV-HV),0]
            computeEpsilon();
            //按时间遍历,2015年02月09日50ETF期权上市开始,2月10日开始昨日收盘的隐含波动率数据。
            for (int i = startIndex + 1; i < startIndex + backTestingDuration; i++)
            {
                DateTime today = etfDailyData[i].time;
                //获取当日上市的期权合约列表
                var optionInfoList = OptionUtilities.getUnmodifiedOptionInfoList(this.optionInfoList, today);
                //若当日发生50ETF分红派息,myAccount要加上分红的钱,并且需要调整持有头寸的strike
                if (today == timeOf50ETFDividend2016 && positions.Count > 0 && positions.Last().Value.ContainsKey("510050.SH"))
                {
                    //50ETF的头寸中记入分红
                    positions.Last().Value["510050.SH"].totalCashFlow += positions.Last().Value["510050.SH"].volume * bonusOf50ETFDividend2016;
                    //期权持仓行权价调整
                    foreach (var item in optionInfoList)
                    {
                        if (item.optionCode == holdingStatus.callCodeFront)
                        {
                            holdingStatus.strike             = item.strike;
                            holdingStatus.callPositionFront *= item.contractMultiplier / standardContractMultiplier;
                            holdingStatus.putPositionFront  *= item.contractMultiplier / standardContractMultiplier;
                            holdingStatus.callPositionNext  *= item.contractMultiplier / standardContractMultiplier;
                            holdingStatus.putPositionNext   *= item.contractMultiplier / standardContractMultiplier;
                        }
                    }
                }
                Dictionary <string, MinuteSignal> signal = new Dictionary <string, MinuteSignal>();
                double fractile90Yesterday = fractile[i - 1][9]; //昨日历史波动率90分位数
                double fractile70Yesterday = fractile[i - 1][7]; //昨日历史波动率70分位数
                double fractile50Yesterday = fractile[i - 1][5]; //昨日历史波动率50分位数
                double fractile30Yesterday = fractile[i - 1][3]; //昨日历史波动率30分位数
                double volYesterday        = etfVol[i - 1];      //昨日历史波动率
                double impvYesterday       = optionVol[i - 1];   //昨日隐含波动率
                //获取当日ATM期权合约代码

                double etfPrice = etfDailyData[i].close;
                //获取当日期限结构,选取当月合约,若当日合约到日期小于等于3天,直接开仓下月合约
                List <double>    dateStructure = OptionUtilities.getDurationStructure(optionInfoList, today);
                double           durationFront = dateStructure[0] <= 3 ? dateStructure[1] : dateStructure[0];
                double           durationNext  = dateStructure[0] <= 3 ? dateStructure[2] : dateStructure[1];
                StraddlePairCode myPair        = getStraddlePairCode(optionInfoList, durationFront, durationNext, etfPrice, today);
                var callATM       = OptionUtilities.getOptionByCode(optionInfoList, myPair.callCodeFront);
                var callPrice     = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(callATM.optionCode, today);
                var putATM        = OptionUtilities.getOptionByCode(optionInfoList, myPair.putCodeFront);
                var putPrice      = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(putATM.optionCode, today);
                var callATMNext   = OptionUtilities.getOptionByCode(optionInfoList, myPair.callCodeNext);
                var callPriceNext = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(callATMNext.optionCode, today);
                var putATMNext    = OptionUtilities.getOptionByCode(optionInfoList, myPair.putCodeNext);
                var putPriceNext  = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(putATMNext.optionCode, today);
                //整合当日分钟线数据
                Dictionary <string, List <KLine> > dataToday = new Dictionary <string, List <KLine> >();
                var etfData = Platforms.container.Resolve <StockMinuteRepository>().fetchFromLocalCsvOrWindAndSave("510050.SH", today);
                dataToday.Add("510050.SH", etfData.Cast <KLine>().ToList());
                dataToday.Add(callATM.optionCode, callPrice.Cast <KLine>().ToList());
                dataToday.Add(putATM.optionCode, putPrice.Cast <KLine>().ToList());
                dataToday.Add(callATMNext.optionCode, callPriceNext.Cast <KLine>().ToList());
                dataToday.Add(putATMNext.optionCode, putPriceNext.Cast <KLine>().ToList());

                //策略信号处理
                //信号1
                //orignalSignal = 0;
                //if (volYesterday >= fractile70Yesterday)
                //{
                //    //卖出跨式期权
                //    orignalSignal = -1;
                //}
                //else if (impvYesterday < volYesterday)
                //{
                //    //买入跨式期权
                //    orignalSignal = 1;
                //}
                //else if (impvYesterday - volYesterday > epsilon[i - 1])
                //{
                //    //卖出跨式期权
                //    orignalSignal = -1;
                //}
                //信号2
                orignalSignal = 0;
                if (volYesterday - impvYesterday > 0 && volYesterday <= fractile50Yesterday)
                {
                    //买入跨式期权
                    orignalSignal = 1;
                }
                else if (impvYesterday - volYesterday > epsilon[i - 1])
                {
                    //卖出跨式期权
                    orignalSignal = -1;
                }

                //指定平仓时间为开盘第一个分钟。
                int      openIndex = 0;
                DateTime now       = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(today), openIndex);
                Console.WriteLine("time: {0}, 昨日历史波动率: {1}, 历史波动率70分位数: {2}, 昨日隐含波动率: {3}", now, volYesterday.ToString("N"), fractile70Yesterday.ToString("N"), optionVol[i - 1].ToString("N"));
                //如果有持仓先判断持仓状态和信号方向是否相同,如果不同先平仓
                if (holdingStatus.callPositionFront != 0)
                {
                    if (dataToday.ContainsKey(holdingStatus.callCodeFront) == false)
                    {
                        var callLastDayFront = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.callCodeFront, today);
                        dataToday.Add(holdingStatus.callCodeFront, callLastDayFront.Cast <KLine>().ToList());
                    }
                    if (dataToday.ContainsKey(holdingStatus.putCodeFront) == false)
                    {
                        var putLastDayFront = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.putCodeFront, today);
                        dataToday.Add(holdingStatus.putCodeFront, putLastDayFront.Cast <KLine>().ToList());
                    }
                    if (dataToday.ContainsKey(holdingStatus.callCodeNext) == false)
                    {
                        var callLastDayNext = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.callCodeNext, today);
                        dataToday.Add(holdingStatus.callCodeNext, callLastDayNext.Cast <KLine>().ToList());
                    }
                    if (dataToday.ContainsKey(holdingStatus.putCodeNext) == false)
                    {
                        var putLastDayNext = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.putCodeNext, today);
                        dataToday.Add(holdingStatus.putCodeNext, putLastDayNext.Cast <KLine>().ToList());
                    }
                    if (holdingStatus.callPositionFront * orignalSignal < 0) //仓位和信号相反,强制平仓
                    {
                        Console.WriteLine("平仓!");

                        MinuteCloseAllWithBar.CloseAllPosition(dataToday, ref positions, ref myAccount, now, openIndex, slipPoint);
                        holdingStatus = new StraddlePair();
                    }
                    if (DateUtils.GetSpanOfTradeDays(today, holdingStatus.endDate) <= 3) //有仓位无信号,判断是否移仓
                    {
                        Console.WriteLine("平仓!");
                        MinuteCloseAllWithBar.CloseAllPosition(dataToday, ref positions, ref myAccount, now, openIndex, slipPoint);
                        holdingStatus = new StraddlePair();
                    }
                }
                //指定开仓时间为开盘第10分钟。错开开平仓的时间。
                openIndex = 10;
                now       = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(today), openIndex);
                if (holdingStatus.callPositionFront == 0 && orignalSignal != 0) //无仓位有信号,开仓
                {
                    if (orignalSignal == 1)                                     //做多跨式期权
                    {
                        MinuteSignal openSignalCallFront = new MinuteSignal()
                        {
                            code = callATM.optionCode, volume = optionVolume, time = now, tradingVarieties = "option", price = callPrice[openIndex].open, minuteIndex = openIndex
                        };
                        MinuteSignal openSignalPutFront = new MinuteSignal()
                        {
                            code = putATM.optionCode, volume = optionVolume, time = now, tradingVarieties = "option", price = putPrice[openIndex].open, minuteIndex = openIndex
                        };
                        MinuteSignal openSignalCallNext = new MinuteSignal()
                        {
                            code = callATMNext.optionCode, volume = -optionVolume, time = now, tradingVarieties = "option", price = callPriceNext[openIndex].open, minuteIndex = openIndex
                        };
                        MinuteSignal openSignalPutNext = new MinuteSignal()
                        {
                            code = putATMNext.optionCode, volume = -optionVolume, time = now, tradingVarieties = "option", price = putPriceNext[openIndex].open, minuteIndex = openIndex
                        };
                        Console.WriteLine("做多跨式期权!");
                        signal.Add(callATM.optionCode, openSignalCallFront);
                        signal.Add(putATM.optionCode, openSignalPutFront);
                        signal.Add(callATMNext.optionCode, openSignalCallNext);
                        signal.Add(putATMNext.optionCode, openSignalPutNext);
                        //变更持仓状态
                        holdingStatus = new StraddlePair {
                            callCodeFront = callATM.optionCode, putCodeFront = putATM.optionCode, callCodeNext = callATMNext.optionCode, putCodeNext = putATMNext.optionCode, callPositionFront = optionVolume, putPositionFront = optionVolume, callPositionNext = -optionVolume, putPositionNext = -optionVolume, etfPrice_open = etfData[openIndex].open, straddlePairPrice_open = callPrice[openIndex].open + putPrice[openIndex].open - callPriceNext[openIndex].open - putPriceNext[openIndex].open, straddleOpenDate = today, endDate = callATM.endDate, strike = callATM.strike, endDateNext = callATMNext.endDate
                        };
                    }
                    else if (orignalSignal == -1) //做空跨式期权
                    {
                        MinuteSignal openSignalCall = new MinuteSignal()
                        {
                            code = callATM.optionCode, volume = -optionVolume, time = now, tradingVarieties = "option", price = callPrice[openIndex].open, minuteIndex = openIndex
                        };
                        MinuteSignal openSignalPut = new MinuteSignal()
                        {
                            code = putATM.optionCode, volume = -optionVolume, time = now, tradingVarieties = "option", price = putPrice[openIndex].open, minuteIndex = openIndex
                        };
                        MinuteSignal openSignalCallNext = new MinuteSignal()
                        {
                            code = callATMNext.optionCode, volume = optionVolume, time = now, tradingVarieties = "option", price = callPriceNext[openIndex].open, minuteIndex = openIndex
                        };
                        MinuteSignal openSignalPutNext = new MinuteSignal()
                        {
                            code = putATMNext.optionCode, volume = optionVolume, time = now, tradingVarieties = "option", price = putPriceNext[openIndex].open, minuteIndex = openIndex
                        };
                        Console.WriteLine("做空跨式期权!");
                        signal.Add(callATM.optionCode, openSignalCall);
                        signal.Add(putATM.optionCode, openSignalPut);
                        signal.Add(callATMNext.optionCode, openSignalCallNext);
                        signal.Add(putATMNext.optionCode, openSignalPutNext);
                        //变更持仓状态
                        holdingStatus = new StraddlePair {
                            callCodeFront = callATM.optionCode, putCodeFront = putATM.optionCode, callCodeNext = callATMNext.optionCode, putCodeNext = putATMNext.optionCode, callPositionFront = -optionVolume, putPositionFront = -optionVolume, callPositionNext = optionVolume, putPositionNext = optionVolume, etfPrice_open = etfData[openIndex].open, straddlePairPrice_open = -callPrice[openIndex].open - putPrice[openIndex].open + callPriceNext[openIndex].open + putPriceNext[openIndex].open, straddleOpenDate = today, endDate = callATM.endDate, strike = callATM.strike, endDateNext = callATMNext.endDate
                        };
                    }
                    MinuteTransactionWithBar.ComputePosition(signal, dataToday, ref positions, ref myAccount, slipPoint: slipPoint, now: now, nowIndex: openIndex);
                }
                //每日收盘前,整理持仓情况
                int    thisIndex = 239;
                double delta     = 0;
                var    thisTime  = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(today), thisIndex);
                if (today >= timeOf50ETFDividend2016)
                {
                    benchmark.Add(etfData[thisIndex].close + bonusOf50ETFDividend2016);
                }
                else
                {
                    benchmark.Add(etfData[thisIndex].close);
                }
                if (holdingStatus.callPositionFront != 0)
                {
                    if (dataToday.ContainsKey(holdingStatus.callCodeFront) == false)
                    {
                        var callLastDayFront = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.callCodeFront, today);
                        dataToday.Add(holdingStatus.callCodeFront, callLastDayFront.Cast <KLine>().ToList());
                    }
                    if (dataToday.ContainsKey(holdingStatus.putCodeFront) == false)
                    {
                        var putLastDayFront = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.putCodeFront, today);
                        dataToday.Add(holdingStatus.putCodeFront, putLastDayFront.Cast <KLine>().ToList());
                    }
                    if (dataToday.ContainsKey(holdingStatus.callCodeNext) == false)
                    {
                        var callLastDayNext = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.callCodeNext, today);
                        dataToday.Add(holdingStatus.callCodeNext, callLastDayNext.Cast <KLine>().ToList());
                    }
                    if (dataToday.ContainsKey(holdingStatus.putCodeNext) == false)
                    {
                        var putLastDayNext = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.putCodeNext, today);
                        dataToday.Add(holdingStatus.putCodeNext, putLastDayNext.Cast <KLine>().ToList());
                    }
                    //计算期权delta值,并用50ETF对冲
                    //var positionLast = positions.Last().Value;
                    //delta= computeOptionDelta(positionLast, holdingStatus, today, dataToday, thisIndex);
                    //double etfChangeVolume =Math.Round( -delta - holdingStatus.etfPosition);
                    //MinuteSignal openSignalETF = new MinuteSignal() { code = "510050.SH", volume = etfChangeVolume, time = thisTime, tradingVarieties = "stock", price = dataToday["510050.SH"][thisIndex].open, minuteIndex = thisIndex };
                    //signal = new Dictionary<string, MinuteSignal>();
                    //signal.Add("510050.SH", openSignalETF);
                    //MinuteTransactionWithBar.ComputePosition(signal, dataToday, ref positions, ref myAccount, slipPoint: slipPoint, now: thisTime);
                    //holdingStatus.etfPosition += etfChangeVolume;
                    // AccountUpdatingForMinute.computeAccountUpdating(ref myAccount, positions, thisTime, dataToday);
                }

                //更新当日属性信息
                AccountUpdatingWithMinuteBar.computeAccount(ref myAccount, positions, thisTime, data: dataToday, nowIndex: thisIndex);

                //记录历史仓位信息
                accountHistory.Add(new BasicAccount(myAccount.time, myAccount.totalAssets, myAccount.freeCash, myAccount.positionValue, myAccount.margin, myAccount.initialAssets));
                //在控制台上数据每日持仓信息
                if (holdingStatus.callPositionFront != 0)
                {
                    Console.WriteLine("time: {0},etf: {1}, strike: {2}, position: {3}, call: {4}, put: {5}, endDate: {6}, delta: {7}, etfVolume: {8}", thisTime, etfData[thisIndex].close, holdingStatus.strike, holdingStatus.callPositionFront, dataToday[holdingStatus.callCodeFront][thisIndex].close, dataToday[holdingStatus.putCodeFront][thisIndex].close, holdingStatus.endDate, delta, holdingStatus.etfPosition);
                }
                //Console.WriteLine("time: {0}, total: {1}, cash: {2}, option: {3}, margin: {4}", thisTime, myAccount.totalAssets, myAccount.freeCash, myAccount.positionValue, myAccount.margin);
            }
            //策略绩效统计及输出
            PerformanceStatisics myStgStats = new PerformanceStatisics();

            myStgStats = PerformanceStatisicsUtils.compute(accountHistory, positions, benchmark.ToArray());
            //画图
            Dictionary <string, double[]> line = new Dictionary <string, double[]>();

            double[] netWorth = accountHistory.Select(a => a.totalAssets / initialCapital).ToArray();
            line.Add("NetWorth", netWorth);
            //记录净值数据
            RecordUtil.recordToCsv(accountHistory, GetType().FullName, "account", parameters: "straddle", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //记录持仓变化
            var positionStatus = OptionRecordUtil.Transfer(positions);

            RecordUtil.recordToCsv(positionStatus, GetType().FullName, "positions", parameters: "straddle", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //记录统计指标
            var performanceList = new List <PerformanceStatisics>();

            performanceList.Add(myStgStats);
            RecordUtil.recordToCsv(performanceList, GetType().FullName, "performance", parameters: "straddle", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //统计指标在console 上输出
            Console.WriteLine("--------Strategy Performance Statistics--------\n");
            Console.WriteLine(" netProfit:{0,5:F4} \n totalReturn:{1,-5:F4} \n anualReturn:{2,-5:F4} \n anualSharpe :{3,-5:F4} \n winningRate:{4,-5:F4} \n PnLRatio:{5,-5:F4} \n maxDrawDown:{6,-5:F4} \n maxProfitRatio:{7,-5:F4} \n informationRatio:{8,-5:F4} \n alpha:{9,-5:F4} \n beta:{10,-5:F4} \n averageHoldingRate:{11,-5:F4} \n", myStgStats.netProfit, myStgStats.totalReturn, myStgStats.anualReturn, myStgStats.anualSharpe, myStgStats.winningRate, myStgStats.PnLRatio, myStgStats.maxDrawDown, myStgStats.maxProfitRatio, myStgStats.informationRatio, myStgStats.alpha, myStgStats.beta, myStgStats.averageHoldingRate);
            Console.WriteLine("-----------------------------------------------\n");
            //benchmark净值
            List <double> netWorthOfBenchmark = benchmark.Select(x => x / benchmark[0]).ToList();

            line.Add("Base", netWorthOfBenchmark.ToArray());
            string[] datestr = accountHistory.Select(a => a.time.ToString("yyyyMMdd")).ToArray();
            Application.Run(new PLChart(line, datestr));
        }
        public void compute()
        {
            SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> > positions = new SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> >();
            //初始化Account信息
            BasicAccount myAccount = new BasicAccount();

            myAccount.initialAssets = initialCapital;
            myAccount.totalAssets   = initialCapital;
            myAccount.freeCash      = myAccount.totalAssets;
            //记录历史账户信息
            List <BasicAccount> accountHistory = new List <BasicAccount>();
            List <double>       benchmark      = new List <double>();
            //标记当日跨式组合多空信号。1表示多头,0表示无信号,-1表示空头。
            double   orignalSignal = 0;
            Straddle holdingStatus = new Straddle();

            //统计历史波动率分位数,从回测期开始前一天,统计到最后一天
            double[][] fractile = new double[backTestingDuration + 1][];
            fractile = computeRollingFractile(startIndex - 1, etfDailyData.Count() - 1, 100);
            //统计隐含波动率
            computeImpv();
            //统计隐含波动率和历史波动率之差 epsilon=max[E(IV-HV),0]
            computeEpsilon();
            //按时间遍历,2015年02月09日50ETF期权上市开始,2月10日开始昨日收盘的隐含波动率数据。
            for (int i = startIndex + 1; i < startIndex + backTestingDuration; i++)
            {
                Dictionary <string, MinuteSignal> signal = new Dictionary <string, MinuteSignal>();
                double fractile90Yesterday = fractile[i - 1][9]; //昨日历史波动率90分位数
                double fractile70Yesterday = fractile[i - 1][7]; //昨日历史波动率70分位数
                double fractile50Yesterday = fractile[i - 1][5]; //昨日历史波动率50分位数
                double fractile30Yesterday = fractile[i - 1][3]; //昨日历史波动率30分位数
                double volYesterday        = etfVol[i - 1];      //昨日历史波动率
                double impvYesterday       = optionVol[i - 1];   //昨日隐含波动率
                //获取当日ATM期权合约代码
                DateTime today    = etfDailyData[i].time;
                double   etfPrice = etfDailyData[i].close;
                double   duration;
                //获取当日期限结构,选取当月合约,若当日合约到日期小于等于3天,直接开仓下月合约
                List <double> dateStructure = OptionUtilities.getDurationStructure(optionInfoList, today);
                double        duration0     = dateStructure[0] <= 3 ? dateStructure[1] : dateStructure[0];
                duration = duration0;
                var call      = OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认购").OrderBy(x => Math.Abs(x.strike - etfPrice)).Where(x => x.startDate <= today).ToList();
                var callATM   = call[0];
                var callPrice = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(callATM.optionCode, today);
                // double callImpv = ImpliedVolatilityUtilities.ComputeImpliedVolatility(callATM.strike, duration / 252.0, 0.04, 0, callATM.optionType, callPrice[0].close, etfPrice);
                var put      = OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认沽").OrderBy(x => Math.Abs(x.strike - callATM.strike)).ToList();
                var putATM   = put[0];
                var putPrice = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(putATM.optionCode, today);
                //double putImpv = ImpliedVolatilityUtilities.ComputeImpliedVolatility(putATM.strike, duration / 252.0, 0.04, 0, putATM.optionType, putPrice[0].close, etfPrice);
                //整合当日分钟线数据
                Dictionary <string, List <KLine> > dataToday = new Dictionary <string, List <KLine> >();
                var etfData = Platforms.container.Resolve <StockMinuteRepository>().fetchFromLocalCsvOrWindAndSave("510050.SH", today);
                dataToday.Add("510050.SH", etfData.Cast <KLine>().ToList());
                dataToday.Add(callATM.optionCode, callPrice.Cast <KLine>().ToList());
                dataToday.Add(putATM.optionCode, putPrice.Cast <KLine>().ToList());

                //策略信号处理
                ////信号1
                //orignalSignal = 0;
                //if (volYesterday >= fractile70Yesterday)
                //{
                //    //卖出跨式期权
                //    orignalSignal = -1;
                //}
                //else if (optionVol[i - 1] < volYesterday)
                //{
                //    //买入跨式期权
                //    orignalSignal = 1;
                //}
                //else if (optionVol[i - 1] - volYesterday > epsilon[i - 1])
                //{
                //    //卖出跨式期权
                //    orignalSignal = -1;
                //}
                //信号2
                orignalSignal = 0;
                if (volYesterday - impvYesterday > 0 && volYesterday <= fractile70Yesterday)
                {
                    //买入跨式期权
                    //orignalSignal = 1;
                }
                else if (impvYesterday - volYesterday > 2 * epsilon[i - 1])
                {
                    //卖出跨式期权
                    orignalSignal = -1;
                }

                //指定平仓时间为开盘第一个分钟。
                DateTime now = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(today), 0);
                Console.WriteLine("time: {0}, 昨日历史波动率: {1}, 历史波动率70分位数: {2}, 昨日隐含波动率: {3}", now, volYesterday.ToString("N"), fractile70Yesterday.ToString("N"), optionVol[i - 1].ToString("N"));
                //如果有持仓先判断持仓状态和信号方向是否相同,如果不同先平仓
                if (holdingStatus.callPosition != 0)
                {
                    //平仓之前获取IH数据
                    if (holdingStatus.IHCode != null)
                    {
                        var IHData = Platforms.container.Resolve <FuturesMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.IHCode, today);
                        dataToday.Add(holdingStatus.IHCode, IHData.Cast <KLine>().ToList());
                    }
                    if (dataToday.ContainsKey(holdingStatus.callCode) == false)
                    {
                        var callLastDay = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.callCode, today);
                        dataToday.Add(holdingStatus.callCode, callLastDay.Cast <KLine>().ToList());
                    }
                    if (dataToday.ContainsKey(holdingStatus.putCode) == false)
                    {
                        var putLastDay = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.putCode, today);
                        dataToday.Add(holdingStatus.putCode, putLastDay.Cast <KLine>().ToList());
                    }
                    if (holdingStatus.callPosition * orignalSignal < 0) //仓位和信号相反,强制平仓
                    {
                        Console.WriteLine("平仓!");

                        MinuteCloseAllPositonsWithSlip.closeAllPositions(dataToday, ref positions, ref myAccount, now, slipPoint);
                        holdingStatus = new Straddle();
                    }
                    if (DateUtils.GetSpanOfTradeDays(today, holdingStatus.endDate) <= 3) //有仓位无信号,判断是否移仓
                    {
                        Console.WriteLine("平仓!");
                        MinuteCloseAllPositonsWithSlip.closeAllPositions(dataToday, ref positions, ref myAccount, now, slipPoint);
                        holdingStatus = new Straddle();
                    }
                }
                //指定开仓时间为开盘第10分钟。错开开平仓的时间。
                int openIndex = 10;
                now = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(today), openIndex);
                if (holdingStatus.callPosition == 0 && orignalSignal != 0) //无仓位有信号,开仓
                {
                    if (orignalSignal == 1)                                //做多跨式期权
                    {
                        MinuteSignal openSignalCall = new MinuteSignal()
                        {
                            code = callATM.optionCode, volume = optionVolume, time = now, tradingVarieties = "option", price = callPrice[openIndex].close, minuteIndex = openIndex
                        };
                        MinuteSignal openSignalPut = new MinuteSignal()
                        {
                            code = putATM.optionCode, volume = optionVolume, time = now, tradingVarieties = "option", price = putPrice[openIndex].close, minuteIndex = openIndex
                        };
                        Console.WriteLine("做多跨式期权!");
                        signal.Add(callATM.optionCode, openSignalCall);
                        signal.Add(putATM.optionCode, openSignalPut);
                        //变更持仓状态
                        holdingStatus.callCode           = callATM.optionCode;
                        holdingStatus.putCode            = putATM.optionCode;
                        holdingStatus.callPosition       = optionVolume;
                        holdingStatus.putPosition        = optionVolume;
                        holdingStatus.etfPrice_open      = etfData[openIndex].close;
                        holdingStatus.straddlePrice_open = callPrice[openIndex].close + putPrice[openIndex].close;
                        holdingStatus.straddleOpenDate   = today;
                        holdingStatus.endDate            = callATM.endDate;
                        holdingStatus.strike             = callATM.strike;
                    }
                    else if (orignalSignal == -1) //做空跨式期权
                    {
                        MinuteSignal openSignalCall = new MinuteSignal()
                        {
                            code = callATM.optionCode, volume = -optionVolume, time = now, tradingVarieties = "option", price = callPrice[openIndex].close, minuteIndex = openIndex
                        };
                        MinuteSignal openSignalPut = new MinuteSignal()
                        {
                            code = putATM.optionCode, volume = -optionVolume, time = now, tradingVarieties = "option", price = putPrice[openIndex].close, minuteIndex = openIndex
                        };
                        Console.WriteLine("做空跨式期权!");
                        signal.Add(callATM.optionCode, openSignalCall);
                        signal.Add(putATM.optionCode, openSignalPut);
                        //变更持仓状态
                        holdingStatus.callCode           = callATM.optionCode;
                        holdingStatus.putCode            = putATM.optionCode;
                        holdingStatus.callPosition       = -optionVolume;
                        holdingStatus.putPosition        = -optionVolume;
                        holdingStatus.etfPrice_open      = etfData[openIndex].close;
                        holdingStatus.straddlePrice_open = callPrice[openIndex].close + putPrice[openIndex].close;
                        holdingStatus.straddleOpenDate   = today;
                        holdingStatus.endDate            = callATM.endDate;
                        holdingStatus.strike             = callATM.strike;
                    }
                    MinuteTransactionWithSlip.computeMinuteOpenPositions(signal, dataToday, ref positions, ref myAccount, slipPoint: slipPoint, now: now, capitalVerification: false);
                }
                //每日收盘前,整理持仓情况
                int thisIndex = 239;
                var thisTime  = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(today), thisIndex);
                benchmark.Add(etfData[thisIndex].close);
                if (holdingStatus.callPosition != 0)
                {
                    if (dataToday.ContainsKey(holdingStatus.callCode) == false)
                    {
                        var callLastDay = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.callCode, today);
                        dataToday.Add(holdingStatus.callCode, callLastDay.Cast <KLine>().ToList());
                    }
                    if (dataToday.ContainsKey(holdingStatus.putCode) == false)
                    {
                        var putLastDay = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(holdingStatus.putCode, today);
                        dataToday.Add(holdingStatus.putCode, putLastDay.Cast <KLine>().ToList());
                    }
                    AccountUpdatingForMinute.computeAccountUpdating(ref myAccount, positions, thisTime, dataToday);
                }
                //更新当日属性信息
                AccountUpdatingForMinute.computeAccountUpdating(ref myAccount, positions, thisTime, dataToday);
                //记录历史仓位信息
                accountHistory.Add(new BasicAccount(myAccount.time, myAccount.totalAssets, myAccount.freeCash, myAccount.positionValue, myAccount.margin, myAccount.initialAssets));
                //在控制台上数据每日持仓信息
                if (holdingStatus.callPosition != 0)
                {
                    Console.WriteLine("time: {0},etf: {1}, strike: {2}, position: {3}, call: {4}, put: {5}, endDate: {6}", thisTime, etfData[thisIndex].close, holdingStatus.strike, holdingStatus.callPosition, dataToday[holdingStatus.callCode][thisIndex].close, dataToday[holdingStatus.putCode][thisIndex].close, holdingStatus.endDate);
                }
                //Console.WriteLine("time: {0}, total: {1}, cash: {2}, option: {3}, margin: {4}", thisTime, myAccount.totalAssets, myAccount.freeCash, myAccount.positionValue, myAccount.margin);
            }
            //策略绩效统计及输出
            PerformanceStatisics myStgStats = new PerformanceStatisics();

            myStgStats = PerformanceStatisicsUtils.compute(accountHistory, positions, benchmark.ToArray());
            //画图
            Dictionary <string, double[]> line = new Dictionary <string, double[]>();

            double[] netWorth = accountHistory.Select(a => a.totalAssets / initialCapital).ToArray();
            line.Add("NetWorth", netWorth);
            //记录净值数据
            RecordUtil.recordToCsv(accountHistory, GetType().FullName, "account", parameters: "straddle", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //记录持仓变化
            var positionStatus = OptionRecordUtil.Transfer(positions);

            RecordUtil.recordToCsv(positionStatus, GetType().FullName, "positions", parameters: "straddle", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //记录统计指标
            var performanceList = new List <PerformanceStatisics>();

            performanceList.Add(myStgStats);
            RecordUtil.recordToCsv(performanceList, GetType().FullName, "performance", parameters: "straddle", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //统计指标在console 上输出
            Console.WriteLine("--------Strategy Performance Statistics--------\n");
            Console.WriteLine(" netProfit:{0,5:F4} \n totalReturn:{1,-5:F4} \n anualReturn:{2,-5:F4} \n anualSharpe :{3,-5:F4} \n winningRate:{4,-5:F4} \n PnLRatio:{5,-5:F4} \n maxDrawDown:{6,-5:F4} \n maxProfitRatio:{7,-5:F4} \n informationRatio:{8,-5:F4} \n alpha:{9,-5:F4} \n beta:{10,-5:F4} \n averageHoldingRate:{11,-5:F4} \n", myStgStats.netProfit, myStgStats.totalReturn, myStgStats.anualReturn, myStgStats.anualSharpe, myStgStats.winningRate, myStgStats.PnLRatio, myStgStats.maxDrawDown, myStgStats.maxProfitRatio, myStgStats.informationRatio, myStgStats.alpha, myStgStats.beta, myStgStats.averageHoldingRate);
            Console.WriteLine("-----------------------------------------------\n");
            //benchmark净值
            List <double> netWorthOfBenchmark = benchmark.Select(x => x / benchmark[0]).ToList();

            line.Add("Base", netWorthOfBenchmark.ToArray());
            string[] datestr = accountHistory.Select(a => a.time.ToString("yyyyMMdd")).ToArray();
            Application.Run(new PLChart(line, datestr));
        }
예제 #18
0
        public void compute()
        {
            log.Info("开始回测(回测期{0}到{1})", Kit.ToInt_yyyyMMdd(startDate), Kit.ToInt_yyyyMMdd(endDate));
            var repo           = Platforms.container.Resolve <OptionInfoRepository>();
            var optionInfoList = repo.fetchFromLocalCsvOrWindAndSaveAndCache(1);

            Caches.put("OptionInfo", optionInfoList);

            SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> > positions = new SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> >();
            //初始化Account信息
            BasicAccount myAccount = new BasicAccount();

            myAccount.initialAssets = initialCapital;
            myAccount.totalAssets   = initialCapital;
            myAccount.freeCash      = myAccount.totalAssets;

            //记录历史账户信息
            List <BasicAccount> accountHistory = new List <BasicAccount>();
            List <double>       benchmark      = new List <double>();
            ///数据准备
            //记录牛市价差两条腿的信息
            BullSpread myLegs = new BullSpread();
            //交易日信息
            List <DateTime> tradeDays = DateUtils.GetTradeDays(startDate, endDate);
            //50ETF的日线数据准备,从回测期开始之前100个交易开始取
            int number = 100;
            List <StockDaily> dailyData = new List <StockDaily>();

            dailyData = Platforms.container.Resolve <StockDailyRepository>().fetchFromLocalCsvOrWindAndSave(targetVariety, DateUtils.PreviousTradeDay(startDate, number), endDate);
            //计算50ETF的EMA
            var           closePrice = dailyData.Select(x => x.close).ToArray();
            List <double> ema7       = TA_MA.EMA(closePrice, 5).ToList();
            List <double> ema50      = TA_MA.EMA(closePrice, 20).ToList();
            List <double> ema10      = TA_MA.EMA(closePrice, 10).ToList();
            double        maxProfit  = 0;

            for (int day = 1; day < tradeDays.Count(); day++)
            {
                benchmark.Add(closePrice[day + number]);
                var today = tradeDays[day];
                myAccount.time = today;
                var    dateStructure = OptionUtilities.getDurationStructure(optionInfoList, tradeDays[day]);
                double duration      = 0;
                for (int i = 0; i < dateStructure.Count(); i++)
                {
                    if (dateStructure[i] >= 20 && dateStructure[i] <= 40)
                    {
                        duration = dateStructure[i];
                        break;
                    }
                }
                Dictionary <string, MinuteSignal> signal = new Dictionary <string, MinuteSignal>();
                var etfData = Platforms.container.Resolve <StockMinuteRepository>().fetchFromLocalCsvOrWindAndSave(targetVariety, tradeDays[day]);
                if (ema7[day + number - 1] - ema50[day + number - 1] > 0 && dailyData[number + day - 1].close > ema10[day + number - 1] && myLegs.strike1 == 0) // EMA7日线大于EMA50日线,并且ETF价格站上EMA10,开牛市价差
                {
                    //取出指定日期
                    double lastETFPrice = dailyData[number + day - 1].close;
                    Dictionary <string, List <KLine> > dataToday = new Dictionary <string, List <KLine> >();
                    dataToday.Add(targetVariety, etfData.Cast <KLine>().ToList());
                    DateTime now = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(tradeDays[day]), 0);
                    //MinuteSignal openSignal = new MinuteSignal() { code = targetVariety, volume = 10000, time = now, tradingVarieties = "stock", price =averagePrice, minuteIndex = day };
                    //signal.Add(targetVariety, openSignal);
                    //选取指定的看涨期权
                    var list = OptionUtilities.getOptionListByDate(OptionUtilities.getOptionListByStrike(OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, tradeDays[day], duration), "认购"), lastETFPrice, lastETFPrice + 0.5), Kit.ToInt_yyyyMMdd(today)).OrderBy(x => x.strike).ToList();
                    //如果可以构成看涨期权牛市价差,就开仓
                    if (list.Count() >= 2)
                    {
                        var option1     = list[0];
                        var option2     = list[list.Count() - 1];
                        var option1Data = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(option1.optionCode, today);
                        var option2Data = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(option2.optionCode, today);
                        if ((option1Data[0].close > 0 && option2Data[0].close > 0) == true)
                        {
                            dataToday.Add(option1.optionCode, option1Data.Cast <KLine>().ToList());
                            dataToday.Add(option2.optionCode, option2Data.Cast <KLine>().ToList());
                            //var vol1 = ImpliedVolatilityUtilities.ComputeImpliedVolatility(option1.strike, duration / 252.0, 0.04, 0, option1.optionType, option1Data[0].close, etfData[0].close);
                            //var vol2 = ImpliedVolatilityUtilities.ComputeImpliedVolatility(option2.strike, duration / 252.0, 0.04, 0, option2.optionType, option2Data[0].close, etfData[0].close);
                            MinuteSignal openSignal1 = new MinuteSignal()
                            {
                                code = option1.optionCode, volume = 10000, time = now, tradingVarieties = "option", price = option1Data[0].close, minuteIndex = 0
                            };
                            MinuteSignal openSignal2 = new MinuteSignal()
                            {
                                code = option2.optionCode, volume = -10000, time = now, tradingVarieties = "option", price = option2Data[0].close, minuteIndex = 0
                            };
                            Console.WriteLine("开仓!");
                            signal.Add(option1.optionCode, openSignal1);
                            signal.Add(option2.optionCode, openSignal2);
                            myLegs.code1            = option1.optionCode;
                            myLegs.code2            = option2.optionCode;
                            myLegs.strike1          = option1.strike;
                            myLegs.strike2          = option2.strike;
                            myLegs.endDate          = option1.endDate;
                            myLegs.spreadPrice_Open = option1Data[0].close - option2Data[0].close;
                            myLegs.etfPrice_Open    = etfData[0].close;
                            myLegs.spreadOpenDate   = now;
                            maxProfit = 0;
                            Console.WriteLine("time: {0},etf: {1}, call1: {2} call1price: {3}, call2: {4}, call2price: {5}", now, etfData[0].close, myLegs.strike1, option1Data[0].close, myLegs.strike2, option2Data[0].close);
                        }
                    }
                    MinuteTransactionWithSlip.computeMinuteOpenPositions(signal, dataToday, ref positions, ref myAccount, slipPoint: slipPoint, now: now, capitalVerification: false);
                }
                if (positions.Count() > 0 && myLegs.strike1 != 0)
                {
                    Dictionary <string, List <KLine> > dataToday = new Dictionary <string, List <KLine> >();
                    dataToday.Add(targetVariety, etfData.Cast <KLine>().ToList());
                    var option1Data = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(myLegs.code1, today);
                    var option2Data = Platforms.container.Resolve <OptionMinuteRepository>().fetchFromLocalCsvOrWindAndSave(myLegs.code2, today);
                    dataToday.Add(myLegs.code1, option1Data.Cast <KLine>().ToList());
                    dataToday.Add(myLegs.code2, option2Data.Cast <KLine>().ToList());
                    int thisIndex   = 239;
                    var thisTime    = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(today), thisIndex);
                    var etfPriceNow = etfData[thisIndex].close;
                    var durationNow = DateUtils.GetSpanOfTradeDays(today, myLegs.endDate);
                    Console.WriteLine("time: {0},etf: {1}, call1: {2} call1price: {3}, call2: {4}, call2price: {5}", thisTime, etfPriceNow, myLegs.strike1, option1Data[thisIndex].close, myLegs.strike2, option2Data[thisIndex].close);
                    //多个退出条件①收益达到最大收益的60%以上②多日之内不上涨③迅速下跌
                    double spreadPrice = option1Data[thisIndex].close - option2Data[thisIndex].close;
                    maxProfit = (spreadPrice - myLegs.spreadPrice_Open) > maxProfit ? spreadPrice - myLegs.spreadPrice_Open : maxProfit;
                    double holdingDays = DateUtils.GetSpanOfTradeDays(myLegs.spreadOpenDate, today);
                    //止盈
                    bool profitTarget = (spreadPrice) > 0.6 * (myLegs.strike2 - myLegs.strike1) && durationNow >= 10;
                    //止损
                    bool lossTarget1 = (spreadPrice - myLegs.spreadPrice_Open) < 0 && holdingDays > 20;
                    bool lossTarget2 = etfPriceNow < myLegs.strike1 - 0.2;
                    bool lossTarget3 = spreadPrice / myLegs.spreadPrice_Open < 0.6;
                    bool lossTarget4 = maxProfit > 0.02 && (spreadPrice - myLegs.spreadPrice_Open) / maxProfit < 0.8;
                    if (profitTarget || lossTarget1 || lossTarget2 || lossTarget3 || lossTarget4 || durationNow <= 1 || holdingDays >= 7)
                    {
                        Console.WriteLine("平仓!");
                        maxProfit = 0;
                        myLegs    = new BullSpread();
                        MinuteCloseAllPositonsWithSlip.closeAllPositions(dataToday, ref positions, ref myAccount, thisTime, slipPoint);
                    }
                    AccountUpdatingForMinute.computeAccountUpdating(ref myAccount, positions, thisTime, dataToday);
                }
                else
                {
                    int thisIndex = 239;
                    var thisTime  = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(today), thisIndex);
                    Dictionary <string, List <KLine> > dataToday = new Dictionary <string, List <KLine> >();
                    dataToday.Add(targetVariety, etfData.Cast <KLine>().ToList());
                    AccountUpdatingForMinute.computeAccountUpdating(ref myAccount, positions, thisTime, dataToday);
                }
                BasicAccount tempAccount = new BasicAccount();
                tempAccount.time          = myAccount.time;
                tempAccount.freeCash      = myAccount.freeCash;
                tempAccount.margin        = myAccount.margin;
                tempAccount.positionValue = myAccount.positionValue;
                tempAccount.totalAssets   = myAccount.totalAssets;
                tempAccount.initialAssets = myAccount.initialAssets;
                accountHistory.Add(tempAccount);
            }
            //策略绩效统计及输出
            PerformanceStatisics myStgStats = new PerformanceStatisics();

            myStgStats = PerformanceStatisicsUtils.compute(accountHistory, positions);
            //画图
            Dictionary <string, double[]> line = new Dictionary <string, double[]>();

            double[] netWorth = accountHistory.Select(a => a.totalAssets / initialCapital).ToArray();
            line.Add("NetWorth", netWorth);
            //记录净值数据
            RecordUtil.recordToCsv(accountHistory, GetType().FullName, "account", parameters: "EMA7_EMA50", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //记录持仓变化
            var positionStatus = OptionRecordUtil.Transfer(positions);

            RecordUtil.recordToCsv(positionStatus, GetType().FullName, "positions", parameters: "EMA7_EMA50", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //记录统计指标
            var performanceList = new List <PerformanceStatisics>();

            performanceList.Add(myStgStats);
            RecordUtil.recordToCsv(performanceList, GetType().FullName, "performance", parameters: "EMA7_EMA50", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //统计指标在console 上输出
            Console.WriteLine("--------Strategy Performance Statistics--------\n");
            Console.WriteLine(" netProfit:{0,5:F4} \n totalReturn:{1,-5:F4} \n anualReturn:{2,-5:F4} \n anualSharpe :{3,-5:F4} \n winningRate:{4,-5:F4} \n PnLRatio:{5,-5:F4} \n maxDrawDown:{6,-5:F4} \n maxProfitRatio:{7,-5:F4} \n informationRatio:{8,-5:F4} \n alpha:{9,-5:F4} \n beta:{10,-5:F4} \n averageHoldingRate:{11,-5:F4} \n", myStgStats.netProfit, myStgStats.totalReturn, myStgStats.anualReturn, myStgStats.anualSharpe, myStgStats.winningRate, myStgStats.PnLRatio, myStgStats.maxDrawDown, myStgStats.maxProfitRatio, myStgStats.informationRatio, myStgStats.alpha, myStgStats.beta, myStgStats.averageHoldingRate);
            Console.WriteLine("-----------------------------------------------\n");
            //benchmark净值
            List <double> netWorthOfBenchmark = benchmark.Select(x => x / benchmark[0]).ToList();

            line.Add("Base", netWorthOfBenchmark.ToArray());
            string[] datestr = accountHistory.Select(a => a.time.ToString("yyyyMMdd")).ToArray();
            Application.Run(new PLChart(line, datestr));
        }
예제 #19
0
        /// <summary>
        /// 策略回测部分,期权时间价值策略
        /// 在日循环上判断(1)选择操作标的(2)是否开平仓,在分钟循环上进行具体操作
        /// 分钟上的操作:(1)开仓(2)到期平仓(3)调仓平值期权(4)止盈止损
        /// (1)若直接开平仓,在开盘15分钟时进行操作(2)若判断止盈止损,在收盘15分钟时进行操作
        /// </summary>
        public void compute()
        {
            log.Info("开始回测(回测期{0}到{1})", Kit.ToInt_yyyyMMdd(startdate), Kit.ToInt_yyyyMMdd(endDate));
            var repo           = Platforms.container.Resolve <OptionInfoRepository>();
            var optionInfoList = repo.fetchFromLocalCsvOrWindAndSaveAndCache(1);

            Caches.put("OptionInfo", optionInfoList);
            List <DateTime> tradeDays = DateUtils.GetTradeDays(startdate, endDate);
            //var ETFDaily = Platforms.container.Resolve<StockDailyRepository>().fetchFromLocalCsvOrWindAndSave("510050.SH", Kit.ToDate(20150101),Kit.ToDate(20160731));

            ///账户初始化
            //初始化position
            SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> > positions = new SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> >();
            //初始化Account信息
            BasicAccount myAccount = new BasicAccount();

            myAccount.totalAssets = initialCapital;
            myAccount.freeCash    = myAccount.totalAssets;
            //记录历史账户信息
            List <BasicAccount> accountHistory = new List <BasicAccount>();

            ///回测循环
            //回测循环--By Day
            foreach (var day in tradeDays)
            {
                //日内数据准备
                Dictionary <string, List <KLine> > data = new Dictionary <string, List <KLine> >();
                var             list     = OptionUtilities.getOptionListByDate(optionInfoList, Kit.ToInt_yyyyMMdd(day));
                List <DateTime> endDate  = OptionUtilities.getEndDateListByAscending(list);
                var             ETFtoday = Platforms.container.Resolve <StockMinuteRepository>().fetchFromLocalCsvOrWindAndSave("510050.SH", day);
                data.Add("510050.SH", ETFtoday.Cast <KLine>().ToList());
                foreach (var info in list)
                {
                    string IHCode      = OptionUtilities.getCorrespondingIHCode(info, Kit.ToInt_yyyyMMdd(day));
                    var    repoOption  = Platforms.container.Resolve <OptionMinuteRepository>();
                    var    optionToday = repoOption.fetchFromLocalCsvOrWindAndSave(info.optionCode, day);
                    data.Add(info.optionCode, optionToday.Cast <KLine>().ToList());
                }
                int index = 0;
                //交易开关设置,控制day级的交易开关
                bool tradingOn = true; //总交易开关
                bool openingOn = true; //开仓开关
                bool closingOn = true; //平仓开关

                //是否为交割日
                bool isExpiredDay = day.Equals(endDate[0]);
                //是否为回测最后一天
                bool isLastDayOfBackTesting = day.Equals(endDate);

                //回测循环 -- By Minute
                //不允许在同一根1minBar上开平仓
                while (index < 240)
                {
                    int      nextIndex = index + 1;
                    DateTime now       = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(day), index);
                    Dictionary <string, MinuteSignal> signal = new Dictionary <string, MinuteSignal>();
                    double etfPrice = ETFtoday[index].close;
                    //按strike price与etf价格的接近程度排序
                    List <double> strikeTodayArr = OptionUtilities.getStrikeListByAscending(list).OrderBy(x => Math.Abs(x - etfPrice)).ToList();
                    try
                    {
                        /*
                         * if (index != 225)
                         * {
                         *  index = nextIndex;
                         *  continue;
                         * }
                         */
                        //持仓查询,先平后开
                        //若当前有持仓 且 允许平仓
                        //是否是空仓,若position中所有品种volum都为0,则说明是空仓
                        bool isEmptyPosition = positions.Count != 0 ? positions[positions.Keys.Last()].Values.Sum(x => Math.Abs(x.volume)) == 0 : true;

                        if ((positions.Count != 0 && !isEmptyPosition) && tradingOn)
                        {
                            //平仓条件
                            //(1)若当天为交割日或回测结束日,平仓,且关闭开仓开关,次日才能开仓;
                            //(2)若closingOn为false,平仓;
                            //(3)检查持仓期权是否为平价期权,若否,清掉当前头寸并建立新的持仓;
                            //--------------------------------------------------------------------
                            //(1)若当天为交割日或回测结束日,平仓,且关闭开仓开关,次日才能开仓;
                            //(2)若closingOn为false,平仓;
                            //取出当前持仓期权的strike
                            double strikePriceOfPositions = optionInfoList[optionInfoList.FindIndex(a => a.optionCode == positions[positions.Keys.Last()].Values.First().code)].strike;
                            bool   isParPriceOption       = strikePriceOfPositions == strikeTodayArr[0];
                            //--------------------------------------------------------------------
                            if (!isEmptyPosition && (isExpiredDay || isLastDayOfBackTesting || closingOn == false))
                            {
                                //全部平仓
                                DateTime next = MinuteCloseAllPositonsWithSlip.closeAllPositions(data, ref positions, ref myAccount, now: now, slipPoint: slipPoint);
                                //当天不可再开仓
                                openingOn = false;
                            }
                            //(3)检查持仓期权是否为平价期权,若否,清掉当前头寸并建立新的持仓;
                            else if (!isEmptyPosition && !isParPriceOption)
                            {
                                //全部平仓
                                DateTime next = MinuteCloseAllPositonsWithSlip.closeAllPositions(data, ref positions, ref myAccount, now: now, slipPoint: slipPoint);
                                //当天不可再开仓
                                openingOn = false;
                            }
                        }
                        //若当前无持仓 且 允许开仓
                        //若当前为交割日,则不开仓
                        if (isExpiredDay == true)
                        {
                            openingOn = false;
                        }
                        else if ((positions.Count == 0 || isEmptyPosition) && openingOn && tradingOn)
                        {
                            //标的池构建
                            //选择目标期权品种放入标的池:
                            //四个头寸(1)short当月平价认购(2)short当月平价认沽(3)long下月平价认购(4)long下月平价认沽
                            OptionInfo callCandidateFront = OptionUtilities.getSpecifiedOption(list, endDate[0], "认购", strikeTodayArr[0])[0];
                            OptionInfo putCandidateFront  = OptionUtilities.getSpecifiedOption(list, endDate[0], "认沽", strikeTodayArr[0])[0];
                            OptionInfo callCandidateNext  = OptionUtilities.getSpecifiedOption(list, endDate[1], "认购", strikeTodayArr[0])[0];
                            OptionInfo putCandidateNext   = OptionUtilities.getSpecifiedOption(list, endDate[1], "认沽", strikeTodayArr[0])[0];

                            //检查四个标的strike是否相同,若相同则开仓,若不相同是,说明下月平价期权尚未挂出,则continue
                            bool isSameStrike = callCandidateFront.strike == callCandidateFront.strike;
                            //生成开仓信号
                            if (isSameStrike)
                            {
                                //查询可用资金
                                double nowFreeCash = myAccount.freeCash;
                                //计算每个头寸的建仓量,原则:尽量使各头寸等金额
                                double openVolumeOfCallFront = Math.Floor(nowFreeCash / 4 / data[callCandidateFront.optionCode][index].close / optionContractTimes) * optionContractTimes;
                                double openVolumeOfPutFront  = Math.Floor(nowFreeCash / 4 / data[putCandidateFront.optionCode][index].close / optionContractTimes) * optionContractTimes;
                                double openVolumeOfCallNext  = Math.Floor(nowFreeCash / 4 / data[callCandidateNext.optionCode][index].close / optionContractTimes) * optionContractTimes;
                                double openVolumeOfPutNext   = Math.Floor(nowFreeCash / 4 / data[putCandidateNext.optionCode][index].close / optionContractTimes) * optionContractTimes;

                                MinuteSignal callFront = new MinuteSignal()
                                {
                                    code = callCandidateFront.optionCode, volume = -openVolumeOfCallFront, time = now, tradingVarieties = "option", price = data[callCandidateFront.optionCode][index].close, minuteIndex = index
                                };
                                MinuteSignal putFront = new MinuteSignal()
                                {
                                    code = putCandidateFront.optionCode, volume = -openVolumeOfPutFront, time = now, tradingVarieties = "option", price = data[putCandidateFront.optionCode][index].close, minuteIndex = index
                                };
                                MinuteSignal callNext = new MinuteSignal()
                                {
                                    code = callCandidateNext.optionCode, volume = openVolumeOfCallNext, time = now, tradingVarieties = "option", price = data[callCandidateNext.optionCode][index].close, minuteIndex = index
                                };
                                MinuteSignal putNext = new MinuteSignal()
                                {
                                    code = putCandidateNext.optionCode, volume = openVolumeOfPutNext, time = now, tradingVarieties = "option", price = data[putCandidateNext.optionCode][index].close, minuteIndex = index
                                };
                                signal.Add(callFront.code, callFront);
                                signal.Add(putFront.code, putFront);
                                signal.Add(callNext.code, callNext);
                                signal.Add(putNext.code, putNext);
                                DateTime next = MinuteTransactionWithSlip.computeMinuteOpenPositions(signal, data, ref positions, ref myAccount, slipPoint: slipPoint, now: now);
                                nextIndex = Math.Max(nextIndex, TimeListUtility.MinuteToIndex(next));
                            }
                        }
                        //账户信息更新
                        AccountUpdatingForMinute.computeAccountUpdating(ref myAccount, positions, now, data);
                    }

                    catch (Exception)
                    {
                        throw;
                    }

                    index = nextIndex;
                }
                //账户信息记录By Day
                //用于记录的临时账户
                BasicAccount tempAccount = new BasicAccount();
                tempAccount.time          = myAccount.time;
                tempAccount.freeCash      = myAccount.freeCash;
                tempAccount.margin        = myAccount.margin;
                tempAccount.positionValue = myAccount.positionValue;
                tempAccount.totalAssets   = myAccount.totalAssets;
                accountHistory.Add(tempAccount);
            }

            //遍历输出到console
            foreach (var account in accountHistory)
            {
                Console.WriteLine("time:{0},netWorth:{1,8:F3}\n", account.time, account.totalAssets / initialCapital);
            }

            //将accountHistory输出到csv
            var resultPath = ConfigurationManager.AppSettings["CacheData.ResultPath"] + "accountHistory.csv";
            var dt         = DataTableUtils.ToDataTable(accountHistory); // List<MyModel> -> DataTable

            CsvFileUtils.WriteToCsvFile(resultPath, dt);                 // DataTable -> CSV File
            Console.ReadKey();
        }
예제 #20
0
        protected void Page_Load(object sender, EventArgs e)
        {
            string pageChecker = Request.QueryString["page"];

            if (string.IsNullOrEmpty(pageChecker))
            {
                Session.Remove("WithdrawalSearch");
            }

            using (NpgsqlConnection conn = Classes.DB.InstBTCDB("instbtc"))
            {
                NpgsqlCommand command = new NpgsqlCommand();
                string        query   = string.Empty;

                if (Request.HttpMethod == "POST")
                {
                    string status         = txtStatus.Value;
                    string clientId       = txtClientId.Value;
                    string clientEmail    = txtClientEmail.Value;
                    string clientName     = txtClientName.Value;
                    string walletId       = txtWalletId.Value;
                    string documentId     = txtWalletId.Value;
                    string createdDate    = txtCreatedDate.Value;
                    string docStatus      = txtDocStatus.Value;
                    string refferenceHash = txtHash.Value;

                    WithdrawalSearchModel searchModel = new WithdrawalSearchModel()
                    {
                        Status      = status,
                        ClientModel = new ClientModelSearch
                        {
                            Id    = clientId,
                            Email = clientEmail
                        },
                        DocumentStatus  = docStatus,
                        ClientName      = clientName,
                        WalletId        = walletId,
                        DocumentId      = documentId,
                        CreatedDate     = createdDate,
                        refference_hash = refferenceHash
                    };
                    Session["WithdrawalSearch"] = searchModel;
                }

                if (Session["WithdrawalSearch"] != null)
                {
                    WithdrawalSearchModel sessionSearchModel = (WithdrawalSearchModel)Session["WithdrawalSearch"];

                    //Get SQLCommand Parameters and Query Parameters
                    KeyValuePair <NpgsqlCommand, string> pair = getParameter(sessionSearchModel);
                    command = pair.Key;
                    query   = pair.Value;
                }

                //Get Withdrawals Datas
                List <MWithdrawal> withdrawalRequest = new List <MWithdrawal>();
                withdrawalRequest = WithdrawalUtilities.WithdrawalRequest(conn, command, query);

                #region Pagination
                Dictionary <string, int> pagerDictionary = new Dictionary <string, int>();
                string paginationString = "page";
                DocListPager.initialize(paginationString, 10);
                TotalRequest         = WithdrawalUtilities.GetWithdrawalCount(conn, command, query);
                pagerDictionary      = DocListPager.paginate(TotalRequest);
                withdrawalRequest    = WithdrawalUtilities.WithdrawalRequest(conn, command, query, pagerDictionary["offset"], pagerDictionary["limit"]);
                rowCount.InnerText   = $"{TotalRequest} Records Found";
                resultBody.InnerHtml = BuildHtmlTable(withdrawalRequest).ToString();
                #endregion

                //Get Document Statuses Selection
                OptionUtilities optionUtilities = new OptionUtilities();
                txtDocStatus.Items.Clear();
                txtDocStatus.Items.AddRange(optionUtilities.GetDocumentStatusOptions());

                //Return Values to their Fields
                ReturnFieldValues();
            }
        }
예제 #21
0
        protected void Page_Load(object sender, EventArgs e)
        {
            string            username      = Classes.Cookie.GetCookie("ggZurkVKwLIM+SQ2NMcfsra8/nnrhm9u5sl4TMYTE2Y", false);
            var               roles         = Utilities.AccountUtilities.getUserRoles(username);
            RoleUtilities     roleUtilities = new RoleUtilities();
            List <RolesModel> rolesModels   = new List <RolesModel>();
            List <string>     roleLists     = roles.Split(',').ToList();

            if (roleLists.Find(f => f.ToLower() == "12") == null)
            {
                Response.Redirect("/dashboard.aspx");
            }



            if (Request.HttpMethod == "POST")
            {
                #region Assign Post Variables
                string ClientId          = Request.Form["clientId"];
                string PaymentReferrence = Request.Form["pspRef"];
                string PaymentStatus     = Request.Form["pspStatus"];
                string CreditedStatus    = Request.Form["creditedStatus"];
                string PspId             = Request.Form["ctl00$ctl00$MainContent$LMainContent$pspId"];
                string Amount            = Request.Form["amount"];
                string Currency          = Request.Form["currency"];
                string Note             = Request.Form["note"];
                string CardLast4        = Request.Form["cardLast4"];
                string CardExpiry       = Request.Form["cardExpiry"];
                string CardHolderName   = Request.Form["cardHolder"];
                string TradingAccountId = Request.Form["PIN"];
                #endregion

                string PIN = !string.IsNullOrEmpty(TradingAccountId) ? TradingAccountId : string.Empty;

                #region Get Client Info
                ClientModel Info = new ClientModel();
                using (NpgsqlConnection conn = Classes.DB.InstBTCDB("instbtc"))
                {
                    Info = Clients.FindById(conn, int.Parse(ClientId));
                }
                #endregion

                if (Info != null)
                {
                    #region Creating the Transaction Object
                    Classes.Instbtc.Models.TransactionModel Transaction = new Classes.Instbtc.Models.TransactionModel
                    {
                        Psp_ID            = decimal.Parse(PspId),
                        Deposit_Currency  = Currency,
                        Deposit_Amount    = Convert.ToDecimal(Amount),
                        Exchange_Currency = "BTC",
                        Exchange_Amount   = Convert.ToDecimal(Classes.Instbtc.Utilities.Conversion.GetBTCAmountRestSharp(Amount, Currency)),
                        Created_Date      = DateTime.UtcNow,
                        Client_ID         = Convert.ToDecimal(ClientId),
                        Psp_Status        = PaymentStatus,
                        Credited_Status   = CreditedStatus,
                        PaymentReference  = PaymentReferrence,
                        Notes             = Note,
                        type                 = Classes.Instbtc.Models.TransactionType.DEPOSIT,
                        CardLast4            = !string.IsNullOrEmpty(CardLast4) ? CardLast4 : "",
                        CardHolderName       = !string.IsNullOrEmpty(CardHolderName) ? CardHolderName : "",
                        Transaction_Currency = "BTC"
                    };
                    #endregion

                    #region Create The Transaction
                    var    TransactionCheck = Utilities.Transactions.CheckTransactionIfExist(Transaction.PaymentReference);
                    object result           = new object();
                    if (string.IsNullOrEmpty(TransactionCheck))
                    {
                        result = Classes.Instbtc.Create.Transactions.CreateTransaction(Transaction);
                    }
                    else
                    {
                        toastrUtilities.SessionPush("toast", new KeyValuePair <string, string>("error", $"Cant Create Transaction, Existing Detected!"));
                        Response.Redirect("/transaction-lists.aspx");
                    }

                    #endregion

                    if (result.ToString() != "Internal Error" || result != null)
                    {
                        decimal OriginalDepositTransactionAmount = decimal.Parse(Transaction.Deposit_Amount.ToString());
                        decimal OriginalBtcExchangeAmount        = decimal.Parse(Transaction.Exchange_Amount.ToString());

                        EmailTemplateUtilities.SendNotificationDeposit(Info.Id.ToString(), OriginalDepositTransactionAmount.ToString(), OriginalBtcExchangeAmount.ToString(), Transaction);

                        //if (Info.Referral.ToLower() == "lblv" || Info.Referral.ToLower() == "tradershome" || Info.Referral.ToLower() == "profitix" || Info.Referral.ToLower() == "vlom" || Info.Referral.ToLower() == "uptos" || Info.Referral.ToLower() == "fundiza" || Info.Referral.ToLower() == "kiplar" || Info.Referral.ToLower() == "investigram" || Info.Referral.ToLower() == "commercewealth")
                        //{
                        //    try
                        //    {
                        //        var pspList = PspUtilities.GetPspById(Transaction.Psp_ID.ToString());
                        //        var pspName = pspList.Where(w => w.Id == int.Parse(Transaction.Psp_ID.ToString()))?.FirstOrDefault()?.Name;
                        //        pspName = pspName.Replace("USD ", "").Replace("EUR ", "").Replace("AUD ", "");
                        //        var res = BrandsIntegration.PushToBrand(Info, Transaction, PaymentStatus, result, $"[{pspName}] " + Note, PIN, pspName);
                        //        toastrUtilities.SessionPush("toast", new KeyValuePair<string, string>("success", $"{res}"));
                        //    }
                        //    catch (Exception ex)
                        //    {
                        //        toastrUtilities.SessionPush("toast", new KeyValuePair<string, string>("error", $"{ex.Message.ToString()}"));
                        //    }
                        //}
                        //else
                        //{
                        //    decimal OriginalDepositTransactionAmount = decimal.Parse(Transaction.Deposit_Amount.ToString());
                        //    decimal OriginalBtcExchangeAmount = decimal.Parse(Transaction.Exchange_Amount.ToString());

                        //    EmailTemplateUtilities.SendNotificationDeposit(Info.Id.ToString(), OriginalDepositTransactionAmount.ToString(), OriginalBtcExchangeAmount.ToString(), Transaction);
                        //}
                    }
                    else
                    {
                        toastrUtilities.SessionPush("toast", new KeyValuePair <string, string>("error", $"An Error Occured Cant Create Transaction"));
                    }
                }
                else
                {
                    //Redirect Invalid Client Id;
                    toastrUtilities.SessionPush("toast", new KeyValuePair <string, string>("error", $"No Client With this Id: {ClientId}"));
                    Response.Redirect("/transaction-lists.aspx");
                }
            }

            OptionUtilities optionUtilities = new OptionUtilities();
            pspId.Items.AddRange(optionUtilities.GetPSPOptions());
        }
예제 #22
0
        public void compute()
        {
            log.Info("开始回测(回测期{0}到{1})", Kit.ToInt_yyyyMMdd(startDate), Kit.ToInt_yyyyMMdd(endDate));
            var repo = Platforms.container.Resolve <OptionInfoRepository>();

            optionInfoList = repo.fetchFromLocalCsvOrWindAndSaveAndCache(1);
            Caches.put("OptionInfo", optionInfoList);
            //初始化头寸信息
            SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> > positions = new SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> >();
            //初始化Account信息
            BasicAccount myAccount = new BasicAccount();

            myAccount.initialAssets = initialCapital;
            myAccount.totalAssets   = initialCapital;
            myAccount.freeCash      = myAccount.totalAssets;
            //初始化持仓信息
            StranglePair holdPair = new StranglePair();
            //记录历史账户信息
            List <BasicAccount> accountHistory = new List <BasicAccount>();
            List <double>       benchmark      = new List <double>();
            //可以变动的策略参数
            int    length = 40;
            double range  = 0.04;

            //50ETF的日线数据准备,从回测期开始之前100个交易开始取
            int number = 100;
            List <StockDaily> dailyData = new List <StockDaily>();

            dailyData = Platforms.container.Resolve <StockDailyRepository>().fetchFromLocalCsvOrWindAndSave(targetVariety, DateUtils.PreviousTradeDay(startDate, number), endDate);
            var closePrice = dailyData.Select(x => x.close).ToArray();
            var ETFMA      = TA_MA.SMA(closePrice, length);
            //获取中国波指的数据
            List <StockDaily> iVix = Platforms.container.Resolve <StockDailyRepository>().fetchFromLocalCsvOrWindAndSave("000188.SH", startDate, endDate);

            //按交易日回测
            for (int day = 0; day < tradeDays.Count(); day++)
            {
                benchmark.Add(closePrice[day + number]);
                double MAyesterday  = ETFMA[day + number - 1];
                double lastETFPrice = dailyData[number + day - 1].close;
                var    today        = tradeDays[day];
                //获取当日上市的期权合约列表
                var optionInfoList = OptionUtilities.getUnmodifiedOptionInfoList(this.optionInfoList, today);
                //初始化信号的数据结构
                Dictionary <string, MinuteSignal> signal = new Dictionary <string, MinuteSignal>();
                //获取今日日内50ETF数据
                var etfData = Platforms.container.Resolve <StockMinuteRepository>().fetchFromLocalCsvOrWindAndSave(targetVariety, tradeDays[day]);
                //初始化行情信息,将50ETF的价格放入dataToday
                Dictionary <string, List <KLine> > dataToday = new Dictionary <string, List <KLine> >();
                dataToday.Add(targetVariety, etfData.Cast <KLine>().ToList());
                //记录今日账户信息
                myAccount.time = today;

                //获取今日期权的到期日期
                var dateStructure = OptionUtilities.getDurationStructure(optionInfoList, tradeDays[day]);
                //选定到日期在40个交易日至60个交易日的合约
                double duration = 0;
                //for (int i = 0; i < dateStructure.Count(); i++)
                //{
                //    if (dateStructure[i] >= 40 && dateStructure[i] <= 80)
                //    {
                //        duration = dateStructure[i];
                //        break;
                //    }
                //}
                duration = dateStructure[1];
                //如果没有持仓就开仓
                if (holdPair.endDate == new DateTime())
                {
                    if (duration == 0)
                    {
                        continue;
                    }
                    //按照开盘1分钟的价格来开平仓。
                    int      index       = 0;
                    DateTime now         = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(tradeDays[day]), index);
                    double   etfPriceNow = etfData[index].open;
                    if (etfPriceNow > MAyesterday * (1 + range))//看涨,卖出虚值的put
                    {
                        var list = OptionUtilities.getOptionListByDate(OptionUtilities.getOptionListByStrike(OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认沽"), etfPriceNow - 0.1, etfPriceNow - 0.5), Kit.ToInt_yyyyMMdd(today)).OrderBy(x => - x.strike).ToList();
                        if (list.Count == 0)
                        {
                            continue;
                        }
                        OptionInfo put = list[0];
                        if (put.strike != 0 && (put.modifiedDate > today.AddDays(10) || put.modifiedDate < today)) //开仓
                        {
                            tradeAssistant(ref dataToday, ref signal, put.optionCode, -put.contractMultiplier, today, now, index);
                            holdPair = new StranglePair()
                            {
                                callCode = "", putCode = put.optionCode, callPosition = 0, putPosition = -put.contractMultiplier, endDate = put.endDate, etfPrice = etfPriceNow, callStrike = 0, putStrike = put.strike
                            };
                            MinuteTransactionWithBar.ComputePosition(signal, dataToday, ref positions, ref myAccount, slipPoint: slipPoint, now: now, nowIndex: index);
                        }
                    }
                    else if (etfPriceNow < MAyesterday * (1 - range))//看跌,卖出虚值的call
                    {
                        var list = OptionUtilities.getOptionListByDate(OptionUtilities.getOptionListByStrike(OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认购"), etfPriceNow + 0.1, etfPriceNow + 0.5), Kit.ToInt_yyyyMMdd(today)).OrderBy(x => x.strike).ToList();
                        if (list.Count == 0)
                        {
                            continue;
                        }
                        OptionInfo call = list[0];
                        if (call.strike != 0 && (call.modifiedDate > today.AddDays(10) || call.modifiedDate < today)) //开仓
                        {
                            tradeAssistant(ref dataToday, ref signal, call.optionCode, -call.contractMultiplier, today, now, index);
                            holdPair = new StranglePair()
                            {
                                callCode = call.optionCode, putCode = "", callPosition = -call.contractMultiplier, putPosition = 0, endDate = call.endDate, etfPrice = etfPriceNow, callStrike = call.strike, putStrike = 0
                            };
                            MinuteTransactionWithBar.ComputePosition(signal, dataToday, ref positions, ref myAccount, slipPoint: slipPoint, now: now, nowIndex: index);
                        }
                    }
                    else//不涨不跌,卖出宽跨式期权
                    {
                        var putList = OptionUtilities.getOptionListByDate(OptionUtilities.getOptionListByStrike(OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认沽"), etfPriceNow - 0.1, etfPriceNow - 0.5), Kit.ToInt_yyyyMMdd(today)).OrderBy(x => - x.strike).ToList();

                        var callList = OptionUtilities.getOptionListByDate(OptionUtilities.getOptionListByStrike(OptionUtilities.getOptionListByOptionType(OptionUtilities.getOptionListByDuration(optionInfoList, today, duration), "认购"), etfPriceNow + 0.1, etfPriceNow + 0.5), Kit.ToInt_yyyyMMdd(today)).OrderBy(x => x.strike).ToList();
                        if (putList.Count == 0 || callList.Count == 0)
                        {
                            continue;
                        }
                        OptionInfo call = callList[0];
                        OptionInfo put  = putList[0];
                        if (put.strike != 0 && (put.modifiedDate > today.AddDays(10) || put.modifiedDate < today) && call.strike != 0 && (call.modifiedDate > today.AddDays(10) || call.modifiedDate < today)) //开仓
                        {
                            tradeAssistant(ref dataToday, ref signal, put.optionCode, -put.contractMultiplier, today, now, index);
                            tradeAssistant(ref dataToday, ref signal, call.optionCode, -call.contractMultiplier, today, now, index);
                            holdPair = new StranglePair()
                            {
                                callCode = call.optionCode, putCode = put.optionCode, callPosition = -call.contractMultiplier, putPosition = -put.contractMultiplier, endDate = put.endDate, etfPrice = etfPriceNow, callStrike = call.strike, putStrike = put.strike
                            };
                            MinuteTransactionWithBar.ComputePosition(signal, dataToday, ref positions, ref myAccount, slipPoint: slipPoint, now: now, nowIndex: index);
                        }
                    }
                }
                else //如果有持仓就判断需不需要移仓
                {
                    double   durationNow = DateUtils.GetSpanOfTradeDays(today, holdPair.endDate);
                    int      index       = 234;
                    DateTime now         = TimeListUtility.IndexToMinuteDateTime(Kit.ToInt_yyyyMMdd(tradeDays[day]), index);
                    if (holdPair.callPosition != 0)
                    {
                        tradeAssistant(ref dataToday, ref signal, holdPair.callCode, -holdPair.callPosition, today, now, index);
                    }
                    if (holdPair.putPosition != 0)
                    {
                        tradeAssistant(ref dataToday, ref signal, holdPair.putCode, -holdPair.putPosition, today, now, index);
                    }
                    if (durationNow <= 10) //强制平仓
                    {
                        //按照收盘前5分钟的价格来开平仓。
                        MinuteTransactionWithBar.ComputePosition(signal, dataToday, ref positions, ref myAccount, slipPoint: slipPoint, now: now, nowIndex: index);
                        holdPair = new StranglePair();
                    }
                }

                if (etfData.Count > 0)
                {
                    //更新当日属性信息
                    AccountUpdatingWithMinuteBar.computeAccount(ref myAccount, positions, etfData.Last().time, etfData.Count() - 1, dataToday);
                    //记录历史仓位信息
                    accountHistory.Add(new BasicAccount(myAccount.time, myAccount.totalAssets, myAccount.freeCash, myAccount.positionValue, myAccount.margin, myAccount.initialAssets));
                    benchmark.Add(etfData.Last().close);
                    if (netValue.Count() == 0)
                    {
                        netValue.Add(new NetValue {
                            time = today, netvalueReturn = 0, benchmarkReturn = 0, netvalue = myAccount.totalAssets, benchmark = etfData.Last().close
                        });
                    }
                    else
                    {
                        var netValueLast = netValue.Last();
                        netValue.Add(new NetValue {
                            time = today, netvalueReturn = myAccount.totalAssets / netValueLast.netvalue - 1, benchmarkReturn = etfData.Last().close / netValueLast.benchmark - 1, netvalue = myAccount.totalAssets, benchmark = etfData.Last().close
                        });
                    }
                }
            }
            //策略绩效统计及输出
            PerformanceStatisics myStgStats = new PerformanceStatisics();

            myStgStats = PerformanceStatisicsUtils.compute(accountHistory, positions);
            //画图
            Dictionary <string, double[]> line = new Dictionary <string, double[]>();

            double[] netWorth = accountHistory.Select(a => a.totalAssets / initialCapital).ToArray();
            line.Add("NetWorth", netWorth);
            //记录净值数据
            RecordUtil.recordToCsv(accountHistory, GetType().FullName, "account", parameters: "ShortOptionByMA", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //记录持仓变化
            var positionStatus = OptionRecordUtil.Transfer(positions);

            RecordUtil.recordToCsv(positionStatus, GetType().FullName, "positions", parameters: "ShortOptionByMA", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //记录统计指标
            var performanceList = new List <PerformanceStatisics>();

            performanceList.Add(myStgStats);
            RecordUtil.recordToCsv(performanceList, GetType().FullName, "performance", parameters: "ShortOptionByMA", performance: myStgStats.anualSharpe.ToString("N").Replace(".", "_"));
            //统计指标在console 上输出
            Console.WriteLine("--------Strategy Performance Statistics--------\n");
            Console.WriteLine(" netProfit:{0,5:F4} \n totalReturn:{1,-5:F4} \n anualReturn:{2,-5:F4} \n anualSharpe :{3,-5:F4} \n winningRate:{4,-5:F4} \n PnLRatio:{5,-5:F4} \n maxDrawDown:{6,-5:F4} \n maxProfitRatio:{7,-5:F4} \n informationRatio:{8,-5:F4} \n alpha:{9,-5:F4} \n beta:{10,-5:F4} \n averageHoldingRate:{11,-5:F4} \n", myStgStats.netProfit, myStgStats.totalReturn, myStgStats.anualReturn, myStgStats.anualSharpe, myStgStats.winningRate, myStgStats.PnLRatio, myStgStats.maxDrawDown, myStgStats.maxProfitRatio, myStgStats.informationRatio, myStgStats.alpha, myStgStats.beta, myStgStats.averageHoldingRate);
            Console.WriteLine("-----------------------------------------------\n");

            //benchmark净值
            List <double> netWorthOfBenchmark = benchmark.Select(x => x / benchmark[0]).ToList();

            line.Add("50ETF", netWorthOfBenchmark.ToArray());
            // ivix数据
            double[] iVixClose = iVix.Select(x => x.close / iVix[0].close).ToArray();
            //line.Add("iVix", iVixClose);
            string[] datestr = accountHistory.Select(a => a.time.ToString("yyyyMMdd")).ToArray();


            //maoheng 画图
            //Application.Run(new PLChart(line, datestr));

            //cuixun 画图
            //绘制图形的标题
            string formTitle = this.startDate.ToShortDateString() + "--" + this.endDate.ToShortDateString() + "  " + this.targetVariety + " 净值曲线"
                               + "\r\n" + "\r\n" + "净利润:" + myStgStats.netProfit + "  " + "夏普率:" + myStgStats.anualSharpe + "  " + "最大回撤:" + myStgStats.maxDrawDown
                               + "\r\n" + "\r\n";
            //生成图像
            PLChart plc = new PLChart(line, datestr, formTitle: formTitle);

            //运行图像
            //Application.Run(plc);
            plc.LoadForm();
            //保存图像
            plc.SaveZed(GetType().FullName, this.targetVariety, this.startDate, this.endDate, myStgStats.netProfit.ToString(), myStgStats.anualSharpe.ToString(), myStgStats.maxDrawDown.ToString());
        }
        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);
            }
        }