using YLErp.BLL.MarginCalculation; using YLErp.DBModels; using YLErp.Enums; using YLErp.Modules; using YLErp.Modules.CalculationModule; using YLErp.Modules.DataProviderModule; using YLErp.Modules.EodModule.SettlementModule; using YLErp.Modules.PricingModule; using YLErp.Modules.TradeModule; using YLErp.Modules.VolatilityModule; namespace YLErp.Forms { public partial class FormOption : Form { readonly RichTextBoxWriter _rbWriter; FormJsonView _formJsonView; public FormOption() { InitializeComponent(); _rbWriter = new RichTextBoxWriter(richTextBoxLog); } private void ShowJson(object obj) { var json = JsonHelper.Serialize(obj); _rbWriter.WriteLine(json); if (_formJsonView == null) { _formJsonView = new FormJsonView(); } _formJsonView.SetJson(json).ShowDialog(); } //查看交易 private void btnViewTrade_Click(object sender, EventArgs e) { var data = GetCalcData(null); if (data == null) { return; } _rbWriter.Clear().WriteLine(btnViewTrade.Text); ShowJson(data.trade); } //定价计算 private void btnPricing_Click(object sender, EventArgs e) { ExecPricing(); } private void btnPricingV2_Click(object sender, EventArgs e) { ExecPricing("V2"); } private void ExecPricing(string calcVersion = "V1") { var data = GetCalcData(null); if (data == null) { return; } var tdFull = data.tradeFull; ResetTrade(tdFull); _rbWriter.Clear().Write(DateTime.Now.ToString() + " ").WriteLine(btnPricing.Text); tdFull.OptionType = "看涨"; var result = new PriceCalcService(GetOptUserInfo()).CalcOptionPrice(tdFull, calcMargin: false, CalcScenarioEnum.Pricing, calcVersion: calcVersion); ShowJson(result); _rbWriter.WriteLine(DateTime.Now); } private void btnViewPosition_Click(object sender, EventArgs e) { var valueDate = GetPosCalcValueDate(); var data = GetCalcData(valueDate); if (data == null) { return; } _rbWriter.Clear().WriteLine(btnViewPosition.Text); ShowJson(data.trade); } //计算持仓PV private void btnCalcPv_Click(object sender, EventArgs e) { var data = GetCalcDataV2(); if (data == null) { return; } _rbWriter.Clear().WriteLine(btnCalcPv.Text); var sw = new System.Diagnostics.Stopwatch(); sw.Start(); var td = data.trade; var req = new OptionValueCalcRequest(td.NoRiskRate ?? BLL.valuedateBLL.SysRiskFreeRate()) { vols = new[] { data.vol }, spotPrices = new[] { data.underlyingPrice }, preciseTimeMode = checkRealTime.Checked, calcDeltaT1 = true, calcScenario = Enums.CalcScenarioEnum.RealtimeRisk }; var result = OptionCalculatorV2.GetOptionValueResult(data.valueDate, td, req, out _); sw.Stop(); _rbWriter.WriteLine($"耗时{sw.ElapsedMilliseconds / 1000}秒,pv:{result.Pv}"); ShowJson(result); } //计算持仓保证金 private void btnCalcMargin_Click(object sender, EventArgs e) { var data = GetCalcDataV2(); if (data == null) { return; } _rbWriter.Clear().WriteLine(btnCalcMargin.Text); var sw = new System.Diagnostics.Stopwatch(); sw.Start(); var td = data.trade; var priceProvider = new ManualPriceProvider(); priceProvider.SetPrice(td.UnderlyingCode, data.underlyingPrice); var req = new RunMarginCalculationReq(OptUserInfo.UnitTestUser) { forOtherSide = false, hasOptionInfo = true, PriceProvider = priceProvider, settleDate = data.valueDate, tradeList = new List { td }, volType = "持仓", CalcMarginType = checkRealTime.Checked ? Enums.CalcMarginTypeEnum.None : Enums.CalcMarginTypeEnum.EodMargin, }; var list = MarginDefault.RunMarginCalculation(req); sw.Stop(); _rbWriter.WriteLine($"耗时{sw.ElapsedMilliseconds / 1000}秒"); if (list.Count < 1) { _rbWriter.WriteLine($"没有取到日期'{data.valueDate:yyyy-MM-dd}'的保证金"); } else { ShowJson(list[0]); } } //是否实时风险 private void checkRealTime_CheckedChanged(object sender, EventArgs e) { if (checkRealTime.Checked) { dateTimePicker1.Enabled = false; dateTimePicker1.Value = BLL.valuedateBLL.ValueDate; btnViewPosition.Text = "查看实时持仓"; btnCalcPv.Text = "计算实时PV"; btnCalcMargin.Text = "计算实时保证金"; } else { dateTimePicker1.Enabled = true; btnViewPosition.Text = "查看日终持仓"; btnCalcPv.Text = "计算日终PV"; btnCalcMargin.Text = "计算日终保证金"; } } //获取实时行情标的价格 private void menuGetCurUmPrice_Click(object sender, EventArgs e) { var data = GetCalcData(null); if (data == null) { return; } var um = DbContextFactory.GetYLDbContext().underlying_manager .Where(n => n.UnderlyingCode == data.trade.UnderlyingCode) .Select(n => new { n.Price }).FirstOrDefault(); if (um == null) { tbUnderlyingPrice.Text = string.Empty; _rbWriter.WriteLine("标的数据不存在:" + data.trade.UnderlyingCode); } else { tbUnderlyingPrice.Text = um.Price?.ToString("F4"); } } //日终收盘价 private void menuGetEodClosePrice_Click(object sender, EventArgs e) { var data = GetCalcData(null); if (data == null) { return; } var valueDate = GetPosCalcValueDate(); var provider = new EodPriceProvider(valueDate); if (provider.TryGetEodPrice(data.trade.UnderlyingCode, out var eodPrice)) { tbUnderlyingPrice.Text = eodPrice.ClosePrice.ToString("F4"); } else { tbUnderlyingPrice.Text = string.Empty; _rbWriter.WriteLine($"日期'{valueDate:yyyy-MM-dd}',标的收盘价不存在:{data.trade.UnderlyingCode}"); } } //日终结算价 private void menuGetEodSettlePrice_Click(object sender, EventArgs e) { var data = GetCalcData(null); if (data == null) { return; } var valueDate = GetPosCalcValueDate(); var provider = new EodPriceProvider(valueDate); if (provider.TryGetEodPrice(data.trade.UnderlyingCode, out var eodPrice)) { tbUnderlyingPrice.Text = eodPrice.SettlePrice.ToString("F4"); } else { tbUnderlyingPrice.Text = string.Empty; _rbWriter.WriteLine($"日期'{valueDate:yyyy-MM-dd}',标的结算价不存在:{data.trade.UnderlyingCode}"); } } //日终参考价 private void menuGetEodRefPrice_Click(object sender, EventArgs e) { var data = GetCalcData(null); if (data == null) { return; } var valueDate = GetPosCalcValueDate(); var provider = new EodPriceProvider(valueDate); if (provider.TryGetEodPrice(data.trade.UnderlyingCode, out var eodPrice)) { tbUnderlyingPrice.Text = eodPrice.GetPrice(SettlementTypeEnum.ReferencePrice).ToString("F4"); } else { tbUnderlyingPrice.Text = string.Empty; _rbWriter.WriteLine($"日期'{valueDate:yyyy-MM-dd}',标的参考价不存在:{data.trade.UnderlyingCode}"); } } //持仓波动率 private void menuGetPositionVol_Click(object sender, EventArgs e) { var data = GetCalcData(null); if (data == null) { return; } var td = data.trade; var valueDate = GetPosCalcValueDate(); var provider = new TradeVolitalityProvider(valueDate) { Initialized = true }; if (provider.TryGetVol(td.id, td.ExerciseDate ?? valueDate, out var vol)) { tbVol.Text = vol.ToString("P4"); } else { _rbWriter.WriteLine($"未获取到持仓波动率,交易编号:{td.TradeNumber},交易ID:{td.id},日期:{valueDate:yyyy-MM-dd}"); } } //对冲波动率 private void menuGetHedgeVol_Click(object sender, EventArgs e) { var data = GetCalcData(null); if (data == null) { return; } var td = data.trade; var valueDate = GetPosCalcValueDate(); var provider = new TradeHedgeVolProvider(valueDate) { Initialized = true }; if (provider.TryGetVol(td.id, out var vol)) { tbVol.Text = vol.ToString("P4"); } else { _rbWriter.WriteLine($"未获取到对冲波动率,交易编号:{td.TradeNumber},交易ID:{td.id},日期:{valueDate:yyyy-MM-dd}"); } } //开仓波动率 private void menuGetOpenVol_Click(object sender, EventArgs e) { var data = GetCalcData(null); if (data == null) { return; } tbVol.Text = data.trade.TradeOpenVolatility?.ToString("P4"); } #region----计算数据处理---- private DateTime GetPosCalcValueDate() { return QdpModule.QdpCalendarHelper.GetNonHoliday(dateTimePicker1.Value.Date); } private CalcDataV2 GetCalcDataV2() { var valueDate = GetPosCalcValueDate(); var data = GetCalcData(checkRealTime.Checked ? null : valueDate); if (data == null) { return null; } if (!double.TryParse(tbUnderlyingPrice.Text, out var underlyingPrice)) { MessageBox.Show("解析标的价格失败:" + tbUnderlyingPrice.Text); return null; } if (!NumberHelper.TryParse(tbVol.Text, out var vol, out var isPercent)) { MessageBox.Show("解析波动率失败:" + tbVol.Text); return null; } return new CalcDataV2(data) { vol = vol, underlyingPrice = underlyingPrice, valueDate = valueDate }; } private CalcData GetCalcData(DateTime? eodValueDate) { try { var tdInput = richTextBoxTrade.Text.Trim(); trade td = null; OtcOptionTradeFull tdFull = null; string errMsg = null; switch (cmbTradeDataSource.Text) { case "交易ID": errMsg = GetDataByTradeId(tdInput, out td, out tdFull, eodValueDate); break; case "交易编号": errMsg = GetDataByTradeNumber(tdInput, out td, out tdFull, eodValueDate); break; case "表单数据(定价请求)": tdFull = ParseFormData(richTextBoxTrade.Lines); break; case "JSON数据(trade)": td = JsonHelper.Deserialize(tdInput); break; case "JSON数据(tradeFull)": tdFull = JsonHelper.Deserialize(tdInput); break; } if (!string.IsNullOrEmpty(errMsg)) { MessageBox.Show(errMsg); return null; } if (td == null && tdFull == null) { MessageBox.Show("交易数据不存在"); return null; } if (td == null) { td = TradeConverter.ConvertOptionTrade(tdFull); } if (tdFull == null) { tdFull = TradeConverter.ConvertToOptionTrade(td); } return new CalcData(td, tdFull); } catch (Exception ex) { MessageBox.Show(ex.ToString()); return null; } } private static string GetDataByTradeId(string tradeIdStr, out trade td, out OtcOptionTradeFull tdFull, DateTime? eodValueDate) { td = null; tdFull = null; if (string.IsNullOrEmpty(tradeIdStr)) { return "请填写交易ID"; } if (!int.TryParse(tradeIdStr, out var tradeId)) { return "交易ID未能正确解析成整数:" + tradeIdStr; } if (eodValueDate.HasValue) { td = GetEodTrade(eodValueDate.Value, tradeId, null); } else { tdFull = new TradeDetailsQueryService(GetOptUserInfo()).GetOtcTradeFull(tradeId); } return null; } private string GetDataByTradeNumber(string tradeNumber, out trade td, out OtcOptionTradeFull tdFull, DateTime? eodValueDate) { td = null; tdFull = null; if (string.IsNullOrEmpty(tradeNumber)) { return "请填写交易编号"; } if (eodValueDate.HasValue) { td = GetEodTrade(eodValueDate.Value, 0, tradeNumber); } else { tdFull = new TradeDetailsQueryService(GetOptUserInfo()).GetOtcTradeFull(tradeNumber); } return null; } private static trade GetEodTrade(DateTime valueDate, int tradeId, string tradeNumber) { var predicateBuilder = new EodQueryPredicateBuilder(new EodSettlementRequest(GetOptUserInfo()) { SettleDate = valueDate, UseClosePrice = true, VolType = "持仓" }); var predicate = string.IsNullOrEmpty(tradeNumber) ? PredicateBuilder.Create(t => t.id == tradeId) : PredicateBuilder.Create(t => t.TradeNumber == tradeNumber); predicate = predicate.And(predicateBuilder.GetOtcTradePredicate()); var otcTrades = new EodSettleDataQueryService(GetOptUserInfo()) .GetOtcTrades(valueDate, predicate, out var tradeCashProvider); if (valueDate != BLL.valuedateBLL.ValueDate && otcTrades.Any()) { var hisDataProvider = new TradeHisDataProvider(valueDate).Initialize(); foreach (var item in otcTrades) { item.NoRiskRate = hisDataProvider.GetNoRiskRate(item.id) ?? item.NoRiskRate ?? BLL.valuedateBLL.RiskFreeRate; item.DividendRate = hisDataProvider.GetDividendRate(item.id); if (item.DividendRate == null) { item.DividendRate = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode).DividendRate ?? item.NoRiskRate; } } } return otcTrades.FirstOrDefault(); } private static OtcOptionTradeFull ParseFormData(string[] lines) { var list = new List>(); foreach (var line in lines) { if (string.IsNullOrWhiteSpace(line)) { continue; } var index = line.IndexOf(':'); if (index < 0) { continue; } list.Add(new KeyValuePair(line.Substring(0, index).Trim(), line.Substring(index + 1).Trim())); } //var fc = new FormDataCollection(list); //var data = fc.ReadAs(); //return data?.trades != null ? data.trades.FirstOrDefault() : null; return null; } /// /// /// private static void ResetTrade(OtcTradeBase otcTrade) { if (otcTrade is null) { return; } otcTrade.id = 0; otcTrade.TradeNumber = string.Empty; otcTrade.Notional = otcTrade.OriginalNotional ?? 0; otcTrade.StockEqvNotional = otcTrade.OriginalStockEqvNotional ?? 0; var um = DataCacheProvider.GetUnderlyingDataSource().GetData(otcTrade.UnderlyingCode); otcTrade.TradeAmount = otcTrade.Notional / (um?.CountRatio ?? 1); otcTrade.ParentTradeId = 0; otcTrade.UnWindDate = null; otcTrade.FinalPrice = null; otcTrade.UnWindNotional = null; otcTrade.HasPartialUnWind = null; otcTrade.CheckStatus = null; otcTrade.ProcessOrderId = 0; otcTrade.ProcessOptDate = null; otcTrade.ProcessStatus = null; otcTrade.DividendDate = new DateTime(2000, 1, 1); otcTrade.StructureType = string.Empty; otcTrade.StructureIntroduction = string.Empty; otcTrade.StockEqvNotional = otcTrade.StockEqvNotional.OtcFormatValue(OtcFormatFlag.StockEqvNotional); otcTrade.StockEqvNotionalReal = otcTrade.StockEqvNotionalReal.OtcFormatValue(OtcFormatFlag.StockEqvNotional); } private static OptUserInfo GetOptUserInfo() { return OptUserInfo.SystemUser; } class CalcData { public trade trade { get; } public OtcOptionTradeFull tradeFull { get; } public DateTime timestamp { get; private set; } public CalcData(trade trade, OtcOptionTradeFull tradeFull) { timestamp = DateTime.Now; this.trade = trade ?? throw new ArgumentNullException(nameof(trade)); this.tradeFull = tradeFull ?? throw new ArgumentNullException(nameof(tradeFull)); } public void UpdateTimeStampe() { timestamp = DateTime.Now; } public CalcData Clone() { return new CalcData(trade.Clone(), tradeFull.Clone()); } } class CalcDataV2 { public DateTime valueDate; public double underlyingPrice; public double vol; readonly CalcData _data; public CalcDataV2(CalcData data) { _data = data ?? throw new ArgumentNullException(nameof(data)); } public trade trade => _data.trade; public OtcOptionTradeFull tradeFull => _data.tradeFull; } class InnerFormData { public IEnumerable trades { get; set; } } #endregion private void FormOption_Load(object sender, EventArgs e) { cmbTradeDataSource.SelectedIndex = 1; menuStrip1.AllowMerge = false; } } }