private StockTickTransaction onTick(int seconds, List <StockTickTransaction> data) { StockTickTransaction tick = new StockTickTransaction(); int secondsIndex = DataTimeStampExtension.GetStockSecondsIndex(data[0].TransactionDateTime); for (int i = 0; i < data.Count(); i++) { secondsIndex = DataTimeStampExtension.GetStockSecondsIndex(data[i].TransactionDateTime); if (secondsIndex <= seconds) { tick = data[i]; } else { break; } } return(tick); }
public void computeImbalanceInfactor(DateTime startDate, DateTime endDate) { var tradedays = dateRepo.GetStockTransactionDate(startDate, endDate); foreach (var date in tradedays) { double[] imbalanceInfactor = new double[28802]; double[] priceChange = new double[28802]; var stockData = stockRepo.GetStockTransaction(code, date, date.AddHours(17)); var stock = DataTimeStampExtension.ModifyStockTickData(stockData); for (int i = 0; i < 28802; i++) { if (stock[i] != null) { imbalanceInfactor[i] = stock[i].BidV1 / (stock[i].AskV1 + stock[i].BidV1); } if (i < 28801 && stock[i] != null && stock[i + 1] != null) { priceChange[i] = Math.Round(stock[i + 1].Bid1 - stock[i].Bid1, 4); } } double total = 0; double right = 0; for (int i = 0; i < 28802; i++) { //if (priceChange[i]!=0 && Math.Abs(imbalanceInfactor[i]-0.5)>=0) { total += 1; if (priceChange[i] > 0 && imbalanceInfactor[i] > 0.75) { right += 1; } if (priceChange[i] < 0 && imbalanceInfactor[i] < 0.25) { right += 1; } } } Console.WriteLine(Math.Round(right / total, 3)); } }
public void computeTWAP(DateTime startDate, DateTime endDate, int totalVolume = 10000000, int newOrderTimeInterval = 15, int oldOrderTimeInterval = 15, int oldOrderFrequency = 10, int newOrderPriceMode = -1, int oldOrderPriceMode = -1, int cancelTimeInterval = 120) { var tradedays = dateRepo.GetStockTransactionDate(startDate, endDate); foreach (var date in tradedays) { List <StockTickTransaction> data = new List <StockTickTransaction>(); try { data = stockRepo.GetStockTransaction(code, date, date); } catch (Exception) { Console.WriteLine("code:{0},date:{1} No Data!!", code, date); } if (data.Count() == 0) { Console.WriteLine("code:{0},date:{1} No Data!!", code, date); continue; } double vol = getVolatilityMinutly(code, date, 10); double mean = 0; double marketMean = 0; int seconds = 0; int dataIndex = 0; int dataSeconds; int untradeVolume = totalVolume; List <OrderBook> orderBook = new List <OrderBook>(); List <TradeBook> tradeBook = new List <TradeBook>(); //初始化每个周期的挂单量和补单量 int period = totalTime / newOrderTimeInterval; int orderVolumePerTimeInterval = getVolumeOfTimeInterval(untradeVolume, period); int stockNeedToTradePerTimeInterval = untradeVolume / period; int oldOrderVolumePerTimeInterval = 0; int orderNeedToTrade = 0; int orderAlreadyTrade = 0; int counting = 0; double lastNewOrderPrice = 0; //逐秒进行判断成交以及策略挂单 for (seconds = 0; seconds <= 14221; seconds++) { DateTime time = date.Date + DataTimeStampExtension.GetStockSecondsTimeByIndex(seconds); //获取市场数据部分 var lastTick = onTick(seconds, data); if (lastTick.Bid1 == 0) { continue; } counting += 1; marketMean = (marketMean * (counting - 1) + lastTick.LastPrice) / counting;//计算市场的平均价格 //根据最新盘口数据调整orderbook中waitingValume字段 modifyOrderBookByTickData(ref orderBook, lastTick); //策略挂单撤单部分 double newOrderPrice = getOrderPrice(newOrderPriceMode, lastTick); double oldOrderPrice = getOrderPrice(oldOrderPriceMode, lastTick); if (counting % newOrderTimeInterval == 1)//每个新挂单周期的第1秒进行挂单 { orderNeedToTrade = orderNeedToTrade + stockNeedToTradePerTimeInterval; if (orderVolumePerTimeInterval > 0) { orderId += 1; double price = getOrderPrice(newOrderPriceMode, lastTick); placeAnOrder(ref orderBook, lastTick, price, time, orderVolumePerTimeInterval, orderId); lastNewOrderPrice = price; } //如果价格跳涨,单位时间内多挂1倍的单 if (lastNewOrderPrice > 0 && (lastTick.Ask1 / lastNewOrderPrice - 1) > 1 * vol * Math.Sqrt(newOrderTimeInterval / 60.0)) { orderId += 1; placeAnOrder(ref orderBook, lastTick, lastTick.Ask1, time, orderVolumePerTimeInterval, orderId); lastNewOrderPrice = lastTick.Ask1; } } if (counting % oldOrderTimeInterval == 5)//每个补单周期的第5秒进行补单 { int activeOrderNumbers = getActivieOrderNumbers(orderBook); int volumeNow = (int)(Math.Round((orderNeedToTrade - orderAlreadyTrade - activeOrderNumbers) / 100.0) * 100); volumeNow = Math.Min(oldOrderVolumePerTimeInterval, volumeNow); if (volumeNow > 0) { orderId += 1; double price = getOrderPrice(oldOrderPriceMode, lastTick); placeAnOrder(ref orderBook, lastTick, price, time, volumeNow, orderId); } } if (counting % cancelTimeInterval == 0) //每个撤单周期进行撤单,并计算需要补挂的单子 { int activeOrderNumbers = getActivieOrderNumbers(orderBook); cancelDeviateOrders(ref orderBook, lastTick); if (orderAlreadyTrade / Convert.ToDouble(orderNeedToTrade) < tradingRate) { cancelPartialDeviateOrders(ref orderBook, lastTick); activeOrderNumbers = getActivieOrderNumbers(orderBook); } //计算后续补单每次挂单量 int oldOrderUntrade = orderNeedToTrade - orderAlreadyTrade - activeOrderNumbers; oldOrderVolumePerTimeInterval = getVolumeOfTimeInterval(oldOrderUntrade, oldOrderFrequency); } //判断成交部分 dataSeconds = DataTimeStampExtension.GetStockSecondsIndex(data[dataIndex].TransactionDateTime); if (dataSeconds == seconds) { //根据该tick的盘口数据,进行成交判断 transactionSimulation(ref orderBook, ref tradeBook, data[dataIndex]); //根据成交信息更新数据 orderAlreadyTrade = getTradedNumbers(tradeBook); untradeVolume = totalVolume - orderAlreadyTrade; //移到下一个tick的数据 if (dataIndex + 1 < data.Count()) { dataIndex = dataIndex + 1; } } //输出最后的交易情况 if (seconds == 14220) { mean = getTradeAveragePrice(tradeBook); int orderVolume = getOrderBookVolume(orderBook); Console.WriteLine("{0}: 市场均价 {1} 成交均价 {2} 成交量 {3} 需成交 {4} 挂单 {5}", time, marketMean, mean, orderAlreadyTrade, orderNeedToTrade, orderVolume); } } } }
public void compute(DateTime startDate, DateTime endDate) { var tradedays = dateRepo.GetStockTransactionDate(startDate, endDate); List <ETFConsitituent> etfInfo = new List <ETFConsitituent>(); List <double> amountList = getAmount(code, startDate, endDate); double[] arbitraryPurchase = new double[28802]; double[] arbitraryRedeem = new double[28802]; bool[] isNan = new bool[28802]; for (int i = 0; i < 28802; i++) { isNan[i] = true; } for (int k = 0; k < tradedays.Count(); k++) { DateTime date = tradedays[k]; etfInfo = getETFInfo(code, date); foreach (var item in etfInfo) { if (item.cash_substitution_mark == "必须") { for (int i = 0; i < 28802; i++) { if (isNan[i] == true) { arbitraryPurchase[i] += -item.substitution_amout; } } } else { var stockData = stockRepo.GetStockTransaction(item.code, date, date.AddHours(17)); if (stockData != null && stockData.Count > 0) { var stock = DataTimeStampExtension.ModifyStockTickData(stockData); for (int i = 0; i < stock.Count(); i++) { if (isNan[i] == true && stock[i] != null && stock[i].AskV1 != 0 && stock[i].BidV1 != 0) { arbitraryPurchase[i] += -item.volume * stock[i].Ask1; //arbitraryRedeem[i] += item.volume * stock[i].Bid1; } if (stock[i] == null) { isNan[i] = false; arbitraryPurchase[i] = 0; //arbitraryRedeem[i] = 0; } } } else { if (item.cash_substitution_mark == "禁止") { for (int i = 0; i < 28802; i++) { arbitraryPurchase[i] = 0; isNan[i] = false; } } else { var stock = stockDailyRepo.GetStockTransaction(item.code, date, date); for (int i = 0; i < 28802; i++) { if (isNan[i] == true) { arbitraryPurchase[i] += -item.volume * stock[stock.Count() - 1].Close * (1 + item.premium_ratio / 100.0); } } } } } } var etf = DataTimeStampExtension.ModifyStockTickData(stockRepo.GetStockTransaction(code, date, date.AddHours(17))); for (int i = 0; i < etf.Count(); i++) { if (isNan[i] == true && etf[i] != null && etf[i].AskV1 != 0 && etf[i].BidV1 != 0) { arbitraryPurchase[i] += amountList[k] * etf[i].Bid1; // arbitraryRedeem[i] += -amountList[k] * etf[i].Ask1; } if (etf[i] == null) { isNan[i] = false; arbitraryPurchase[i] = 0; //arbitraryRedeem[i] = 0; } } Console.WriteLine("today {0} change {1}", date, arbitraryPurchase.Max()); } }
private List <StockTransaction> tranferTickToMinuteDayByDay(string code, DateTime date, double openData, List <StockTickTransaction> tickData) { List <StockTransaction> minuteList = new List <StockTransaction>(); //构造时间间隔的左闭右开区间利用9点30分的分钟线包含时间[9:30:00,9:31:00) List <Interval> timeList = new List <Interval>(); for (int index = 0; index < 240; index++) { TimeSpan startTime = DataTimeStampExtension.GetStockMinuteTimeByIndex(index); TimeSpan endTime = startTime.Add(new TimeSpan(0, 0, 60)); if (index == 119 || index == 239) { endTime = startTime.Add(new TimeSpan(0, 0, 61)); } Interval interval = new Interval(startTime, endTime, new TimeSpan(0, 0, 60)); timeList.Add(interval); } double high = openData; double open = openData; double low = openData; double close = openData; double amount = 0; double volume = 0; double startAmount = 0; double endAmount = 0; double startVolume = 0; double endVolume = 0; foreach (var item in timeList) { int num = 0; for (int i = 0; i < tickData.Count(); i++) { if (tickData[i].TransactionDateTime.TimeOfDay >= item.Begin && tickData[i].TransactionDateTime.TimeOfDay < item.End) { num = num + 1; endAmount = tickData[i].Amount; endVolume = tickData[i].Volume; close = tickData[i].LastPrice; if (num == 1) { open = tickData[i].LastPrice; high = open; low = open; } if (tickData[i].LastPrice > high) { high = tickData[i].LastPrice; } if (tickData[i].LastPrice < low) { low = tickData[i].LastPrice; } } } if (num == 0) //这一分钟没有成交 { amount = 0; volume = 0; open = close; high = close; low = close; } else { amount = endAmount - startAmount; volume = endVolume - startVolume; startAmount = endAmount; startVolume = endVolume; } StockTransaction kLines = new StockTransaction(); kLines.Open = open; kLines.High = high; kLines.Low = low; kLines.Close = close; kLines.Amount = amount; kLines.Volume = volume; kLines.Code = code; kLines.DateTime = date.Date + item.Begin; kLines.Level = StockTransactionLevel.Minute; minuteList.Add(kLines); open = close; high = close; low = close; } return(minuteList); }
private void BulkLoadStockMinuteToSqlFromSource(string code, DateTime currentTime) { IdentifyOrCreateDBAndTable(currentTime); var latestTime = GetLatestTimeFromSql(code, currentTime); latestTime = latestTime == default(DateTime) ? new DateTime(currentTime.Year, currentTime.Month, 1) : latestTime.AddMinutes(1); if (latestTime.TimeOfDay >= new TimeSpan(14, 59, 00)) { latestTime = latestTime.Date.AddDays(1); } var endTime = GetEndTime(currentTime); if (latestTime < endTime) { var dataTable = tickRepo.GetStockTransaction(code, latestTime, endTime); var days = dateTimeRepo.GetStockTransactionDate(latestTime.Date, endTime.Date); var timelist = DataTimeStampExtension.GetStockMinuteTimeList(); List <StockMinuteTransaction> minuteAll = new List <StockMinuteTransaction>(); foreach (var day in days) { //Console.WriteLine("date:{0} start!!", day); List <StockMinuteTransaction> minuteNow = new List <StockMinuteTransaction>(); var dtToday = (from data in dataTable where data.TransactionDateTime.Date == day.Date select data).ToList(); if (dtToday[dtToday.Count() - 1].Volume <= 0) { continue; } if (dtToday.Count() != 0) { //处理开盘前的价格和成交量 double totalVolume = 0; double totalAmount = 0; double high = 0; double low = 0; double close = 0; double open = 0; var preOpen = (from data in dtToday where (data.TransactionDateTime.TimeOfDay < timelist[0]) select data).ToList(); if (preOpen.Count != 0) { var last = preOpen[preOpen.Count() - 1]; totalVolume = last.Volume; totalAmount = last.Amount; close = last.LastPrice; open = close; high = close; low = close; } for (int i = 0; i < timelist.Count() - 1; i++) { var dtNow = (from data in dtToday where (data.TransactionDateTime.TimeOfDay >= timelist[i]) && (data.TransactionDateTime.TimeOfDay <= timelist[i + 1]) select data).ToList(); if (dtNow.Count() != 0) { high = dtNow.Max(x => x.LastPrice); low = dtNow.Min(x => x.LastPrice); var listNow = dtNow.ToList(); var startData = listNow[0]; var endData = listNow[listNow.Count() - 1]; open = startData.LastPrice; close = endData.LastPrice; double volumeNew = endData.Volume; double amountNew = endData.Amount; double volume = volumeNew - totalVolume; double amount = amountNew - totalAmount; totalAmount = amountNew; totalVolume = volumeNew; StockMinuteTransaction KLine = new StockMinuteTransaction(); KLine.Amount = amount; KLine.Volume = volume; KLine.Open = open; KLine.Close = close; KLine.High = high; KLine.Low = low; KLine.Code = code; KLine.DateTime = day.Date + timelist[i]; minuteNow.Add(KLine); } else { StockMinuteTransaction KLine = new StockMinuteTransaction(); KLine.Amount = 0; KLine.Volume = 0; KLine.Open = close; KLine.Close = close; KLine.High = close; KLine.Low = close; KLine.Code = code; KLine.DateTime = day.Date + timelist[i]; minuteNow.Add(KLine); } } var nearClose = (from data in dtToday where (data.TransactionDateTime.TimeOfDay > timelist[timelist.Count() - 1]) select data).ToList(); if (nearClose.Count() != 0) { high = nearClose.Max(x => x.LastPrice); low = nearClose.Min(x => x.LastPrice); var listNow = nearClose.ToList(); var startData = listNow[0]; var endData = listNow[listNow.Count() - 1]; open = startData.LastPrice; close = endData.LastPrice; double volumeNew = endData.Volume; double amountNew = endData.Amount; double volume = volumeNew - totalVolume; double amount = amountNew - totalAmount; totalAmount = amountNew; totalVolume = volumeNew; StockMinuteTransaction KLine = new StockMinuteTransaction(); KLine.Amount = amount; KLine.Volume = volume; KLine.Open = open; KLine.Close = close; KLine.High = high; KLine.Low = low; KLine.Code = code; KLine.DateTime = day.Date + timelist[timelist.Count() - 1]; minuteNow.Add(KLine); } else { StockMinuteTransaction KLine = new StockMinuteTransaction(); KLine.Amount = 0; KLine.Volume = 0; KLine.Open = close; KLine.Close = close; KLine.High = close; KLine.Low = close; KLine.Code = code; KLine.DateTime = day.Date + timelist[timelist.Count() - 1]; minuteNow.Add(KLine); } } else { //for (int i = 0; i < timelist.Count(); i++) //{ // StockMinuteTransaction KLine = new StockMinuteTransaction(); // KLine.Amount = 0; // KLine.Volume = 0; // KLine.Open =0; // KLine.Close = 0; // KLine.High = 0; // KLine.Low = 0; // KLine.Code = code; // KLine.DateTime = day.Date + timelist[i]; // minuteNow.Add(KLine); //} Console.WriteLine("date:{0},no tickData!!!", day); } minuteAll.AddRange(minuteNow); } if (minuteAll.Count() != 0) { var dt = transactionListToDataTable(minuteAll); WriteToSql(dt); } } }
private List <StockMinuteTransaction> LoadStockMinuteToSqlFromSouceDaily(string code, DateTime currentTime, bool record = true) { List <StockMinuteTransaction> list = new List <StockMinuteTransaction>(); IdentifyOrCreateDBAndTable(currentTime); var dtToday = tickRepo.GetStockTransaction(code, currentTime, currentTime, record); dtToday = (from data in dtToday where (data.TransactionDateTime.TimeOfDay <= new TimeSpan(15, 0, 1)) select data).ToList(); var timelist = DataTimeStampExtension.GetStockMinuteTimeList(); List <StockMinuteTransaction> minuteNow = new List <StockMinuteTransaction>(); bool exists = true; if (dtToday.Count() == 0 || dtToday[dtToday.Count() - 1].Volume <= 0) { exists = false; } if (exists == true) { //处理开盘前的价格和成交量 var day = currentTime.Date; double totalVolume = 0; double totalAmount = 0; double high = 0; double low = 0; double close = 0; double open = 0; var preOpen = (from data in dtToday where (data.TransactionDateTime.TimeOfDay < timelist[0]) select data).ToList(); if (preOpen.Count != 0) { var last = preOpen[preOpen.Count() - 1]; totalVolume = last.Volume; totalAmount = last.Amount; close = last.LastPrice; open = close; high = close; low = close; } for (int i = 0; i < timelist.Count() - 1; i++) { var dtNow = (from data in dtToday where (data.TransactionDateTime.TimeOfDay >= timelist[i]) && (data.TransactionDateTime.TimeOfDay <= timelist[i + 1]) select data).ToList(); if (dtNow.Count() != 0) { high = dtNow.Max(x => x.LastPrice); low = dtNow.Min(x => x.LastPrice); var listNow = dtNow.ToList(); var startData = listNow[0]; var endData = listNow[listNow.Count() - 1]; open = startData.LastPrice; close = endData.LastPrice; double volumeNew = endData.Volume; double amountNew = endData.Amount; double volume = volumeNew - totalVolume; double amount = amountNew - totalAmount; totalAmount = amountNew; totalVolume = volumeNew; StockMinuteTransaction KLine = new StockMinuteTransaction(); KLine.Amount = amount; KLine.Volume = volume; KLine.Open = open; KLine.Close = close; KLine.High = high; KLine.Low = low; KLine.Code = code; KLine.DateTime = day.Date + timelist[i]; minuteNow.Add(KLine); } else { StockMinuteTransaction KLine = new StockMinuteTransaction(); KLine.Amount = 0; KLine.Volume = 0; KLine.Open = close; KLine.Close = close; KLine.High = close; KLine.Low = close; KLine.Code = code; KLine.DateTime = day.Date + timelist[i]; minuteNow.Add(KLine); } } var nearClose = (from data in dtToday where (data.TransactionDateTime.TimeOfDay > timelist[timelist.Count() - 1]) select data).ToList(); if (nearClose.Count() != 0) { high = nearClose.Max(x => x.LastPrice); low = nearClose.Min(x => x.LastPrice); var listNow = nearClose.ToList(); var startData = listNow[0]; var endData = listNow[listNow.Count() - 1]; open = startData.LastPrice; close = endData.LastPrice; double volumeNew = endData.Volume; double amountNew = endData.Amount; double volume = volumeNew - totalVolume; double amount = amountNew - totalAmount; totalAmount = amountNew; totalVolume = volumeNew; StockMinuteTransaction KLine = new StockMinuteTransaction { Amount = amount, Volume = volume, Open = open, Close = close, High = high, Low = low, Code = code, DateTime = day.Date + timelist[timelist.Count() - 1] }; minuteNow.Add(KLine); } else { StockMinuteTransaction KLine = new StockMinuteTransaction(); KLine.Amount = 0; KLine.Volume = 0; KLine.Open = close; KLine.Close = close; KLine.High = close; KLine.Low = close; KLine.Code = code; KLine.DateTime = day.Date + timelist[timelist.Count() - 1]; minuteNow.Add(KLine); } list = minuteNow; } else { // Console.WriteLine("date:{0},no tickData!!!", currentTime); } return(list); }
public void computeImpv(DateTime startDate, DateTime endDate) { var start = startDate; //while (start < endDate) //{ // if (!ExistInSqlServer(start)) // { // CreateDBOrTableIfNecessary(start); // } // start = start.AddYears(1); //} //if (!ExistInSqlServer(endDate)) //{ // CreateDBOrTableIfNecessary(endDate); //} var tradedays = dateRepo.GetStockTransactionDate(startDate, endDate); //逐日进行计算 foreach (var date in tradedays) { if (!ExistInSqlServer(date)) { CreateDBOrTableIfNecessary(date); } double[,] myFuture = new double[4, 28802]; var tickdata = new Dictionary <string, List <StockOptionTickTransaction> >(); var etf = DataTimeStampExtension.ModifyStockTickData(stockRepo.GetStockTransaction("510050.SH", date, date.AddHours(17))); var list = infoRepo.GetStockOptionInfo(underlying, date, date).Where(x => x.unit == 10000); Dictionary <StockOptionProperty, string> optionCode = new Dictionary <StockOptionProperty, string>(); //给出所有的strike信息 List <double> strikeList = new List <double>(); foreach (var item in list) { if (strikeList.Contains(item.strike) == false) { strikeList.Add(item.strike); } } strikeList = strikeList.OrderBy(x => x).ToList(); //给出所有的duration信息 List <DateTime> expireDateList = new List <DateTime>(); foreach (var item in list) { if (expireDateList.Contains(item.expireDate) == false) { expireDateList.Add(item.expireDate); } } expireDateList = expireDateList.OrderBy(x => x).ToList(); foreach (var item in list) { var option0 = optionRepo.GetStockTransaction(item.code, date, date.AddHours(17)); if (option0.Count == 0) { continue; } var option = DataTimeStampExtension.ModifyOptionTickData(option0); StockOptionProperty property = new StockOptionProperty { strike = item.strike, call_or_put = item.type, expireDate = item.expireDate }; optionCode.Add(property, item.code); tickdata.Add(item.code, option); } //计算合约的合成远期价格 for (int k = 0; k < 3; k++) //k遍历了到期时间 { double[,] futures = new double[4, 28802]; //futures[选取的strike,时间下标] double[,] weights = new double[4, 28802]; for (int i = 0; i < 28802; i++) { var etfMid = getStockMidPrice(etf[i], volumeTarget * 100); if (etfMid == 0) { continue; } var expireDate = expireDateList[k]; var strikeListNow = strikeList.OrderBy(x => Math.Abs(x - etfMid * Math.Exp(rate * dateRepo.GetDuration(date, expireDate) / 252.0))).ToList(); for (int j = 0; j <= 3; j++) { StockOptionProperty call = new StockOptionProperty { strike = strikeListNow[j], call_or_put = "认购", expireDate = expireDate }; StockOptionProperty put = new StockOptionProperty { strike = strikeListNow[j], call_or_put = "认沽", expireDate = expireDate }; bool callExists = false, putExists = false; foreach (var key in optionCode.Keys) { if (key.call_or_put == call.call_or_put && key.strike == call.strike && key.expireDate == call.expireDate) { callExists = true; call = key; } if (key.call_or_put == put.call_or_put && key.strike == put.strike && key.expireDate == put.expireDate) { putExists = true; put = key; } } if (callExists && putExists) { var callTick = tickdata[optionCode[call]]; var putTick = tickdata[optionCode[put]]; var callMid = getOptionMidPrice(callTick[i], volumeTarget); var putMid = getOptionMidPrice(putTick[i], volumeTarget); if (callMid > 0 && putMid > 0) { var callSpread = getOptionSpread(callTick[i], volumeTarget); var putSpread = getOptionSpread(putTick[i], volumeTarget); futures[j, i] = (callMid - putMid) * Math.Exp(rate * dateRepo.GetDuration(date, expireDate) / 252.0) + strikeListNow[j]; weights[j, i] = 1 / ((Math.Pow(callSpread, 2) + Math.Pow(putSpread, 2)) / 2); } } } myFuture[k, i] = 0; double weightsAll = 0; for (int j = 0; j < 3; j++) { myFuture[k, i] += futures[j, i] * weights[j, i]; weightsAll += weights[j, i]; } if (weightsAll != 0) { myFuture[k, i] /= weightsAll; } } int firstNonZero = 0; for (int i = 0; i < 28802; i++) { if (myFuture[k, i] != 0) { firstNonZero = i; break; } } for (int i = firstNonZero + 1; i < 28802; i++) { if (myFuture[k, i] == 0) { myFuture[k, i] = myFuture[k, i - 1]; } } for (int i = firstNonZero + 1; i < 28802; i++) { myFuture[k, i] = emaCoeff * myFuture[k, i] + (1 - emaCoeff) * myFuture[k, i - 1]; } //计算隐含波动率 foreach (var item in list) { if (item.expireDate != expireDateList[k]) { continue; } DataTable dt = new DataTable(); dt.Columns.Add("code"); dt.Columns.Add("tdatetime", typeof(DateTime)); dt.Columns.Add("expiredate"); dt.Columns.Add("futurePrice"); dt.Columns.Add("futurePrice0"); dt.Columns.Add("duration"); dt.Columns.Add("maturitydate"); dt.Columns.Add("etfPrice"); dt.Columns.Add("strike"); dt.Columns.Add("call_or_put"); dt.Columns.Add("ask"); dt.Columns.Add("bid"); dt.Columns.Add("ask_impv"); dt.Columns.Add("bid_impv"); StockOptionProperty option = new StockOptionProperty { strike = item.strike, call_or_put = item.type, expireDate = item.expireDate }; foreach (var key in optionCode.Keys) { if (key.call_or_put == option.call_or_put && key.strike == option.strike && key.expireDate == option.expireDate) { option = key; } } if (optionCode.ContainsKey(option) == true) { for (int i = 0; i < 28802; i++) { if (myFuture[k, i] == 0) { continue; } var etfMid = getStockMidPrice(etf[i], volumeTarget * 100); if (etfMid == 0) { continue; } var strikeListNow = strikeList.OrderBy(x => Math.Abs(x - etfMid * Math.Exp(rate * dateRepo.GetDuration(date, item.expireDate) / 252.0))).ToList(); var optionTick = tickdata[optionCode[option]]; if (optionTick[i] == null) { continue; } double etfprice = etf[i].LastPrice; double ask = optionTick[i].Ask1; double bid = optionTick[i].Bid1; double duration = dateRepo.GetDuration(date, option.expireDate) / 252.0; double strike = item.strike; string callorput = item.type; double askvol = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(myFuture[k, i], ask, strike, duration, rate, callorput), 4); double bidvol = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(myFuture[k, i], bid, strike, duration, rate, callorput), 4); double future0 = 0; for (int m = 0; m <= 3; m++) { if (strikeListNow[m] == item.strike) { future0 = futures[m, i]; break; } } DataRow dr = dt.NewRow(); dr["code"] = item.code; dr["tdatetime"] = Convert.ToDateTime(date + timelist[i]);//etf[i].TransactionDateTime; dr["maturitydate"] = item.expireDate; dr["futurePrice"] = Math.Round(myFuture[k, i], 4); dr["futurePrice0"] = Math.Round(future0, 4); dr["strike"] = Math.Round(strike, 4); dr["expiredate"] = dateRepo.GetDuration(date, option.expireDate); dr["duration"] = Math.Round(duration, 5); dr["etfPrice"] = etfprice; dr["call_or_put"] = item.type; dr["ask"] = ask; dr["bid"] = bid; if (askvol > 0 && askvol < 3) { dr["ask_impv"] = askvol; } else { dr["ask_impv"] = null; } if (bidvol > 0 && bidvol < 3) { dr["bid_impv"] = bidvol; } else { dr["bid_impv"] = null; } if (optionTick[i].TransactionDateTime < date.Date + new TimeSpan(14, 57, 00)) { dt.Rows.Add(dr); } } } SaveResultToMssql(date, dt, item.strike, dateRepo.GetDuration(date, item.expireDate), item.type, item.code); } } } }
private void compute(DateTime date) { List <StockTickTransaction> etf = new List <StockTickTransaction>(); etf = DataTimeStampExtension.ModifyStockTickData(stockRepo.GetStockTransaction("510050.SH", date, date.AddHours(17))); foreach (var item in parityList) { DataTable dt = new DataTable(); dt.Columns.Add("tdatetime"); dt.Columns.Add("expiredate"); dt.Columns.Add("maturitydate"); dt.Columns.Add("annualizedReturn"); dt.Columns.Add("annualizedCloseCost"); dt.Columns.Add("etfPrice"); dt.Columns.Add("strike"); dt.Columns.Add("callPrice"); dt.Columns.Add("putPrice"); dt.Columns.Add("callMinutelyPrice"); dt.Columns.Add("putMinutelyPrice"); dt.Columns.Add("minutelyVolume"); double strike = item.strike; int expiredate = 0; List <StockOptionTickTransaction> call = new List <StockOptionTickTransaction>(); List <StockOptionTickTransaction> put = new List <StockOptionTickTransaction>(); call = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.call, date, date.AddHours(17))); put = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.put, date, date.AddHours(17))); //计算套利空间 myList = new List <StockOptionParityProfit>(); TimeSpan span = item.expireDate - date; // var multiple = item.unit/10000.0; for (int i = 0; i < 28802; i++) { StockOptionParityProfit result = new StockOptionParityProfit(); double callMinutelyVolume = 0; double putMinutelyVolume = 0; double callPrice = 0; double putPrice = 0; if (etf[i] != null && call != null && put != null && call[i] != null && put[i] != null && etf[i].LastPrice != 0 && call[i].LastPrice != 0 && put[i].LastPrice != 0 && call[i].Ask1 != 0 && put[i].Bid1 != 0 && call[i].Bid1 != 0 && put[i].Ask1 != 0) { result.date = etf[i].TransactionDateTime; result.strike = item.strike; result.etfPrice = etf[i].LastPrice; result.expiredate = span.Days + 1; expiredate = result.expiredate; result.maturitydate = item.expireDate; double profit = result.strike - (etf[i].Ask1 - call[i].Bid1 + put[i].Ask1); double margin = (etf[i].Ask1 - call[i].Bid1 + put[i].Ask1) + (call[i].LastPrice + Math.Max(0.12 * etf[i].LastPrice - Math.Max(result.strike - etf[i].LastPrice, 0), 0.07 * etf[i].LastPrice)); double annualizedReturn = (profit - etf[i].Ask1 * 0.0001 - 1.6 / 10000.0) / margin / (double)result.expiredate * 365.0; double annualizedCloseCost = (-result.strike + (etf[i].Bid1 - call[i].Ask1 + put[i].Bid1) - etf[i].Bid1 * 0.0001 - 3.2 / 10000.0) / margin / (double)result.expiredate * 365.0; result.profit = annualizedReturn; result.cost = annualizedCloseCost; result.callPrice = call[i].LastPrice; result.putPrice = put[i].LastPrice; if (i > 120 && call[i - 120] != null) { callMinutelyVolume = call[i].Volume - call[i - 120].Volume; if (callMinutelyVolume != 0) { callPrice = (call[i].Amount - call[i - 120].Amount) / callMinutelyVolume / item.unit; } } else { callMinutelyVolume = Math.Round(call[i].Volume / Convert.ToDouble(i + 1) * 120.0, 0); if (callMinutelyVolume != 0) { callPrice = call[i].Amount / call[i].Volume / item.unit; } } if (i > 120 && put[i - 120] != null) { putMinutelyVolume = put[i].Volume - put[i - 120].Volume; if (putMinutelyVolume != 0) { putPrice = (put[i].Amount - put[i - 120].Amount) / putMinutelyVolume / item.unit; } } else { putMinutelyVolume = Math.Round(put[i].Volume / Convert.ToDouble(i + 1) * 120.0, 0); if (putMinutelyVolume != 0) { putPrice = put[i].Amount / put[i].Volume / item.unit; } } myList.Add(result); DataRow dr = dt.NewRow(); dr["tdatetime"] = result.date; dr["maturitydate"] = result.maturitydate; dr["strike"] = Math.Round(result.strike, 4); dr["annualizedReturn"] = Math.Round(result.profit, 4); dr["annualizedCloseCost"] = Math.Round(result.cost, 4); dr["expiredate"] = result.expiredate; dr["etfPrice"] = result.etfPrice; dr["callPrice"] = result.callPrice; dr["putPrice"] = result.putPrice; dr["callMinutelyPrice"] = Math.Round(Convert.ToDecimal(callPrice), 6); dr["putMinutelyPrice"] = Math.Round(Convert.ToDecimal(putPrice), 6); dr["minutelyVolume"] = Math.Min(Convert.ToDecimal(callMinutelyVolume), Convert.ToDecimal(putMinutelyVolume)); if (result.date < result.date.Date + new TimeSpan(14, 57, 00)) { dt.Rows.Add(dr); } } } SaveResultToMssql(date, dt, strike, expiredate); //SaveResultToMssql(date, dt,expiredate); } }
public void record(DateTime startDate, DateTime endDate) { var tradedays = dateRepo.GetStockTransactionDate(startDate, endDate); CreateDBOrTableIfNecessary(startDate); CreateDBOrTableIfNecessary(startDate.AddYears(1)); var start = startDate; while (start < endDate) { if (!ExistInSqlServer(start)) { CreateDBOrTableIfNecessary(start); } start = start.AddYears(1); } if (!ExistInSqlServer(endDate)) { CreateDBOrTableIfNecessary(endDate); } foreach (var date in tradedays) { DataTable dt = new DataTable(); dt = initializeDataTable(dt); double[] sigma1Ask = new double[28802]; double[] sigma1Bid = new double[28802]; double[] sigma2Ask = new double[28802]; double[] sigma2Bid = new double[28802]; double[] vixAsk = new double[28802]; double[] vixBid = new double[28802]; var list = infoRepo.GetStockOptionInfo(underlying, date, date); list = OptionUtilities.modifyOptionListByETFBonus(list, date); List <StockOptionInformation> callListThisMonth = new List <StockOptionInformation>(); List <StockOptionInformation> callListNextMonth = new List <StockOptionInformation>(); List <StockOptionInformation> putListThisMonth = new List <StockOptionInformation>(); List <StockOptionInformation> putListNextMonth = new List <StockOptionInformation>(); var durationList = OptionUtilities.getDurationStructure(list, date); double durationThisMonth = 0; double durationNextMonth = 0; if (durationList[0] > 7) { durationThisMonth = durationList[0]; durationNextMonth = durationList[1]; } else { durationThisMonth = durationList[1]; durationNextMonth = durationList[2]; } foreach (var item in list) { if (OptionUtilities.getDuration(item, date) == durationThisMonth && item.unit == 10000) { if (item.type == "认购") { callListThisMonth.Add(item); } else { putListThisMonth.Add(item); } } else if (OptionUtilities.getDuration(item, date) == durationNextMonth && item.unit == 10000) { if (item.type == "认购") { callListNextMonth.Add(item); } else { putListNextMonth.Add(item); } } } callListThisMonth = callListThisMonth.OrderBy(x => x.strike).ToList(); callListNextMonth = callListNextMonth.OrderBy(x => x.strike).ToList(); putListThisMonth = putListThisMonth.OrderBy(x => x.strike).ToList(); putListNextMonth = putListNextMonth.OrderBy(x => x.strike).ToList(); //获取当日ETF及期权数据 List <StockTickTransaction> etf = new List <StockTickTransaction>(); etf = DataTimeStampExtension.ModifyStockTickData(stockRepo.GetStockTransaction("510050.SH", date, date.AddHours(17))); Dictionary <double, List <StockOptionTickTransaction> > callDataThisMonth = new Dictionary <double, List <StockOptionTickTransaction> >(); Dictionary <double, List <StockOptionTickTransaction> > putDataThisMonth = new Dictionary <double, List <StockOptionTickTransaction> >(); Dictionary <double, List <StockOptionTickTransaction> > callDataNextMonth = new Dictionary <double, List <StockOptionTickTransaction> >(); Dictionary <double, List <StockOptionTickTransaction> > putDataNextMonth = new Dictionary <double, List <StockOptionTickTransaction> >(); List <double> strikeListThisMonth = new List <double>(); List <double> strikeListNextMonth = new List <double>(); foreach (var item in callListThisMonth) { strikeListThisMonth.Add(item.strike); var call = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.code, date, date.AddHours(17))); callDataThisMonth.Add(item.strike, call); } foreach (var item in putListThisMonth) { var put = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.code, date, date.AddHours(17))); putDataThisMonth.Add(item.strike, put); } foreach (var item in callListNextMonth) { strikeListNextMonth.Add(item.strike); var call = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.code, date, date.AddHours(17))); callDataNextMonth.Add(item.strike, call); } foreach (var item in putListNextMonth) { //2016-2-17数据有缺失 var put = DataTimeStampExtension.ModifyOptionTickData(optionRepo.GetStockTransaction(item.code, date, date.AddHours(17))); putDataNextMonth.Add(item.strike, put); } strikeListThisMonth = strikeListThisMonth.OrderBy(x => x).ToList(); strikeListNextMonth = strikeListNextMonth.OrderBy(x => x).ToList(); for (int index = 0; index < 28802; index++) { bool hasData = true; foreach (var item in strikeListThisMonth) { if (callDataThisMonth[item] == null || putDataThisMonth[item] == null || callDataThisMonth[item][index] == null || putDataThisMonth[item][index] == null || (callDataThisMonth[item][index].AskV1 == 0 && callDataThisMonth[item][index].BidV1 == 0) || (putDataThisMonth[item][index].AskV1 == 0 && putDataThisMonth[item][index].BidV1 == 0)) { hasData = false; break; } } //if (durationThisMonth <= 30) { foreach (var item in strikeListNextMonth) { if (callDataNextMonth[item] == null || putDataNextMonth[item] == null || callDataNextMonth[item][index] == null || putDataNextMonth[item][index] == null || callDataNextMonth[item][index].AskV1 == 0 || putDataNextMonth[item][index].AskV1 == 0 || callDataNextMonth[item][index].BidV1 == 0 || putDataNextMonth[item][index].BidV1 == 0) { hasData = false; break; } } } if (hasData == false) { continue; } //初始化记录合约信息的列表 List <iVixInfo> thisMonthInfo = new List <iVixInfo>(); List <iVixInfo> nextMonthInfo = new List <iVixInfo>(); DataRow dr = dt.NewRow(); var now = callDataThisMonth[strikeListThisMonth[0]][index].TransactionDateTime; var expiredate1 = callListThisMonth[0].expireDate; var expiredate2 = callListNextMonth[0].expireDate; var span = date.AddHours(15) - now; //计算时间T NT:近月合约剩余到期时间(以分钟计) T:NT/365 double T1 = (durationThisMonth - 1 + (span.Hours * 60 + span.Minutes) / 840.0) / 365.0; //找到认购期权价格与认沽期权价格相差最小的执行价的K //计算远期价格F S+exp(RT)×[认购期权价格 S −认沽期权价格 S ] double distance1 = 100; double kThisMonth = 0; double F = 0; for (int i = 0; i < strikeListThisMonth.Count(); i++) { double distance0 = Math.Abs((callDataThisMonth[strikeListThisMonth[i]][index].Ask1 + callDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2 - (putDataThisMonth[strikeListThisMonth[i]][index].Ask1 + putDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2); if (distance0 < distance1) { distance1 = distance0; F = strikeListThisMonth[i] + Math.Exp(rate * T1) * ((callDataThisMonth[strikeListThisMonth[i]][index].Ask1 + callDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2 - (putDataThisMonth[strikeListThisMonth[i]][index].Ask1 + putDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2); } } //找到K0 for (int i = 0; i < strikeListThisMonth.Count() - 1; i++) { kThisMonth = strikeListThisMonth[i]; if (strikeListThisMonth[i + 1] > F) { break; } } //计算近月ivix for (int i = 0; i < strikeListThisMonth.Count(); i++) { iVixInfo info = new iVixInfo(); double ask = 0; double bid = 0; double dK = 0; double k = strikeListThisMonth[i]; if (i == strikeListThisMonth.Count() - 1) { dK = strikeListThisMonth[strikeListThisMonth.Count() - 1] - strikeListThisMonth[strikeListThisMonth.Count() - 2]; } else { dK = strikeListThisMonth[i + 1] - strikeListThisMonth[i]; } info.strike = k; info.duration = T1; info.coefficient = 2 / info.duration * dK / Math.Pow(info.strike, 2) * Math.Exp(rate * info.duration); if (strikeListThisMonth[i] < kThisMonth) { ask = putDataThisMonth[strikeListThisMonth[i]][index].Ask1; bid = putDataThisMonth[strikeListThisMonth[i]][index].Bid1; var mid = (ask + bid) / 2; info.sigma = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid, info.strike, info.duration, rate, "认沽"), 4); info.vega = ImpliedVolatilityExtension.ComputeOptionVega(info.strike, info.duration, rate, 0, info.sigma, F * Math.Exp(-rate * info.duration)) / 100.0; info.ask = ask; info.askv = putDataThisMonth[strikeListThisMonth[i]][index].AskV1; info.bid = bid; info.bidv = putDataThisMonth[strikeListThisMonth[i]][index].BidV1; info.minutelyVolume = ComputeMinutelyVolume(putDataThisMonth[strikeListThisMonth[i]], index); } else if (strikeListThisMonth[i] == kThisMonth) { ask = (putDataThisMonth[strikeListThisMonth[i]][index].Ask1 + callDataThisMonth[strikeListThisMonth[i]][index].Ask1) / 2; bid = (putDataThisMonth[strikeListThisMonth[i]][index].Bid1 + callDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2; var mid1 = (putDataThisMonth[strikeListThisMonth[i]][index].Ask1 + putDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2; var mid2 = (callDataThisMonth[strikeListThisMonth[i]][index].Ask1 + callDataThisMonth[strikeListThisMonth[i]][index].Bid1) / 2; var sigma1 = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid1, info.strike, info.duration, rate, "认沽"), 4); var sigma2 = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid2, info.strike, info.duration, rate, "认购"), 4); var vega1 = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, sigma1, F * Math.Exp(-rate * info.duration)) / 100.0; var vega2 = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, sigma2, F * Math.Exp(-rate * info.duration)) / 100.0; info.sigma = (sigma1 + sigma2) / 2; info.vega = (vega1 + vega2) / 2; info.ask = ask; info.askv = Math.Min(putDataThisMonth[strikeListThisMonth[i]][index].AskV1, callDataThisMonth[strikeListThisMonth[i]][index].AskV1) * 2; info.bid = bid; info.bidv = Math.Min(putDataThisMonth[strikeListThisMonth[i]][index].BidV1, callDataThisMonth[strikeListThisMonth[i]][index].BidV1) * 2; var volumeCall = ComputeMinutelyVolume(callDataThisMonth[strikeListThisMonth[i]], index); var volumePut = ComputeMinutelyVolume(putDataThisMonth[strikeListThisMonth[i]], index); info.minutelyVolume = Math.Min(volumeCall, volumePut) * 2; } else { ask = callDataThisMonth[strikeListThisMonth[i]][index].Ask1; bid = callDataThisMonth[strikeListThisMonth[i]][index].Bid1; var mid = (ask + bid) / 2; info.sigma = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid, info.strike, info.duration, rate, "认购"), 4); info.vega = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, info.sigma, F * Math.Exp(-rate * info.duration)) / 100.0; info.ask = ask; info.askv = callDataThisMonth[strikeListThisMonth[i]][index].AskV1; info.bid = bid; info.bidv = callDataThisMonth[strikeListThisMonth[i]][index].BidV1; info.minutelyVolume = ComputeMinutelyVolume(callDataThisMonth[strikeListThisMonth[i]], index); } sigma1Ask[index] += (2 / T1) * dK / (k * k) * Math.Exp(rate * T1) * ask; sigma1Bid[index] += (2 / T1) * dK / (k * k) * Math.Exp(rate * T1) * bid; thisMonthInfo.Add(info); } sigma1Ask[index] += -1 / T1 * Math.Pow((F / kThisMonth) - 1, 2); sigma1Bid[index] += -1 / T1 * Math.Pow((F / kThisMonth) - 1, 2); sigma1Ask[index] = Math.Sqrt(sigma1Ask[index]); sigma1Bid[index] = Math.Sqrt(sigma1Bid[index]); if (durationThisMonth > 30) { vixAsk[index] = sigma1Ask[index]; vixBid[index] = sigma1Bid[index]; } //计算时间T NT:近月合约剩余到期时间(以分钟计) T:NT/365 double T2 = (durationNextMonth - 1 + (span.Minutes) / 840) / 365.0; //找到认购期权价格与认沽期权价格相差最小的执行价的K //计算远期价格F S+exp(RT)×[认购期权价格 S −认沽期权价格 S ] distance1 = 100; double kNextMonth = 0; F = 0; for (int i = 0; i < strikeListNextMonth.Count(); i++) { double distance0 = Math.Abs((callDataNextMonth[strikeListNextMonth[i]][index].Ask1 + callDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2 - (putDataNextMonth[strikeListNextMonth[i]][index].Ask1 + putDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2); if (distance0 < distance1) { distance1 = distance0; F = strikeListNextMonth[i] + Math.Exp(rate * T2) * ((callDataNextMonth[strikeListNextMonth[i]][index].Ask1 + callDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2 - (putDataNextMonth[strikeListNextMonth[i]][index].Ask1 + putDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2); } } //找到K0 for (int i = 0; i < strikeListNextMonth.Count() - 1; i++) { kNextMonth = strikeListNextMonth[i]; if (strikeListNextMonth[i + 1] > F) { break; } } //计算远月ivix for (int i = 0; i < strikeListNextMonth.Count(); i++) { iVixInfo info = new iVixInfo(); double ask = 0; double bid = 0; double dK = 0; double k = strikeListNextMonth[i]; if (i == strikeListNextMonth.Count() - 1) { dK = strikeListNextMonth[strikeListNextMonth.Count() - 1] - strikeListNextMonth[strikeListNextMonth.Count() - 2]; } else { dK = strikeListNextMonth[i + 1] - strikeListNextMonth[i]; } info.strike = k; info.duration = T2; info.coefficient = 2 / info.duration * dK / Math.Pow(info.strike, 2) * Math.Exp(rate * info.duration); if (strikeListNextMonth[i] < kNextMonth) { ask = putDataNextMonth[strikeListNextMonth[i]][index].Ask1; bid = putDataNextMonth[strikeListNextMonth[i]][index].Bid1; var mid = (ask + bid) / 2; info.sigma = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid, info.strike, info.duration, rate, "认沽"), 4); info.vega = ImpliedVolatilityExtension.ComputeOptionVega(info.strike, info.duration, rate, 0, info.sigma, F * Math.Exp(-rate * info.duration)) / 100.0; info.ask = ask; info.askv = putDataNextMonth[strikeListNextMonth[i]][index].AskV1; info.bid = bid; info.bidv = putDataNextMonth[strikeListNextMonth[i]][index].BidV1; info.minutelyVolume = ComputeMinutelyVolume(putDataNextMonth[strikeListNextMonth[i]], index); } else if (strikeListNextMonth[i] == kNextMonth) { ask = (putDataNextMonth[strikeListNextMonth[i]][index].Ask1 + callDataNextMonth[strikeListNextMonth[i]][index].Ask1) / 2; bid = (putDataNextMonth[strikeListNextMonth[i]][index].Bid1 + callDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2; var mid1 = (putDataNextMonth[strikeListNextMonth[i]][index].Ask1 + putDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2; var mid2 = (callDataNextMonth[strikeListNextMonth[i]][index].Ask1 + callDataNextMonth[strikeListNextMonth[i]][index].Bid1) / 2; var sigma1 = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid1, info.strike, info.duration, rate, "认沽"), 4); var sigma2 = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid2, info.strike, info.duration, rate, "认购"), 4); var vega1 = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, sigma1, F * Math.Exp(-rate * info.duration)) / 100.0; var vega2 = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, sigma2, F * Math.Exp(-rate * info.duration)) / 100.0; info.sigma = (sigma1 + sigma2) / 2; info.vega = (vega1 + vega2) / 2; info.ask = ask; info.askv = Math.Min(putDataNextMonth[strikeListNextMonth[i]][index].AskV1, callDataNextMonth[strikeListNextMonth[i]][index].AskV1) * 2; info.bid = bid; info.bidv = Math.Min(putDataNextMonth[strikeListNextMonth[i]][index].BidV1, callDataNextMonth[strikeListNextMonth[i]][index].BidV1) * 2; var volumeCall = ComputeMinutelyVolume(callDataNextMonth[strikeListNextMonth[i]], index); var volumePut = ComputeMinutelyVolume(putDataNextMonth[strikeListNextMonth[i]], index); info.minutelyVolume = Math.Min(volumeCall, volumePut) * 2; } else { ask = callDataNextMonth[strikeListNextMonth[i]][index].Ask1; bid = callDataNextMonth[strikeListNextMonth[i]][index].Bid1; var mid = (ask + bid) / 2; info.sigma = Math.Round(ImpliedVolatilityExtension.sigmaByFuture(F, mid, info.strike, info.duration, rate, "认购"), 4); info.vega = ImpliedVolatilityExtension.ComputeOptionVega(k, info.duration, rate, 0, info.sigma, F * Math.Exp(-rate * info.duration)) / 100.0; info.ask = ask; info.askv = callDataNextMonth[strikeListNextMonth[i]][index].AskV1; info.bid = bid; info.bidv = callDataNextMonth[strikeListNextMonth[i]][index].BidV1; info.minutelyVolume = ComputeMinutelyVolume(callDataNextMonth[strikeListNextMonth[i]], index); } sigma2Ask[index] += (2 / T2) * dK / (k * k) * Math.Exp(rate * T2) * ask; sigma2Bid[index] += (2 / T2) * dK / (k * k) * Math.Exp(rate * T2) * bid; nextMonthInfo.Add(info); } sigma2Ask[index] += -1 / T2 * Math.Pow((F / kNextMonth) - 1, 2); sigma2Bid[index] += -1 / T2 * Math.Pow((F / kNextMonth) - 1, 2); sigma2Ask[index] = Math.Sqrt(sigma2Ask[index]); sigma2Bid[index] = Math.Sqrt(sigma2Bid[index]); if (durationThisMonth <= 30) { vixAsk[index] = Math.Sqrt((T1 * Math.Pow(sigma1Ask[index], 2) * (T2 - 30.0 / 365.0) / (T2 - T1) + T2 * Math.Pow(sigma2Ask[index], 2) * (30.0 / 365.0 - T1) / (T2 - T1)) * 365.0 / 30.0); vixBid[index] = Math.Sqrt((T1 * Math.Pow(sigma1Bid[index], 2) * (T2 - 30.0 / 365.0) / (T2 - T1) + T2 * Math.Pow(sigma2Bid[index], 2) * (30.0 / 365.0 - T1) / (T2 - T1)) * 365.0 / 30.0); foreach (var item in thisMonthInfo) { item.coefficient *= T1 * (T2 - 30.0 / 365.0) / (T2 - T1) * 365.0 / 30.0; } foreach (var item in nextMonthInfo) { item.coefficient *= T2 * (30.0 / 365.0 - T1) / (T2 - T1) * 365.0 / 30.0; } } //计算整体的vega,以及盘口的量 double vegaTotal = 0; double number = 0; double percentAskMax = 0; double percentAskMin = 1; double percentBidMax = 0; double percentBidMin = 1; double percentVolumeMax = 0; double percentVolumeMin = 1; if (durationThisMonth > 30) { foreach (var item in thisMonthInfo) { vegaTotal += item.vega * item.coefficient * 10000; } number = cashVega / vegaTotal; foreach (var item in thisMonthInfo) { double percentAsk = item.askv / number; double percentBid = item.bidv / number; double percentVolume = item.minutelyVolume / number; if (percentAsk > percentAskMax) { percentAskMax = percentAsk; } if (percentAsk < percentAskMin) { percentAskMin = percentAsk; } if (percentBid > percentBidMax) { percentBidMax = percentBid; } if (percentBid < percentBidMin) { percentBidMin = percentBid; } if (percentVolume > percentVolumeMax) { percentVolumeMax = percentVolume; } if (percentVolume < percentVolumeMin) { percentVolumeMin = percentVolume; } } } else { foreach (var item in thisMonthInfo) { vegaTotal += item.vega * item.coefficient * 10000; } foreach (var item in nextMonthInfo) { vegaTotal += item.vega * item.coefficient * 10000; } number = cashVega / 2 / vegaTotal; foreach (var item in thisMonthInfo) { double percentAsk = item.askv / number / item.coefficient; double percentBid = item.bidv / number / item.coefficient; double percentVolume = item.minutelyVolume / number; if (percentAsk > percentAskMax) { percentAskMax = percentAsk; } if (percentAsk < percentAskMin) { percentAskMin = percentAsk; } if (percentBid > percentBidMax) { percentBidMax = percentBid; } if (percentBid < percentBidMin) { percentBidMin = percentBid; } if (percentVolume > percentVolumeMax) { percentVolumeMax = percentVolume; } if (percentVolume < percentVolumeMin) { percentVolumeMin = percentVolume; } } foreach (var item in nextMonthInfo) { double percentAsk = item.askv / number / item.coefficient; double percentBid = item.bidv / number / item.coefficient; double percentVolume = item.minutelyVolume / number; if (percentAsk > percentAskMax) { percentAskMax = percentAsk; } if (percentAsk < percentAskMin) { percentAskMin = percentAsk; } if (percentBid > percentBidMax) { percentBidMax = percentBid; } if (percentBid < percentBidMin) { percentBidMin = percentBid; } if (percentVolume > percentVolumeMax) { percentVolumeMax = percentVolume; } if (percentVolume < percentVolumeMin) { percentVolumeMin = percentVolume; } } } dr["tdatetime"] = now; dr["expiredate1"] = expiredate1; dr["expiredate2"] = expiredate2; dr["duration1"] = Math.Round(T1, 6); dr["duration2"] = Math.Round(T2, 6); dr["sigma1Ask"] = Math.Round(sigma1Ask[index] * 100, 4); dr["sigma1Bid"] = Math.Round(sigma1Bid[index] * 100, 4); dr["sigma2Ask"] = Math.Round(sigma2Ask[index] * 100, 4); dr["sigma2Bid"] = Math.Round(sigma2Bid[index] * 100, 4); dr["sigmaAsk"] = Math.Round(vixAsk[index] * 100, 4); dr["sigmaBid"] = Math.Round(vixBid[index] * 100, 4); dr["vegaTotal"] = Math.Round(vegaTotal, 4); dr["number"] = Math.Round(number, 4); dr["percentAskMax"] = Math.Round(percentAskMax, 4); dr["percentAskMin"] = Math.Round(percentAskMin, 4); dr["percentBidMax"] = Math.Round(percentBidMax, 4); dr["percentBidMin"] = Math.Round(percentBidMin, 4); dr["percentVolumeMax"] = Math.Round(percentVolumeMax, 4); dr["percentVolumeMin"] = Math.Round(percentVolumeMin, 4); if (now < date.Date + new TimeSpan(14, 57, 00)) { dt.Rows.Add(dr); } } SaveResultToMssql(date, dt); } }