Files
zszq-trs/Tools/YLTestTool/Forms/FormOption.cs
T
2024-05-09 14:06:26 +08:00

676 lines
20 KiB
C#

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<trade> { 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<trade>(tdInput);
break;
case "JSON数据(tradeFull)":
tdFull = JsonHelper.Deserialize<OtcOptionTradeFull>(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<trade>(t => t.id == tradeId)
: PredicateBuilder.Create<trade>(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<KeyValuePair<string, string>>();
foreach (var line in lines)
{
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
var index = line.IndexOf(':');
if (index < 0)
{
continue;
}
list.Add(new KeyValuePair<string, string>(line.Substring(0, index).Trim(), line.Substring(index + 1).Trim()));
}
//var fc = new FormDataCollection(list);
//var data = fc.ReadAs<InnerFormData>();
//return data?.trades != null ? data.trades.FirstOrDefault() : null;
return null;
}
/// <summary>
///
/// </summary>
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<OtcOptionTradeFull> trades { get; set; }
}
#endregion
private void FormOption_Load(object sender, EventArgs e)
{
cmbTradeDataSource.SelectedIndex = 1;
menuStrip1.AllowMerge = false;
}
}
}