2165 lines
88 KiB
C#
2165 lines
88 KiB
C#
using BaseOUDAL;
|
|
using Qdp.Foundation.Implementations;
|
|
using System.Text.RegularExpressions;
|
|
using YLErp.Abstract.DataProviders;
|
|
using YLErp.Commons;
|
|
using YLErp.DBModels.Consts;
|
|
using YLErp.Model;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.Modules.SuperviseReportModule.CFMMC2022.Model;
|
|
using YLErp.Modules.TradeModule;
|
|
using YLErp.QdpModule;
|
|
using static YLErp.Modules.SuperviseReportModule.CFMMC2022.Model.SuperviseReportBaseModel;
|
|
|
|
namespace YLErp.Modules.SuperviseReportModule.CFMMC2022.Service
|
|
{
|
|
public abstract class SuperviseReportBaseService : YLBaseService
|
|
{
|
|
protected SuperviseReportReq _req { get; set; }
|
|
|
|
/// <summary>
|
|
/// 分隔符
|
|
/// <para>分号</para>
|
|
/// </summary>
|
|
protected string _separator => ";";
|
|
|
|
protected IEodPriceProviderWrap _priceProvider;
|
|
|
|
protected SuperviseReportBaseService(SuperviseReportReq req, OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
_req = req ?? throw new ArgumentNullException(nameof(req));
|
|
|
|
_priceProvider = new EodPriceProvider(_req.ValueDate).GetPriceProvider(SettlementTypeEnum.ClosePrice);
|
|
}
|
|
|
|
private readonly List<string> ignoreTradeTypes = new List<string>() { "区间累积期权" };
|
|
|
|
|
|
/// <summary>
|
|
/// 了结交易类型代码集合
|
|
/// </summary>
|
|
private readonly List<string> tradeTypes = new List<string>() { "PU", "FU", "ED" };
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="model"></param>
|
|
/// <param name="varietyTypes">标的资产类型</param>
|
|
/// <param name="assetTypes">资产类型</param>
|
|
/// <param name="varietySuffixs">标的资产品种后缀和标的资产对应合约后缀</param>
|
|
/// <param name="syntheticPrice">组合标的价格</param>
|
|
/// <exception cref="ServiceException">EodTrade不存在时抛出</exception>
|
|
protected virtual void FormatModel(SuperviseReportBaseModel model, List<DictionaryItem> assetTypes, List<DictionaryItem> varietySuffixs, List<DictionaryItem> varietyCodeList, out SyntheticPriceModel syntheticPrice)
|
|
{
|
|
if (model.trade == null)
|
|
{
|
|
throw new ServiceException($"日终Trade不存在,交易编号:{model.OriginalTradeNumber}");
|
|
}
|
|
|
|
//工具类型
|
|
model.ToolType = formatToolType(model.trade.TradeType, model.StructureType);
|
|
|
|
//当“工具类型”为OP或FW时,该字段只能填报B或S
|
|
if (model.ToolType == "OP")
|
|
{
|
|
model.ClientDirection = model.trade.BuySell == "买入" ? "B" : "S";
|
|
}
|
|
else if (model.ToolType == "FW")
|
|
{
|
|
model.ClientDirection =
|
|
(model.trade.BuySell == "买入" && model.trade.OptionType == "看涨") ||
|
|
(model.trade.BuySell == "卖出" && model.trade.OptionType == "看跌")
|
|
? "B" : "S";
|
|
}
|
|
//当“工具类型“为SW时,该字段只能填报P或R
|
|
else if (model.ToolType == "SW")
|
|
{
|
|
model.ClientDirection = model.trade.trade_swap.IsGetFloatingProfit ? "P" : "R";
|
|
}
|
|
|
|
//期初价格
|
|
model.UnderlyingInitialPrice = model.trade.SpotPrice.OtcFormatFlex(2); //formatTradeAmount(model.trade.SpotPrice);
|
|
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(model.trade.UnderlyingCode);
|
|
if (um.IsSynthetic() || !string.IsNullOrWhiteSpace(model.trade.BasisUnderlyingCode))
|
|
{
|
|
var marketNoDict = new Dictionary<string, string>();
|
|
var query = DbContext.TradeMeta.Where(O => O.TradeId == model.trade.id && O.MetaValue.Length > 5);
|
|
if (um.IsSynthetic())
|
|
{
|
|
query = query.Where(O => O.MetaKey.StartsWith(ConsTradeMetaKey.SyntheticUnderlying));
|
|
var tradeMeta = query.FirstOrDefault();
|
|
if (string.IsNullOrWhiteSpace(tradeMeta?.MetaValue))
|
|
{
|
|
throw new ServiceException($"组合标的期初价格信息不完整,交易编号:{model.OriginalTradeNumber}");
|
|
}
|
|
syntheticPrice = JsonHelper.Deserialize<SyntheticPriceModel>(tradeMeta.MetaValue);
|
|
if (syntheticPrice.SuList == null)
|
|
{
|
|
throw new ServiceException($"组合标的价格缺失,交易编号:{model.trade.TradeNumber}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
query = query.Where(O => O.MetaKey == ConsTradeMetaKey.SpotInfos);
|
|
var tradeMeta = query.FirstOrDefault();
|
|
string[] arrPrice = null;
|
|
if (string.IsNullOrWhiteSpace(tradeMeta?.MetaValue))
|
|
{
|
|
arrPrice = new[] { model.trade.SpotPrice?.ToString() };
|
|
}
|
|
else
|
|
{
|
|
arrPrice = JsonHelper.Deserialize<string[]>(tradeMeta.MetaValue);
|
|
if (arrPrice == null || arrPrice.Length == 0)
|
|
{
|
|
throw new ServiceException($"期初价格缺失,交易编号:{model.trade.TradeNumber}");
|
|
}
|
|
}
|
|
var prides = new UnderlyingPriceModel[arrPrice.Length];
|
|
for (var i = 0; i < arrPrice.Length; i++)
|
|
{
|
|
prides[i] = new UnderlyingPriceModel
|
|
{
|
|
Price = double.TryParse(arrPrice[i], out var p) ? p : 0,
|
|
Coefficient = i == 0 ? 1 : -1,
|
|
UnderlyingCode = i == 0 ? model.trade.UnderlyingCode : model.trade.BasisUnderlyingCode
|
|
};
|
|
}
|
|
syntheticPrice = new SyntheticPriceModel
|
|
{
|
|
SuList = prides
|
|
};
|
|
}
|
|
var underlyingCodes = syntheticPrice.SuList.Select(O => O).ToArray();
|
|
var arrCode = new string[underlyingCodes.Length];
|
|
var arrUnitZh = new string[underlyingCodes.Length];
|
|
var arrUnitEn = new string[underlyingCodes.Length];
|
|
var arrVarietyType = new string[underlyingCodes.Length];
|
|
var arrUnderlyingPlate = new string[underlyingCodes.Length];
|
|
|
|
var arrDeltaCash = new string[underlyingCodes.Length];
|
|
|
|
//多表的资产类型
|
|
var vTypeIsOther = false;
|
|
var vTypeStr = "";
|
|
|
|
//多标的数量单位
|
|
var vUnitEnIsOther = false;
|
|
var vUnitEnStr = "";
|
|
for (var i = 0; i < underlyingCodes.Length; i++)
|
|
{
|
|
if (underlyingCodes[i] == null || string.IsNullOrWhiteSpace(underlyingCodes[i].UnderlyingCode))
|
|
{
|
|
arrCode[i] = null;
|
|
arrUnitZh[i] = null;
|
|
arrUnitEn[i] = null;
|
|
arrVarietyType[i] = null;
|
|
continue;
|
|
}
|
|
var variety = UnderlyingDataProvider.GetVariety(underlyingCodes[i].UnderlyingCode);
|
|
if (variety == null) { throw new ServiceException($"未找到品种数据: {underlyingCodes[i].UnderlyingCode}"); }
|
|
var um1 = UnderlyingDataProvider.GetUnderlying(underlyingCodes[i].UnderlyingCode);
|
|
var varietySuffix = formatDictItem(varietySuffixs, um1?.MarketCode, um1?.MarketCode);
|
|
marketNoDict[underlyingCodes[i].UnderlyingCode] = varietySuffix;
|
|
arrCode[i] = formatVarietyCode(underlyingCodes[i].UnderlyingCode, variety, varietyCodeList, varietySuffix);
|
|
arrUnitZh[i] = um?.QuoteUnit;//variety.QuoteUnitSingleOriginal;
|
|
//arrUnitEn[i] = formatQuoteUnit(arrUnitZh[i]);
|
|
//arrVarietyType[i] = formatVariety(variety.MainCategory);
|
|
arrUnderlyingPlate[i] = formatUnderlyingPlate(variety.AssetType);
|
|
|
|
arrDeltaCash[i] = OtcFormatHelper.FormatValue((model._delta * underlyingCodes[i].Price), 4).ToString();
|
|
|
|
//多标的数量单位,如果不同的数量单位,就报其他(O)
|
|
if (string.IsNullOrEmpty(vUnitEnStr))
|
|
{
|
|
vUnitEnStr = arrUnderlyingPlate[i] == "IN" ? "元/指数点" : formatQuoteUnit(arrUnitZh[i]);
|
|
}
|
|
else
|
|
{
|
|
if (vUnitEnStr != (arrUnderlyingPlate[i] == "IN" ? "元/指数点" : formatQuoteUnit(arrUnitZh[i])))
|
|
{
|
|
vUnitEnIsOther = true;
|
|
}
|
|
}
|
|
|
|
//多标的资产类型,如果不同的资产类型,就报其他(O)
|
|
if (string.IsNullOrEmpty(vTypeStr))
|
|
{
|
|
vTypeStr = formatVariety(variety.MainCategory);
|
|
}
|
|
else
|
|
{
|
|
if (vTypeStr != formatVariety(variety.MainCategory))
|
|
{
|
|
vTypeIsOther = true;
|
|
}
|
|
}
|
|
}
|
|
model.UnderlyingCode = formatSyntheticUnderlying(syntheticPrice, marketNoDict);
|
|
model.VarietyCode = JoinArr(arrCode);
|
|
//model.QuoteUnitEn = JoinArr(arrUnitEn);
|
|
model.QuoteUnitEn = vUnitEnIsOther ? "Other" : vUnitEnStr;
|
|
//model.VarietyType = JoinArr(arrVarietyType);
|
|
model.VarietyType = vTypeIsOther ? "O" : vTypeStr;
|
|
model.UnderlyingPlate = JoinArr(arrUnderlyingPlate);
|
|
|
|
model.DeltaCash = JoinArr(arrDeltaCash);
|
|
}
|
|
else
|
|
{
|
|
var variety = UnderlyingDataProvider.GetVariety(model.trade.UnderlyingCode);
|
|
if (variety == null) { throw new ServiceException($"未找到品种数据: {model.trade.UnderlyingCode}"); }
|
|
var varietySuffix = formatDictItem(varietySuffixs, um?.MarketCode, um?.MarketCode);
|
|
model.UnderlyingCode = formatUnderlyingCode(model.trade.UnderlyingCode, varietySuffix);
|
|
model.VarietyCode = formatVarietyCode(model.trade.UnderlyingCode, variety, varietyCodeList, varietySuffix);
|
|
model.VarietyType = formatVariety(variety.MainCategory);
|
|
model.UnderlyingPlate = formatUnderlyingPlate(variety.AssetType);
|
|
model.QuoteUnitEn = model.UnderlyingPlate == "IN" ? "元/指数点" : formatQuoteUnit(um?.QuoteUnit);
|
|
model.DeltaCash = OtcFormatHelper.FormatValue((model._delta * model._price ?? model.trade.SpotPrice), 4).ToString();
|
|
syntheticPrice = null;
|
|
}
|
|
|
|
if (um?.UnderlyingInstrumentType == "Stock")
|
|
{
|
|
model.IsStock = true;
|
|
}
|
|
|
|
model.UnderlyingInitialPriceSymbol = formatPriceSymbol(model.UnderlyingPlate);
|
|
|
|
if (model.UnderlyingInitialPriceSymbol == "1")
|
|
{
|
|
model.UnderlyingInitialPriceCurrency = "CNY";
|
|
}
|
|
|
|
|
|
//期权行权时间类型
|
|
model.ExerciseMode = IsOption(model.trade) && model.trade.TradeType != "自定义交易" ? (model.trade.ExerciseMode == "European" ? "EU" : "US") : "O";
|
|
//国投特殊处理
|
|
model.ExerciseMode = PS.Config.Company == Configuration.CompanyEnum.国投 && model.trade.TradeType == "雪球期权" ? "O" : model.ExerciseMode;
|
|
|
|
model.OptionType = ignoreTradeTypes.Contains(model.trade.TradeType) ? "9" : IsOption(model.trade) ? (model.trade.OptionType == "看涨" ? "2" : "1") : "9";
|
|
|
|
if (model.ToolType == "FW" || model.ToolType == "SW")
|
|
{
|
|
model.ExerciseMode = null;
|
|
model.OptionType = null;
|
|
}
|
|
|
|
//看跌是1,看涨是2,价差是9
|
|
if (model.trade.TradeType == "凤凰期权")
|
|
{
|
|
|
|
if (model.trade.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToPutOption || model.trade.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption)
|
|
{
|
|
model.OptionType = "1";
|
|
}
|
|
else if (model.trade.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToCallOption || model.trade.trade_autocall.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption)
|
|
{
|
|
model.OptionType = "2";
|
|
}
|
|
else
|
|
{
|
|
model.OptionType = "9";
|
|
}
|
|
}
|
|
else if (model.trade.TradeType == "雪球期权")
|
|
{
|
|
if (model.trade.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToPutOption || model.trade.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption)
|
|
{
|
|
model.OptionType = "1";
|
|
}
|
|
else if (model.trade.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToCallOption || model.trade.trade_snowball.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption)
|
|
{
|
|
model.OptionType = "2";
|
|
}
|
|
else
|
|
{
|
|
model.OptionType = "9";
|
|
}
|
|
}
|
|
|
|
|
|
//多腿编号
|
|
model.MoreLegCode = formatTradeNumber(model);
|
|
|
|
//期权产品结构
|
|
model.OptionProductStructure = formatOptionProductStructure(model);
|
|
|
|
//获取执行价格
|
|
formatStrike(model);
|
|
|
|
//观察类型、观察起始日、观察截止日、观察周期、观察周期乘数
|
|
formatObserveType(model);
|
|
|
|
//收益计算方式
|
|
formatRevenueCalculationMethod(model);
|
|
|
|
//保底收益
|
|
model.GuaranteedIncome = model.trade.OriginalPrincipalSum * (model.trade.Notional / model.trade.OriginalNotional);
|
|
|
|
model.GuaranteedIncomeSymbol = "1";
|
|
model.GuaranteedIncomeCurrency = "CNY";
|
|
|
|
//保底收益率
|
|
if (model.trade.IsUsePremiumRate == true)
|
|
{
|
|
model.GuaranteedIncome = model.trade.PrincipalRateWrite;
|
|
model.GuaranteedIncomeCurrency = null;
|
|
model.GuaranteedIncomeSymbol = "2";
|
|
}
|
|
|
|
|
|
|
|
//参与率
|
|
model.ParticipateRate = model.trade.ParticipationRate ?? 1;
|
|
|
|
//是否为年化名义金额
|
|
model.IsAnnualizedNominalAmount = model.trade.IsAnnualized ? "Y" : "N";
|
|
//凤凰、雪球
|
|
if (model.OptionProductStructure == "PA")
|
|
{
|
|
model.IsAnnualizedNominalAmount = model.trade.trade_autocall.IsAnnualized2 ? "Y" : "N";
|
|
}
|
|
else if (model.OptionProductStructure == "SA" || model.OptionProductStructure == "GSA")
|
|
{
|
|
model.IsAnnualizedNominalAmount = model.trade.trade_snowball.IsAnnualized2 ? "Y" : "N";
|
|
|
|
//小雪球的时候,红利票息赋值给保底收益
|
|
if (model.OptionProductStructure == "GSA")
|
|
{
|
|
model.GuaranteedIncome = model.trade.trade_snowball.Coupon;
|
|
model.GuaranteedIncomeCurrency = null;
|
|
model.GuaranteedIncomeSymbol = "2";
|
|
}
|
|
}
|
|
|
|
//特定字段赋值
|
|
switch (model.ToolType)
|
|
{
|
|
case "OP":
|
|
setOptionlFields(model);
|
|
break;
|
|
case "FW":
|
|
setForwardFields(model);
|
|
break;
|
|
case "SW":
|
|
setSwapFields(model);
|
|
break;
|
|
}
|
|
|
|
//自定义字段结构不为空时,处理自定义字段报送
|
|
if (!string.IsNullOrEmpty(model.ExtendInfo))
|
|
{
|
|
formatExtendInfo(model);
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取资产类型
|
|
/// </summary>
|
|
/// <param name="inputVal"></param>
|
|
/// <returns></returns>
|
|
private string formatVariety(string inputVal)
|
|
{
|
|
var varietyType = "";
|
|
switch (inputVal)
|
|
{
|
|
case "Equity":
|
|
varietyType = "EQ";
|
|
break;
|
|
case "BulkCommodity":
|
|
varietyType = "CO";
|
|
break;
|
|
case "InterestRate":
|
|
varietyType = "IR";
|
|
break;
|
|
case "Credit":
|
|
varietyType = "CR";
|
|
break;
|
|
case "ExchangeRate":
|
|
varietyType = "FX";
|
|
break;
|
|
default: varietyType = "CO"; break;
|
|
}
|
|
return varietyType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取价格符号
|
|
/// </summary>
|
|
/// <param name="underlyingPlate"></param>
|
|
/// <returns></returns>
|
|
private string formatPriceSymbol(string underlyingPlate)
|
|
{
|
|
switch (underlyingPlate)
|
|
{
|
|
case "IN": return "3";
|
|
case "LIBOR":
|
|
case "LPR":
|
|
case "GBOND":
|
|
case "TBOND":
|
|
case "PolicyBBOND":
|
|
case "CBOND":
|
|
case "FBOND":
|
|
return "2";
|
|
default: return "1";
|
|
}
|
|
}
|
|
|
|
protected double formatInitCastClientPayable(trade t)
|
|
{
|
|
double result = 0;
|
|
if (t != null)
|
|
{
|
|
result = (t.InitialMargin * (t.Notional / t.OriginalNotional)) ?? 0;
|
|
}
|
|
return Math.Max(0, result);
|
|
}
|
|
|
|
protected string formatTradeAmount(double? notional, double coefficient = 1)
|
|
{
|
|
var value = notional * coefficient;
|
|
return OtcFormatHelper.FormatValue(value, 4).ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取工具类型
|
|
/// </summary>
|
|
/// <param name="tradeType"></param>
|
|
/// <param name="structureType"></param>
|
|
/// <returns></returns>
|
|
private string formatToolType(string tradeType, string structureType)
|
|
{
|
|
var toolType = "O";
|
|
switch (tradeType)
|
|
{
|
|
case "收益互换":
|
|
toolType = "SW";
|
|
break;
|
|
case "远期":
|
|
toolType = "FW";
|
|
if (structureType == "掉期")
|
|
{
|
|
toolType = "SW";
|
|
}
|
|
break;
|
|
default:
|
|
toolType = "OP";
|
|
break;
|
|
}
|
|
|
|
return toolType;
|
|
}
|
|
|
|
protected string formatDictItem(List<DictionaryItem> dictItemMap, string name, string defaultValue = "")
|
|
{
|
|
if (name == null || dictItemMap == null) { return defaultValue; }
|
|
var obj = dictItemMap.FirstOrDefault(O => O.Name == name);
|
|
return obj == null ? defaultValue : obj.ShortName;
|
|
}
|
|
|
|
private string formatSyntheticUnderlying(SyntheticPriceModel underlying, Dictionary<string, string> exchangeNo)
|
|
{
|
|
Func<double, string, string> formatCode = (_coefficient, _underlyingCode) =>
|
|
{
|
|
var code = formatUnderlyingCode(_underlyingCode, exchangeNo[_underlyingCode]);
|
|
var coef = Math.Abs(_coefficient).ToString();
|
|
return $"{(coef == "1" ? null : coef)}{code}";
|
|
};
|
|
|
|
var tipsInfo = "";
|
|
foreach (var item in underlying.SuList)
|
|
{
|
|
if (!string.IsNullOrEmpty(tipsInfo) || item.Coefficient < 0)
|
|
{
|
|
tipsInfo += (item.Coefficient >= 0 ? "+" : "-");
|
|
}
|
|
tipsInfo += formatCode(item.Coefficient, item.UnderlyingCode);
|
|
}
|
|
|
|
return tipsInfo;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取标的代码
|
|
/// </summary>
|
|
/// <param name="underlyingCode"></param>
|
|
/// <param name="exchangeNo"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="ArgumentException"></exception>
|
|
private string formatUnderlyingCode(string underlyingCode, string exchangeNo)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(underlyingCode))
|
|
{
|
|
throw new ArgumentException("标的代码不存在", nameof(underlyingCode));
|
|
}
|
|
|
|
var superviseUndelrying = DbContext.supervise_undelrying.FirstOrDefault(n => n.undelrying == underlyingCode);
|
|
if (superviseUndelrying != null && !string.IsNullOrEmpty(superviseUndelrying.undelrying_CFMMC))
|
|
{
|
|
return superviseUndelrying.undelrying_CFMMC;
|
|
}
|
|
|
|
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
|
|
if (underlying == null)
|
|
{
|
|
throw new ArgumentException("标的信息不存在:" + underlyingCode);
|
|
}
|
|
if (underlying.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommoditySpot)
|
|
{
|
|
return underlying.UnderlyingName;
|
|
}
|
|
else if (underlyingCode.Contains("."))
|
|
{
|
|
return underlyingCode;
|
|
}
|
|
return $"{underlyingCode}.{exchangeNo}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取标的资产所属板块
|
|
/// </summary>
|
|
/// <param name="inputVal"></param>
|
|
/// <returns></returns>
|
|
private string formatUnderlyingPlate(string inputVal)
|
|
{
|
|
switch (inputVal)
|
|
{
|
|
case "贵金属":
|
|
case "有色及贵金属":
|
|
return "Pmetal";
|
|
case "黑色": return "Ferrous";
|
|
case "能化":
|
|
case "能源化工":
|
|
return "ECH";
|
|
case "农产品": return "AGP";
|
|
case "有色": return "NonFerrous";
|
|
case "商品ETF": return "COETF";
|
|
case "个股": return "SK";
|
|
case "股指":
|
|
case "指数":
|
|
return "IN";
|
|
case "基金": return "FD";
|
|
case "LIBOR": return "LIBOR";
|
|
case "LPR": return "LPR";
|
|
case "地方政府债": return "GBOND";
|
|
case "国股银票转贴现": return "BAEX_1";
|
|
case "国债": return "TBOND";
|
|
case "政策性金融债": return "PolicyBBOND";
|
|
case "美元兑人民币": return "USDRMB";
|
|
case "公司债": return "CBOND";
|
|
case "金融债": return "FBOND";
|
|
default: return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 多腿编号
|
|
/// </summary>
|
|
/// <param name="model"></param>
|
|
/// <returns></returns>
|
|
private string formatTradeNumber(SuperviseReportBaseModel model)
|
|
{
|
|
var tradeNum = "";
|
|
if (model.ParentTradeId > 0)
|
|
{
|
|
|
|
if (PS.Config.Company == Configuration.CompanyEnum.浙期)
|
|
{
|
|
if (!int.TryParse(Regex.Match(model.OriginalTradeNumber ?? "", @"(?<=X)\d+$").Value, out var tradeNum2))
|
|
{
|
|
return null;
|
|
}
|
|
tradeNum = tradeNum2.ToString();
|
|
}
|
|
else if (PS.Config.Is物产中大 && model.ParentTradeId > 0)
|
|
{
|
|
tradeNum = (DbContext.trade.Where(l=>l.id<model.TradeId && l.ParentTradeId ==model.ParentTradeId && l.ValidState!= "InValid").Count()+1).ToString();
|
|
}
|
|
else if (model.OriginalTradeNumber.IndexOf('-') > 0)
|
|
{
|
|
var arrOTNum = model.OriginalTradeNumber.Split('-');
|
|
|
|
tradeNum = arrOTNum[arrOTNum.Length - 1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tradeNum = null;
|
|
}
|
|
return tradeNum;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取期权产品结构
|
|
/// </summary>
|
|
/// <param name="model"></param>
|
|
/// <returns></returns>
|
|
private string formatOptionProductStructure(SuperviseReportBaseModel model)
|
|
{
|
|
var tradeTypeEn = "O";
|
|
switch (model.OptionProductStructure)
|
|
{
|
|
case "香草期权":
|
|
tradeTypeEn = "VA";
|
|
break;
|
|
case "亚式期权":
|
|
tradeTypeEn = "AS";
|
|
break;
|
|
case "二元期权":
|
|
tradeTypeEn = "DI";
|
|
break;
|
|
case "区间累计期权":
|
|
case "区间累积期权":
|
|
tradeTypeEn = "RA";
|
|
break;
|
|
case "障碍期权":
|
|
if (model.trade.trade_barrier_option.BarrierType.StartsWith("双障碍"))
|
|
{
|
|
tradeTypeEn = "DSF";
|
|
}
|
|
else if (model.trade.trade_barrier_option.BarrierType.EndsWith("敲入"))
|
|
{
|
|
tradeTypeEn = "SKI";
|
|
}
|
|
else if (model.trade.trade_barrier_option.BarrierType.EndsWith("敲出"))
|
|
{
|
|
tradeTypeEn = "SF";
|
|
}
|
|
break;
|
|
case "双鲨期权":
|
|
tradeTypeEn = "DSF";
|
|
break;
|
|
case "累计期权":
|
|
tradeTypeEn = "AC";
|
|
break;
|
|
case "雪球期权":
|
|
if (model.trade.trade_snowball.KIPayoffType == 0)
|
|
{
|
|
tradeTypeEn = "GSA";
|
|
}
|
|
else
|
|
{
|
|
tradeTypeEn = "SA";
|
|
}
|
|
break;
|
|
case "凤凰期权":
|
|
tradeTypeEn = "PA";
|
|
break;
|
|
case "自定义交易":
|
|
tradeTypeEn = "O";
|
|
if (!string.IsNullOrEmpty(model.trade.StructureType))
|
|
{
|
|
var customTradeInfo = DbContext.Structure_Info.FirstOrDefault(n => n.StructureName == model.trade.StructureType);
|
|
if (customTradeInfo != null)
|
|
{
|
|
if (!string.IsNullOrEmpty(customTradeInfo.StructureTypeSm))
|
|
{
|
|
tradeTypeEn = customTradeInfo.StructureTypeSm;
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
default:
|
|
tradeTypeEn = "O";
|
|
break;
|
|
|
|
}
|
|
return tradeTypeEn;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取标的资产品种
|
|
/// </summary>
|
|
/// <param name="underlyingCode"></param>
|
|
/// <param name="variety"></param>
|
|
/// <param name="varietyCodeList"></param>
|
|
/// <param name="marketExchangeNo"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="ArgumentException"></exception>
|
|
|
|
private string formatVarietyCode(string underlyingCode, Variety variety, List<DictionaryItem> varietyCodeList, string marketExchangeNo)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(underlyingCode))
|
|
{
|
|
throw new ArgumentException("标的代码不存在", nameof(underlyingCode));
|
|
}
|
|
var code = varietyCodeList.Where(O => O.Name.ToLower() == underlyingCode.ToLower()).Select(O => O.ShortName).FirstOrDefault();
|
|
if (!string.IsNullOrEmpty(code))
|
|
{
|
|
return code;
|
|
}
|
|
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
|
|
if (underlying == null)
|
|
{
|
|
throw new ArgumentException("标的信息不存在:" + underlyingCode);
|
|
}
|
|
var assetVariety = $"{{0}}.{marketExchangeNo}";
|
|
switch (underlying.UnderlyingInstrumentType)
|
|
{
|
|
case ConsGlobal.InstrumentType.StockIndex:
|
|
case ConsGlobal.InstrumentType.StockIF:
|
|
assetVariety = variety.VarietyName;
|
|
break;
|
|
case ConsGlobal.InstrumentType.CommodityFutures:
|
|
assetVariety = string.Format(assetVariety, variety.VarietyCode);
|
|
break;
|
|
case ConsGlobal.InstrumentType.CommoditySpot:
|
|
if (marketExchangeNo == "SGE")
|
|
{
|
|
assetVariety = string.Format(assetVariety, underlyingCode);
|
|
}
|
|
else
|
|
{
|
|
assetVariety = variety.VarietyName;
|
|
}
|
|
break;
|
|
case ConsGlobal.InstrumentType.Stock:
|
|
//assetVariety = string.Format(assetVariety, getStockVarietyCode(underlyingCode));
|
|
assetVariety = getStockVarietyCode(underlyingCode);
|
|
break;
|
|
default:
|
|
assetVariety = underlyingCode;
|
|
break;
|
|
}
|
|
return assetVariety;
|
|
}
|
|
|
|
private string getStockVarietyCode(string code)
|
|
{
|
|
var assetVariety = "";
|
|
if (code.StartsWith("60") || code.StartsWith("000"))
|
|
{ //主板
|
|
assetVariety = "ZB";
|
|
}
|
|
else if (code.StartsWith("002"))
|
|
{//中小板
|
|
//assetVariety = "ZXB";
|
|
assetVariety = "ZB";
|
|
}
|
|
else if (code.StartsWith("300"))
|
|
{//创业板
|
|
assetVariety = "CYB";
|
|
}
|
|
else if (code.StartsWith("688"))
|
|
{//科创版
|
|
assetVariety = "KCB";
|
|
}
|
|
else
|
|
{
|
|
assetVariety = "";
|
|
}
|
|
return assetVariety;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取数量单位
|
|
/// </summary>
|
|
/// <param name="quoteUnit"></param>
|
|
/// <returns></returns>
|
|
private string formatQuoteUnit(string quoteUnit)
|
|
{
|
|
switch (quoteUnit)
|
|
{
|
|
case "吨":
|
|
return "t";
|
|
case "桶":
|
|
return "barrel";
|
|
case "克":
|
|
return "g";
|
|
case "千克":
|
|
return "kg";
|
|
case "500千克":
|
|
return "500kg";
|
|
case "股":
|
|
case "股(份)":
|
|
return "share";
|
|
case "磅":
|
|
return "lb";
|
|
|
|
case "点":
|
|
//if (PS.Config.Company == Configuration.CompanyEnum.国投)
|
|
//{
|
|
// return "bp";
|
|
//}
|
|
//return "point";
|
|
case "基点":
|
|
//return "bp";
|
|
case "units":
|
|
//return "units";
|
|
return "Other";
|
|
case "指数":
|
|
case "元/指数点":
|
|
return "元/指数点";
|
|
default:
|
|
return "Other";
|
|
}
|
|
//return quoteUnit;
|
|
}
|
|
|
|
protected double formatEndStockEqvNotionalReal(double? stockEqvNotional, double percentRate)
|
|
{
|
|
var result = stockEqvNotional * percentRate;
|
|
return Math.Abs(OtcFormatHelper.FormatValue((result ?? 0), 4));
|
|
}
|
|
|
|
protected string JoinArr(string[] arr)
|
|
{
|
|
var singleArr = new HashSet<string>(arr);
|
|
singleArr.Remove("");
|
|
return string.Join(";", singleArr);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 是否为期权
|
|
/// </summary>
|
|
/// <param name="t"></param>
|
|
/// <returns></returns>
|
|
private bool IsOption(trade t)
|
|
{
|
|
return t.IsOption() || t.TradeType == "自定义交易";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取执行价格1、2、3
|
|
/// </summary>
|
|
/// <param name="model"></param>
|
|
/// <returns></returns>
|
|
private void formatStrike(SuperviseReportBaseModel model)
|
|
{
|
|
|
|
//执行价格符号
|
|
model.StrikeSymbol = formatPriceSymbol(model.UnderlyingPlate);
|
|
|
|
if (model.StrikeSymbol == "1")
|
|
{
|
|
//执行价格货币
|
|
model.StrikeCurrency = "CNY";
|
|
}
|
|
|
|
var trade = model.trade;
|
|
|
|
//当期权产品结构为 AS(亚式期权),且执行价为观察期内标的价格的均值,则此处无需填写执行价格
|
|
if (model.OptionProductStructure == "AS" && trade.trade_asian_option.StrikeType == "Floating")
|
|
{
|
|
return;
|
|
}
|
|
|
|
//执行价1
|
|
model.Strike = trade.Strike ?? 0; //trade.IsMoneynessOption == "是" ? ((trade.Strike * trade.SpotPrice) ?? 0) :
|
|
if (trade.IsMoneynessOption == "是")
|
|
{
|
|
model.Strike = ((trade.Strike * trade.SpotPrice) ?? 0);
|
|
}
|
|
|
|
//执行价2
|
|
if (model.OptionProductStructure == "SA" || model.OptionProductStructure == "GSA")
|
|
{
|
|
model.Strike2 = trade.trade_snowball.SpreadStrikeAtMaturity;
|
|
if (trade.IsMoneynessOption == "是")
|
|
{
|
|
model.Strike2 = (trade.trade_snowball.SpreadStrikeAtMaturity * trade.SpotPrice);
|
|
}
|
|
}
|
|
else if (model.OptionProductStructure == "PA")
|
|
{
|
|
model.Strike2 = trade.trade_autocall.SpreadStrike;
|
|
if (trade.IsMoneynessOption == "是")
|
|
{
|
|
model.Strike2 = (trade.trade_autocall.SpreadStrike * trade.SpotPrice);
|
|
}
|
|
}
|
|
else if (model.OptionProductStructure == "DI" && trade.trade_binary_option.PayoffType.StartsWith("Double"))
|
|
{
|
|
model.Strike2 = trade.trade_binary_option.UpperBarrier;
|
|
if (trade.IsMoneynessOption == "是")
|
|
{
|
|
model.Strike2 = (trade.trade_binary_option.UpperBarrier * trade.SpotPrice);
|
|
}
|
|
}
|
|
else if (model.OptionProductStructure == "O" && trade.trade_risky_option != null)
|
|
{
|
|
model.Strike2 = trade.trade_risky_option.Strike2;
|
|
model.Strike3 = trade.trade_risky_option.Strike3;
|
|
if (trade.IsMoneynessOption == "是")
|
|
{
|
|
model.Strike2 = (trade.trade_risky_option.Strike2 * trade.SpotPrice);
|
|
model.Strike3 = (trade.trade_risky_option.Strike3 * trade.SpotPrice);
|
|
}
|
|
}
|
|
else if (model.OptionProductStructure == "AC" && trade.trade_accumulator_option != null && trade.trade_accumulator_option.AccumulatorStructureType == AccumulatorStructureTypeEnum.Segmented)
|
|
{
|
|
model.Strike2 = trade.trade_accumulator_option.Strike2;
|
|
model.Strike3 = trade.trade_accumulator_option.Strike3;
|
|
if (trade.IsMoneynessOption == "是")
|
|
{
|
|
model.Strike2 = (trade.trade_accumulator_option.Strike2 * trade.SpotPrice);
|
|
model.Strike3 = (trade.trade_accumulator_option.Strike3 * trade.SpotPrice);
|
|
}
|
|
}
|
|
if (model.Strike > model.Strike2 && model.Strike2 > 0)
|
|
{
|
|
var tempVal = model.Strike2 ?? 0;
|
|
model.Strike2 = model.Strike;
|
|
model.Strike = tempVal;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 获取观察方式、观察开始时间、观察结束时间、观察周期
|
|
/// </summary>
|
|
/// <param name="observType"></param>
|
|
/// <returns></returns>
|
|
private void formatObserveType(SuperviseReportBaseModel model)
|
|
{
|
|
string getObType(string input)
|
|
{
|
|
switch (input)
|
|
{
|
|
case "离散": return "DISCRETE";
|
|
case "连续": return "CONTINUOUS";
|
|
case "到期": return "TERMINAL";
|
|
default: return "DISCRETE";
|
|
}
|
|
}
|
|
|
|
DateTime getObSDate(string observationDates, out DateTime inputDateTime)
|
|
{
|
|
var observations = observationDates.Split(',');
|
|
var observeStartData = DateTime.Parse(observations[0]);
|
|
inputDateTime = DateTime.Parse(observations[(observations.Count() - 1)]);
|
|
return observeStartData;
|
|
}
|
|
|
|
var trade = model.trade;
|
|
DateTime oSd;
|
|
DateTime observeEndDate;
|
|
switch (model.OptionProductStructure)
|
|
{
|
|
case "AS":
|
|
model.ObserveType = getObType("离散");
|
|
model.ObserveStartDate = trade.trade_asian_option?.AveragingPeriodStartDate;
|
|
model.ObserveEndDate = model.EndDate;
|
|
break;
|
|
case "DI":
|
|
model.ObserveType = getObType((trade.ExerciseModeCn == "欧式" || trade.ExerciseMode == "European") ? "到期" : trade.trade_binary_option.MonitorType);
|
|
|
|
if (!string.IsNullOrEmpty(trade.trade_binary_option.ObservationDates))
|
|
{
|
|
model.ObserveStartDate = getObSDate(trade.trade_binary_option.ObservationDates, out observeEndDate);
|
|
model.ObserveEndDate = observeEndDate;
|
|
}
|
|
else
|
|
{
|
|
oSd = model.StartDate.Value.AddDays(1);
|
|
model.ObserveStartDate = oSd;
|
|
model.ObserveEndDate = model.EndDate;
|
|
}
|
|
break;
|
|
case "RA":
|
|
model.ObserveType = getObType("离散");//trade_rangeaccrual
|
|
if (!string.IsNullOrEmpty(trade.trade_rangeaccrual.ObservationDates))
|
|
{
|
|
model.ObserveStartDate = getObSDate(trade.trade_rangeaccrual.ObservationDates, out observeEndDate);
|
|
model.ObserveEndDate = observeEndDate;
|
|
|
|
if (isTerminal(trade.trade_rangeaccrual.ObservationDates, model.EndDate.Value))
|
|
{
|
|
model.ObserveType = "TERMINAL";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
oSd = model.StartDate.Value.AddDays(1);
|
|
model.ObserveStartDate = oSd;
|
|
model.ObserveEndDate = model.EndDate;
|
|
}
|
|
break;
|
|
case "SF":
|
|
case "SKI":
|
|
model.ObserveType = getObType(trade.trade_barrier_option.Discrete);
|
|
|
|
if (!string.IsNullOrEmpty(trade.trade_barrier_option.ObservationDates))
|
|
{
|
|
model.ObserveStartDate = getObSDate(trade.trade_barrier_option.ObservationDates, out observeEndDate);
|
|
model.ObserveEndDate = observeEndDate;
|
|
}
|
|
else
|
|
{
|
|
oSd = model.StartDate.Value.AddDays(1);
|
|
model.ObserveStartDate = oSd;
|
|
model.ObserveEndDate = model.EndDate;
|
|
}
|
|
break;
|
|
case "DSF":
|
|
if (model.ProductType == "双鲨期权")
|
|
{
|
|
model.ObserveType = getObType(trade.trade_double_sharkfin_option.Discrete);
|
|
if (!string.IsNullOrEmpty(trade.trade_double_sharkfin_option.ObservationDates))
|
|
{
|
|
model.ObserveStartDate = getObSDate(trade.trade_double_sharkfin_option.ObservationDates, out observeEndDate);
|
|
model.ObserveEndDate = observeEndDate;
|
|
}
|
|
else
|
|
{
|
|
oSd = model.StartDate.Value.AddDays(1);
|
|
model.ObserveStartDate = oSd;
|
|
model.ObserveEndDate = model.EndDate;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
model.ObserveType = getObType(trade.trade_barrier_option.Discrete);
|
|
|
|
if (!string.IsNullOrEmpty(trade.trade_barrier_option.ObservationDates))
|
|
{
|
|
model.ObserveStartDate = getObSDate(trade.trade_barrier_option.ObservationDates, out observeEndDate);
|
|
model.ObserveEndDate = observeEndDate;
|
|
}
|
|
else
|
|
{
|
|
oSd = model.StartDate.Value.AddDays(1);
|
|
model.ObserveStartDate = oSd;
|
|
model.ObserveEndDate = model.EndDate;
|
|
}
|
|
}
|
|
break;
|
|
case "AC":
|
|
model.ObserveType = getObType("离散");//trade_accumulator_option
|
|
if (!string.IsNullOrEmpty(trade.trade_accumulator_option.KOObservationDates))
|
|
{
|
|
var KOObservationDatesArr = trade.trade_accumulator_option.KOObservationDates.Split(';');
|
|
if (KOObservationDatesArr.Length > 0)
|
|
{
|
|
model.ObserveStartDate = getObSDate(KOObservationDatesArr[0], out observeEndDate);
|
|
model.ObserveEndDate = observeEndDate;
|
|
|
|
if (isTerminal(KOObservationDatesArr[0], model.EndDate.Value))
|
|
{
|
|
model.ObserveType = "TERMINAL";
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
oSd = model.StartDate.Value.AddDays(1);
|
|
model.ObserveStartDate = oSd;
|
|
model.ObserveEndDate = model.EndDate;
|
|
}
|
|
break;
|
|
case "SA":
|
|
case "GSA":
|
|
model.ObserveType = getObType("离散");//trade_snowball
|
|
if (!string.IsNullOrEmpty(trade.trade_snowball.KOObservationDates))
|
|
{
|
|
var KOObservationDatesArr = trade.trade_snowball.KOObservationDates.Split(';');
|
|
if (KOObservationDatesArr.Length > 0)
|
|
{
|
|
model.ObserveStartDate = getObSDate(KOObservationDatesArr[0], out observeEndDate);
|
|
model.ObserveEndDate = observeEndDate;
|
|
|
|
if (isTerminal(KOObservationDatesArr[0], model.EndDate.Value))
|
|
{
|
|
model.ObserveType = "TERMINAL";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
oSd = model.StartDate.Value.AddDays(1);
|
|
model.ObserveStartDate = oSd;
|
|
model.ObserveEndDate = model.EndDate;
|
|
}
|
|
|
|
}
|
|
break;
|
|
case "PA":
|
|
model.ObserveType = getObType("离散");//trade_autocall
|
|
if (!string.IsNullOrEmpty(trade.trade_autocall.KOObservationDates))
|
|
{
|
|
var ko = TradeObservationHelper.GetAutocallKOObservationAndCoupon(trade.trade_autocall.KOObservationDates, trade.trade_autocall.CouponBarrier);
|
|
var KOObservationDatesArr = ko.Item2.Split(';');
|
|
if (KOObservationDatesArr.Length > 0)
|
|
{
|
|
model.ObserveStartDate = getObSDate(KOObservationDatesArr[0], out observeEndDate);
|
|
model.ObserveEndDate = observeEndDate;
|
|
|
|
if (isTerminal(KOObservationDatesArr[0], model.EndDate.Value))
|
|
{
|
|
model.ObserveType = "TERMINAL";
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
oSd = model.StartDate.Value.AddDays(1);
|
|
model.ObserveStartDate = oSd;
|
|
model.ObserveEndDate = model.EndDate;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 是否是到期观察
|
|
/// </summary>
|
|
/// <param name="observationDates"></param>
|
|
/// <param name="endDate"></param>
|
|
/// <returns></returns>
|
|
public bool isTerminal(string observationDates, DateTime endDate)
|
|
{
|
|
var isTerminal = false;
|
|
var observations = observationDates.Split(',');
|
|
if (observations.Length == 1)
|
|
{
|
|
var observeStartData = DateTime.Parse(observations[0]);
|
|
if (observeStartData == endDate)
|
|
{
|
|
isTerminal = true;
|
|
}
|
|
}
|
|
return isTerminal;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 获取收益计算方式
|
|
/// </summary>
|
|
/// <param name="model"></param>
|
|
private void formatRevenueCalculationMethod(SuperviseReportBaseModel model)
|
|
{
|
|
var trade = model.trade;
|
|
switch (model.OptionProductStructure)
|
|
{
|
|
case "AS":
|
|
|
|
break;
|
|
case "DI":
|
|
model.RevenueCalculationMethod = trade.trade_binary_option.RebateType == "AtEnd" ? "EXPIRY" : "HIT";
|
|
break;
|
|
case "RA":
|
|
|
|
break;
|
|
case "SF":
|
|
case "SKI":
|
|
model.RevenueCalculationMethod = trade.trade_barrier_option.RebateType == "AtEnd" ? "EXPIRY" : "HIT";
|
|
break;
|
|
case "DSF":
|
|
if (model.ProductType == "双鲨期权")
|
|
{
|
|
model.RevenueCalculationMethod = trade.trade_double_sharkfin_option.RebateType == "AtEnd" ? "EXPIRY" : "HIT";
|
|
}
|
|
else
|
|
{
|
|
model.RevenueCalculationMethod = trade.trade_barrier_option.RebateType == "AtEnd" ? "EXPIRY" : "HIT";
|
|
}
|
|
break;
|
|
case "AC":
|
|
|
|
break;
|
|
case "SA":
|
|
case "GSA":
|
|
model.RevenueCalculationMethod = trade.trade_snowball.KORebateType == 0 ? "HIT" : "EXPIRY";
|
|
break;
|
|
case "PA":
|
|
model.RevenueCalculationMethod = trade.trade_autocall.CouponPayType == 0 ? "HIT" : "EXPIRY";
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置特定期权结构的字段 需要大改
|
|
/// </summary>
|
|
/// <param name="model"></param>
|
|
private void setOptionlFields(SuperviseReportBaseModel model)
|
|
{
|
|
var trade = model.trade;
|
|
switch (model.OptionProductStructure)
|
|
{
|
|
case "DI"://二元
|
|
if (trade.trade_binary_option != null)
|
|
{
|
|
model.ExerciseBenefitsSymbol = "1";
|
|
if (trade.IsUsePremiumRate == true)
|
|
{
|
|
model.ExerciseBenefitsSymbol = "2";
|
|
model.ExerciseBenefits = trade.trade_binary_option.CashOrNothingAmountRate + (model.GuaranteedIncome ?? 0);
|
|
if (model.Strike2 > 0)
|
|
{
|
|
model.ExerciseBenefits2 = trade.trade_binary_option.CashOrNothingAmountHighRate + (model.GuaranteedIncome ?? 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
model.ExerciseBenefitsCurrency = "CNY";
|
|
model.ExerciseBenefits = trade.trade_binary_option.CashOrNothingAmount + (model.GuaranteedIncome ?? 0);
|
|
if (model.Strike2 > 0)
|
|
{
|
|
model.ExerciseBenefits2 = trade.trade_binary_option.CashOrNothingAmountHigh + (model.GuaranteedIncome ?? 0);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case "RA":
|
|
if (trade.trade_rangeaccrual != null)
|
|
{
|
|
model.ExerciseBenefitsSymbol = "2";
|
|
model.ExerciseBenefits = trade.trade_rangeaccrual.BonusRate + (trade.PrincipalRateWrite ?? 0);
|
|
}
|
|
break;
|
|
case "SKI":
|
|
case "SF":
|
|
if (trade.trade_barrier_option != null)
|
|
{
|
|
model.BarriersPrice = trade.trade_barrier_option.BarrierPrice;
|
|
if (!string.IsNullOrEmpty(trade.trade_barrier_option.BarrierType))
|
|
{
|
|
if (trade.trade_barrier_option.BarrierType.StartsWith("上"))
|
|
{
|
|
model.BarriersPriceTouchDirection = "Up";
|
|
}
|
|
else if (trade.trade_barrier_option.BarrierType.StartsWith("下"))
|
|
{
|
|
model.BarriersPriceTouchDirection = "Down";
|
|
}
|
|
|
|
if (trade.trade_barrier_option.BarrierType.EndsWith("敲入"))
|
|
{
|
|
model.BarriersPriceType = "In";
|
|
}
|
|
else if (trade.trade_barrier_option.BarrierType.EndsWith("敲出"))
|
|
{
|
|
model.BarriersPriceType = "Out";
|
|
}
|
|
}
|
|
|
|
if (model.trade.IsMoneynessOption == "是")
|
|
{
|
|
model.BarriersPrice = trade.trade_barrier_option.BarrierPrice * trade.SpotPrice;
|
|
}
|
|
|
|
model.CompensationIncomeCurrency = "CNY";
|
|
if (trade.IsUsePremiumRate == true)
|
|
{
|
|
model.CompensationIncomeSymbol = "2";
|
|
model.CompensationIncome = trade.trade_barrier_option.RebateRate ?? 0;
|
|
model.CompensationIncomeCurrency = null;
|
|
}
|
|
else
|
|
{
|
|
model.CompensationIncomeSymbol = "1";
|
|
model.CompensationIncome = trade.trade_barrier_option.Rebate ?? 0;
|
|
}
|
|
}
|
|
break;
|
|
case "DSF":
|
|
model.CompensationIncomeCurrency = "CNY";
|
|
if (model.ProductType == "双鲨期权")
|
|
{
|
|
if (trade.trade_double_sharkfin_option != null)
|
|
{
|
|
model.BarriersPrice = trade.trade_double_sharkfin_option.BarrierLow;
|
|
model.BarriersPrice2 = trade.trade_double_sharkfin_option.BarrierHigh;
|
|
if (model.trade.IsMoneynessOption == "是")
|
|
{
|
|
model.BarriersPrice = trade.trade_double_sharkfin_option.BarrierLow * trade.SpotPrice;
|
|
model.BarriersPrice2 = trade.trade_double_sharkfin_option.BarrierHigh * trade.SpotPrice;
|
|
}
|
|
model.BarriersPriceTouchDirection = "Down";
|
|
model.BarriersPrice2TouchDirection = "Up";
|
|
model.BarriersPriceType = "Out";
|
|
model.BarriersPrice2Type = "Out";
|
|
if (trade.IsUsePremiumRate == true)
|
|
{
|
|
model.CompensationIncome = trade.trade_double_sharkfin_option.RebateRate ?? 0;
|
|
model.CompensationIncome2 = trade.trade_double_sharkfin_option.RebateHighRate ?? 0;
|
|
model.CompensationIncomeSymbol = "2";
|
|
model.CompensationIncomeCurrency = null;
|
|
}
|
|
else
|
|
{
|
|
model.CompensationIncome = trade.trade_double_sharkfin_option.Rebate ?? 0;
|
|
model.CompensationIncome2 = trade.trade_double_sharkfin_option.RebateHigh ?? 0;
|
|
model.CompensationIncomeSymbol = "1";
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (trade.trade_barrier_option != null)
|
|
{
|
|
model.BarriersPrice = trade.trade_barrier_option.BarrierPrice;
|
|
model.BarriersPrice2 = trade.trade_barrier_option.UpperBarrierPrice;
|
|
if (model.trade.IsMoneynessOption == "是")
|
|
{
|
|
model.BarriersPrice = trade.trade_barrier_option.BarrierPrice * trade.SpotPrice;
|
|
model.BarriersPrice2 = trade.trade_barrier_option.UpperBarrierPrice * trade.SpotPrice;
|
|
}
|
|
model.BarriersPriceTouchDirection = "Down";
|
|
if (!string.IsNullOrEmpty(trade.trade_barrier_option.BarrierType))
|
|
{
|
|
if (trade.trade_barrier_option.BarrierType.EndsWith("敲入"))
|
|
{
|
|
model.BarriersPriceType = "In";
|
|
if (model.BarriersPrice2 > 0)
|
|
{
|
|
model.BarriersPrice2Type = "In";
|
|
model.BarriersPrice2TouchDirection = "Up";
|
|
}
|
|
}
|
|
else if (trade.trade_barrier_option.BarrierType.EndsWith("敲出"))
|
|
{
|
|
model.BarriersPriceType = "Out";
|
|
if (model.BarriersPrice2 > 0)
|
|
{
|
|
model.BarriersPrice2Type = "Out";
|
|
model.BarriersPrice2TouchDirection = "Up";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (trade.IsUsePremiumRate == true)
|
|
{
|
|
model.CompensationIncome = trade.trade_barrier_option.RebateRate ?? 0;
|
|
model.CompensationIncome2 = trade.trade_barrier_option.RebateHighRate ?? 0;
|
|
model.CompensationIncomeSymbol = "2";
|
|
model.CompensationIncomeCurrency = null;
|
|
}
|
|
else
|
|
{
|
|
model.CompensationIncome = trade.trade_barrier_option.Rebate ?? 0;
|
|
model.CompensationIncome2 = trade.trade_barrier_option.RebateHigh ?? 0;
|
|
model.CompensationIncomeSymbol = "1";
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case "SA":
|
|
case "GSA":
|
|
if (trade.trade_snowball != null)
|
|
{
|
|
double? saKOPrice, saKIPrice;
|
|
saKOPrice = trade.trade_snowball.KOBarrier;
|
|
//敲出障碍价
|
|
if (!string.IsNullOrEmpty(trade.trade_snowball.KOObservationDates))
|
|
{
|
|
var saKoResult = QdpHelper.ParseAutocallCustomizedInfo(trade.trade_snowball.KOObservationDates);
|
|
if (saKoResult.Item2 != null)
|
|
{
|
|
var latestKOObservationDate = saKoResult.Item1.Where(x => x.DateTime >= model.ValueDate).OrderBy(x => x.DateTime).FirstOrDefault();
|
|
saKOPrice = saKoResult.Item2[GetDateIndex(saKoResult.Item1, latestKOObservationDate)];
|
|
}
|
|
}
|
|
//敲入障碍价
|
|
saKIPrice = trade.trade_snowball.KIBarrier;
|
|
if (!string.IsNullOrEmpty(trade.trade_snowball.ObservationDates))
|
|
{
|
|
var saKiResult = QdpHelper.ParseAutocallCustomizedInfo(trade.trade_snowball.ObservationDates);
|
|
if (saKiResult.Item2 != null)
|
|
{
|
|
var latestKIObservationDate = saKiResult.Item1.Where(x => x.DateTime >= model.ValueDate).OrderBy(x => x.DateTime).FirstOrDefault();
|
|
saKIPrice = saKiResult.Item2[GetDateIndex(saKiResult.Item1, latestKIObservationDate)];
|
|
}
|
|
}
|
|
|
|
if (trade.trade_snowball.KIPayoffType != 0)
|
|
{
|
|
model.KnockInBarrierPrice = saKIPrice;
|
|
if (model.trade.IsMoneynessOption == "是")
|
|
{
|
|
model.KnockInBarrierPrice = saKIPrice * trade.SpotPrice;
|
|
}
|
|
}
|
|
|
|
model.KnockOutBarrierPrice = saKOPrice;
|
|
if (model.trade.IsMoneynessOption == "是")
|
|
{
|
|
model.KnockOutBarrierPrice = saKOPrice * trade.SpotPrice;
|
|
}
|
|
|
|
if (model.GuaranteedIncomeSymbol == "2")
|
|
{
|
|
model.CouponAnnualRate = trade.trade_snowball.KORebate + (model.GuaranteedIncome ?? 0);
|
|
}
|
|
else
|
|
{
|
|
model.CouponAnnualRate = trade.trade_snowball.KORebate + ((trade.OriginalPrincipalSum ?? 0) / trade.StockEqvNotional);
|
|
}
|
|
|
|
|
|
//雪球敲出时,判断敲出日期是否小杨到期日,是的话,提前终止日期需赋值
|
|
if (!string.IsNullOrEmpty(trade.trade_snowball.KnockInOutStatus) && (trade.trade_snowball.KnockInOutStatusCn.Contains("敲出") || trade.trade_snowball.KnockInOutStatus.ToLower().Contains("out")))
|
|
{
|
|
if (trade.trade_snowball.KnockInOutDate < model.EndDate)
|
|
{
|
|
model.UnWindDate = trade.trade_snowball.KnockInOutDate;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case "PA":
|
|
if (trade.trade_autocall != null)
|
|
{
|
|
double? paKOPrice, paKIPrice, paCoupon, couponRate;
|
|
paKOPrice = trade.trade_autocall.KOBarrier;
|
|
paCoupon = trade.trade_autocall.CouponBarrier;
|
|
couponRate = trade.trade_autocall.Coupon;
|
|
//敲出障碍价、Coupon障碍价
|
|
if (!string.IsNullOrEmpty(trade.trade_autocall.KOObservationDates))
|
|
{
|
|
var ko = TradeObservationHelper.GetAutocallKOObservationAndCoupon(trade.trade_autocall.KOObservationDates, trade.trade_autocall.CouponBarrier);
|
|
var paKoResult = QdpHelper.ParseAutocallCustomizedInfoV3(ko.Item2);
|
|
//敲出观察频率
|
|
if (paKoResult.Item2 != null)
|
|
{
|
|
var latestKOObservationDate = paKoResult.Item1.Where(x => x.DateTime >= model.ValueDate).OrderBy(x => x.DateTime).FirstOrDefault();
|
|
paKOPrice = paKoResult.Item2[GetDateIndex(paKoResult.Item1, latestKOObservationDate)];
|
|
}
|
|
//票息观察频率
|
|
var CouponKoResult = QdpHelper.ParseAutocallCustomizedInfo(ko.Item1);
|
|
if (CouponKoResult.Item3 != null)
|
|
{
|
|
var latestKOObservationDate = CouponKoResult.Item1.Where(x => x.DateTime >= model.ValueDate).OrderBy(x => x.DateTime).FirstOrDefault();
|
|
couponRate = CouponKoResult.Item3[GetDateIndex(CouponKoResult.Item1, latestKOObservationDate)];
|
|
}
|
|
}
|
|
//敲入障碍价
|
|
paKIPrice = trade.trade_autocall.KIBarrier;
|
|
if (!string.IsNullOrEmpty(trade.trade_autocall.ObservationDates))
|
|
{
|
|
var paKiResult = QdpHelper.ParseAutocallCustomizedInfo(trade.trade_autocall.ObservationDates);
|
|
if (paKiResult.Item2 != null)
|
|
{
|
|
var latestKIObservationDate = paKiResult.Item1.Where(x => x.DateTime >= model.ValueDate).OrderBy(x => x.DateTime).FirstOrDefault();
|
|
paKIPrice = paKiResult.Item2[GetDateIndex(paKiResult.Item1, latestKIObservationDate)];
|
|
}
|
|
}
|
|
|
|
model.KnockInBarrierPrice = paKIPrice;
|
|
model.KnockOutBarrierPrice = paKOPrice;
|
|
model.CouponBarrierPrice = paCoupon;
|
|
|
|
if (model.trade.IsMoneynessOption == "是")
|
|
{
|
|
model.KnockInBarrierPrice = paKIPrice * trade.SpotPrice;
|
|
model.KnockOutBarrierPrice = paKOPrice * trade.SpotPrice;
|
|
model.CouponBarrierPrice = paCoupon * trade.SpotPrice;
|
|
}
|
|
|
|
if (model.GuaranteedIncomeSymbol == "2")
|
|
{
|
|
model.CouponAnnualRate = couponRate + (model.GuaranteedIncome ?? 0);
|
|
}
|
|
else
|
|
{
|
|
model.CouponAnnualRate = couponRate + (trade.OriginalPrincipalSum / trade.SpotPrice);
|
|
}
|
|
|
|
//凤凰敲出时,判断敲出日期是否小杨到期日,是的话,提前终止日期需赋值
|
|
if (!string.IsNullOrEmpty(trade.trade_autocall.KnockInOutStatus) && (trade.trade_autocall.KnockInOutStatusCn.Contains("敲出") || trade.trade_autocall.KnockInOutStatus.ToLower().Contains("out")))
|
|
{
|
|
if (trade.trade_autocall.KnockInOutDate < model.EndDate)
|
|
{
|
|
model.UnWindDate = trade.trade_autocall.KnockInOutDate;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置远期结构的字段
|
|
/// </summary>
|
|
/// <param name="model"></param>
|
|
private void setForwardFields(SuperviseReportBaseModel model)
|
|
{
|
|
var trade = model.trade;
|
|
|
|
model.ForwardPrice = trade.Strike;
|
|
model.ForwardPriceCurrency = "CNY";
|
|
model.ForwardPriceSymbol = "1";
|
|
//保底收益
|
|
if (model.GuaranteedIncome == null)
|
|
{
|
|
model.GuaranteedIncome = 0;
|
|
model.GuaranteedIncomeSymbol = "1";
|
|
model.GuaranteedIncomeCurrency = "CNY";
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 设置互换结构的字段
|
|
/// </summary>
|
|
/// <param name="model"></param>
|
|
private void setSwapFields(SuperviseReportBaseModel model)
|
|
{
|
|
var trade = model.trade;
|
|
var tSwap = trade.trade_swap;
|
|
|
|
model.FixedIncomeCurrency = "CNY";
|
|
|
|
if (tSwap.IsGetFloatingProfit)
|
|
{
|
|
if (tSwap.GetLongShort == "多头")
|
|
{
|
|
model.FloatingDirection = "1";
|
|
}
|
|
else
|
|
{
|
|
model.FloatingDirection = "2";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
model.FixedIncome = tSwap.GetSwapRate;
|
|
model.FixedIncomeSymbol = "2";
|
|
model.FixedIncomeCurrency = null;
|
|
}
|
|
|
|
if (tSwap.IsPayFloatingProfit)
|
|
{
|
|
if (tSwap.PayLongShort == "多头")
|
|
{
|
|
model.FloatingDirection = "1";
|
|
}
|
|
else
|
|
{
|
|
model.FloatingDirection = "2";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
model.FixedIncome = tSwap.PaySwapRate;
|
|
model.FixedIncomeSymbol = "2";
|
|
model.FixedIncomeCurrency = null;
|
|
}
|
|
|
|
//互换交易,设置了互换利率的话,固定收益又没设置,就读取互换利率的最后一个
|
|
if (model.FixedIncome <= 0)
|
|
{
|
|
if (!string.IsNullOrEmpty(tSwap.GetSwapTimeAndRate))
|
|
{
|
|
var swapTiamAndRateArr = tSwap.GetSwapTimeAndRate.Split(';');
|
|
|
|
if (swapTiamAndRateArr.Length >= 1)
|
|
{
|
|
var swapRateArr = swapTiamAndRateArr[1]?.Split(',');
|
|
model.FixedIncome = double.Parse(swapRateArr[swapRateArr.Length - 1]);
|
|
model.FixedIncomeSymbol = "2";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 自定义字段结构不为空时,处理自定义字段报送
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
private void formatExtendInfo(SuperviseReportBaseModel item)
|
|
{
|
|
var stInfo = DbContext.Structure_Info.FirstOrDefault(n => n.StructureName == item.StructureType);
|
|
if (stInfo == null)
|
|
{
|
|
return;
|
|
}
|
|
item.OptionProductStructure = string.IsNullOrWhiteSpace(stInfo.StructureTypeSm) ? "O" : stInfo.StructureTypeSm;
|
|
var stDetail = DbContext.Structure_Details.Where(n => n.StructureId == stInfo.id).ToList();
|
|
if (stDetail.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
formatCustomProductStructure(item, stInfo, stDetail);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 自定义结构初始化
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <param name="structure"></param>
|
|
/// <param name="structureDetail"></param>
|
|
private void formatCustomProductStructure(SuperviseReportBaseModel model, Structure_Info structure, List<Structure_Details> structureDetail)
|
|
{
|
|
var sdInfoList = JsonHelper.Deserialize<List<StructureDetailInfo>>(model.ExtendInfo);
|
|
string v1, v2, v3, v4, v5, v6, v7, v8, v9, v10;
|
|
switch (structure.StructureTypeSm)
|
|
{
|
|
case "DI":
|
|
case "RA":
|
|
case "AC":
|
|
v1 = GetCustomVal(structureDetail, sdInfoList, "行权收益1");
|
|
v2 = GetCustomVal(structureDetail, sdInfoList, "行权收益2");
|
|
v3 = GetCustomVal(structureDetail, sdInfoList, "行权收益3");
|
|
v4 = GetCustomVal(structureDetail, sdInfoList, "行权收益货币");
|
|
v5 = GetCustomVal(structureDetail, sdInfoList, "行权收益符号");
|
|
if (!string.IsNullOrEmpty(v1))
|
|
{
|
|
model.ExerciseBenefits = NumericalProcessing(v1, out var isPercentage);
|
|
}
|
|
if (!string.IsNullOrEmpty(v2))
|
|
{
|
|
model.ExerciseBenefits2 = NumericalProcessing(v2, out var isPercentage);
|
|
}
|
|
if (!string.IsNullOrEmpty(v3))
|
|
{
|
|
model.ExerciseBenefits3 = NumericalProcessing(v3, out var isPercentage);
|
|
}
|
|
if (!string.IsNullOrEmpty(v4))
|
|
{
|
|
model.ExerciseBenefitsCurrency = v4;
|
|
}
|
|
if (!string.IsNullOrEmpty(v5))
|
|
{
|
|
model.ExerciseBenefitsSymbol = v5;
|
|
}
|
|
break;
|
|
case "DSF":
|
|
case "SKI":
|
|
case "SF":
|
|
v1 = GetCustomVal(structureDetail, sdInfoList, "障碍价1");
|
|
v2 = GetCustomVal(structureDetail, sdInfoList, "障碍价1触碰方向");
|
|
v3 = GetCustomVal(structureDetail, sdInfoList, "障碍价1类型");
|
|
v4 = GetCustomVal(structureDetail, sdInfoList, "障碍价2");
|
|
v5 = GetCustomVal(structureDetail, sdInfoList, "障碍价2触碰方向");
|
|
v6 = GetCustomVal(structureDetail, sdInfoList, "障碍价2类型");
|
|
v7 = GetCustomVal(structureDetail, sdInfoList, "补偿收益1");
|
|
v8 = GetCustomVal(structureDetail, sdInfoList, "补偿收益2");
|
|
v9 = GetCustomVal(structureDetail, sdInfoList, "补偿收益货币");
|
|
v10 = GetCustomVal(structureDetail, sdInfoList, "补偿收益符号");
|
|
|
|
if (!string.IsNullOrEmpty(v1))
|
|
{
|
|
model.BarriersPrice = NumericalProcessing(v1, out var isPercentage);
|
|
if (model.trade.IsMoneynessOption == "是" && isPercentage)
|
|
{
|
|
model.BarriersPrice = model.BarriersPrice * model.trade.OriginalStockEqvNotional;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
model.BarriersPrice = null;
|
|
}
|
|
|
|
|
|
if (!string.IsNullOrEmpty(v2))
|
|
{
|
|
model.BarriersPriceTouchDirection = getCustomBarriersFiled(v2);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(v3))
|
|
{
|
|
model.BarriersPriceType = getCustomBarriersFiled(v3);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(v4))
|
|
{
|
|
model.BarriersPrice2 = NumericalProcessing(v4, out var isPercentage);
|
|
if (model.trade.IsMoneynessOption == "是" && isPercentage)
|
|
{
|
|
model.BarriersPrice2 = model.BarriersPrice2 * model.trade.OriginalStockEqvNotional;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
model.BarriersPrice2 = null;
|
|
}
|
|
|
|
|
|
if (!string.IsNullOrEmpty(v5))
|
|
{
|
|
model.BarriersPrice2TouchDirection = getCustomBarriersFiled(v5);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(v6))
|
|
{
|
|
model.BarriersPrice2Type = getCustomBarriersFiled(v6);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(v7))
|
|
{
|
|
model.CompensationIncome = NumericalProcessing(v7, out var isPercentage);
|
|
}
|
|
else
|
|
{
|
|
model.CompensationIncome = null;
|
|
}
|
|
|
|
|
|
if (!string.IsNullOrEmpty(v8))
|
|
{
|
|
model.CompensationIncome2 = NumericalProcessing(v8, out var isPercentage);
|
|
}
|
|
else
|
|
{
|
|
model.CompensationIncome2 = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(v9))
|
|
{
|
|
model.CompensationIncomeCurrency = v9;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(v10))
|
|
{
|
|
model.CompensationIncomeSymbol = v10;
|
|
}
|
|
|
|
break;
|
|
|
|
case "SA":
|
|
case "GSA":
|
|
case "PA":
|
|
v1 = GetCustomVal(structureDetail, sdInfoList, "SA&PA-敲入障碍价");
|
|
v2 = GetCustomVal(structureDetail, sdInfoList, "SA&PA-敲入观察期");
|
|
v3 = GetCustomVal(structureDetail, sdInfoList, "SA&PA-敲出障碍价");
|
|
v4 = GetCustomVal(structureDetail, sdInfoList, "SA&PA-Coupon障碍价");
|
|
v5 = GetCustomVal(structureDetail, sdInfoList, "SA&PA-Coupon年化收益率");
|
|
if (!string.IsNullOrEmpty(v1))
|
|
{
|
|
model.KnockInBarrierPrice = NumericalProcessing(v1, out var isPercentage);
|
|
if (model.trade.IsMoneynessOption == "是" && isPercentage)
|
|
{
|
|
model.KnockInBarrierPrice = model.KnockInBarrierPrice * model.trade.OriginalStockEqvNotional;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
model.KnockInBarrierPrice = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(v2))
|
|
{
|
|
model.KnockInObservationPeriod = v2;
|
|
}
|
|
if (!string.IsNullOrEmpty(v3))
|
|
{
|
|
model.KnockOutBarrierPrice = NumericalProcessing(v3, out var isPercentage);
|
|
|
|
if (model.trade.IsMoneynessOption == "是" && isPercentage)
|
|
{
|
|
model.KnockOutBarrierPrice = model.KnockOutBarrierPrice * model.trade.OriginalStockEqvNotional;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
model.KnockOutBarrierPrice = null;
|
|
}
|
|
|
|
|
|
if (!string.IsNullOrEmpty(v4))
|
|
{
|
|
model.CouponBarrierPrice = NumericalProcessing(v4, out var isPercentage);
|
|
}
|
|
else
|
|
{
|
|
model.CouponBarrierPrice = null;
|
|
}
|
|
|
|
|
|
if (!string.IsNullOrEmpty(v5))
|
|
{
|
|
model.CouponAnnualRate = NumericalProcessing(v5, out var isPercentage);
|
|
}
|
|
else
|
|
{
|
|
model.CouponAnnualRate = null;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
#region 黑箱自定义基础字段
|
|
string customObserveType, customObserveStartDate, customObserveEndDate,
|
|
customObservationPeriod, customObservePeriodMultiplier, customRevenueCalculationMethod,
|
|
customGuaranteedIncome, customGuaranteedIncomeCurrency, customGuaranteedIncomeSymbol,
|
|
customStrike1, customStrike2, customStrike3, customStrikeCurrency, customStrikeSymbol,
|
|
customExerciseMode, customOptionType, customExerciseDate, customValidDays;
|
|
|
|
|
|
customExerciseMode = GetCustomVal(structureDetail, sdInfoList, "期权行权时间类型");
|
|
customOptionType = GetCustomVal(structureDetail, sdInfoList, "期权权利类型");
|
|
customExerciseDate = GetCustomVal(structureDetail, sdInfoList, "行权日");
|
|
|
|
|
|
customStrike1 = GetCustomVal(structureDetail, sdInfoList, "执行价格1");
|
|
customStrike2 = GetCustomVal(structureDetail, sdInfoList, "执行价格2");
|
|
customStrike3 = GetCustomVal(structureDetail, sdInfoList, "执行价格3");
|
|
customStrikeCurrency = GetCustomVal(structureDetail, sdInfoList, "执行价格货币");
|
|
customStrikeSymbol = GetCustomVal(structureDetail, sdInfoList, "执行价格符号");
|
|
|
|
|
|
customObserveType = GetCustomVal(structureDetail, sdInfoList, "观察类型");
|
|
customObserveStartDate = GetCustomVal(structureDetail, sdInfoList, "观察起始日");
|
|
customObserveEndDate = GetCustomVal(structureDetail, sdInfoList, "观察结束日");
|
|
customObservationPeriod = GetCustomVal(structureDetail, sdInfoList, "观察周期");
|
|
customObservePeriodMultiplier = GetCustomVal(structureDetail, sdInfoList, "观察周期乘数");
|
|
customRevenueCalculationMethod = GetCustomVal(structureDetail, sdInfoList, "收益计算方式");
|
|
customGuaranteedIncome = GetCustomVal(structureDetail, sdInfoList, "保底收益");
|
|
customGuaranteedIncomeCurrency = GetCustomVal(structureDetail, sdInfoList, "保底收益货币");
|
|
customGuaranteedIncomeSymbol = GetCustomVal(structureDetail, sdInfoList, "保底收益符号");
|
|
|
|
customValidDays = GetCustomVal(structureDetail, sdInfoList, "一年有效天数");
|
|
|
|
if (!string.IsNullOrEmpty(customValidDays))
|
|
{
|
|
model.ValidDaysStr = customValidDays;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customExerciseMode))
|
|
{
|
|
model.ExerciseMode = getCustomExerciseMode(customExerciseMode);
|
|
}
|
|
else
|
|
{
|
|
model.ExerciseMode = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customOptionType))
|
|
{
|
|
model.OptionType = getCustomOptionType(customOptionType);
|
|
}
|
|
else
|
|
{
|
|
model.OptionType = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customExerciseDate))
|
|
{
|
|
model.ExerciseDate = DateTime.Parse(customExerciseDate);
|
|
}
|
|
else
|
|
{
|
|
model.ExerciseDate = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customStrike1))
|
|
{
|
|
model.Strike = NumericalProcessing(customStrike1, out var isPercentage);
|
|
if (model.trade.IsMoneynessOption == "是" && isPercentage)
|
|
{
|
|
model.Strike = ((model.Strike * model.trade.SpotPrice) ?? 0);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
model.Strike = null;
|
|
}
|
|
|
|
|
|
if (!string.IsNullOrEmpty(customStrike2))
|
|
{
|
|
model.Strike2 = NumericalProcessing(customStrike2, out var isPercentage);
|
|
if (model.trade.IsMoneynessOption == "是" && isPercentage)
|
|
{
|
|
model.Strike2 = ((model.Strike2 * model.trade.SpotPrice) ?? 0);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
model.Strike2 = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customStrike3))
|
|
{
|
|
model.Strike3 = NumericalProcessing(customStrike3, out var isPercentage);
|
|
if (model.trade.IsMoneynessOption == "是" && isPercentage)
|
|
{
|
|
model.Strike3 = ((model.Strike3 * model.trade.SpotPrice) ?? 0);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
model.Strike3 = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customStrikeCurrency))
|
|
{
|
|
model.StrikeCurrency = customStrikeCurrency;
|
|
}
|
|
else if (model.Strike != null)
|
|
{
|
|
if (model.UnderlyingInitialPriceSymbol == "1")
|
|
{
|
|
model.StrikeCurrency = "CNY";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
model.StrikeCurrency = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customStrikeSymbol))
|
|
{
|
|
model.StrikeSymbol = customStrikeSymbol;
|
|
}
|
|
else if (model.Strike != null)
|
|
{
|
|
model.StrikeSymbol = model.UnderlyingInitialPriceSymbol;
|
|
}
|
|
else
|
|
{
|
|
model.StrikeSymbol = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customObserveType))
|
|
{
|
|
model.ObserveType = getCustomObType(customObserveType).ToUpper();
|
|
}
|
|
|
|
|
|
if (!string.IsNullOrEmpty(customObserveStartDate))
|
|
{
|
|
model.ObserveStartDate = DateTime.Parse(customObserveStartDate);
|
|
}
|
|
|
|
|
|
if (!string.IsNullOrEmpty(customObserveEndDate))
|
|
{
|
|
model.ObserveEndDate = DateTime.Parse(customObserveEndDate);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customObservationPeriod))
|
|
{
|
|
model.ObservationPeriod = getCustomOBPeriod(customObservationPeriod).ToUpper();
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customObservePeriodMultiplier))
|
|
{
|
|
model.ObservePeriodMultiplier = NumericalProcessing(customObservePeriodMultiplier, out var isPercentage);
|
|
}
|
|
else
|
|
{
|
|
model.ObservePeriodMultiplier = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customRevenueCalculationMethod))
|
|
{
|
|
model.RevenueCalculationMethod = getCustomRCMethod(customRevenueCalculationMethod).ToUpper();
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customGuaranteedIncome))
|
|
{
|
|
model.GuaranteedIncome = NumericalProcessing(customGuaranteedIncome, out _);
|
|
}
|
|
else
|
|
{
|
|
model.GuaranteedIncome = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customGuaranteedIncomeSymbol))
|
|
{
|
|
model.GuaranteedIncomeSymbol = customGuaranteedIncomeSymbol;
|
|
}
|
|
else if (model.GuaranteedIncome != null)
|
|
{
|
|
model.GuaranteedIncomeSymbol = "1";
|
|
}
|
|
else
|
|
{
|
|
model.GuaranteedIncomeSymbol = null;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(customGuaranteedIncomeCurrency))
|
|
{
|
|
model.GuaranteedIncomeCurrency = customGuaranteedIncomeCurrency;
|
|
}
|
|
else if (!string.IsNullOrWhiteSpace(model.GuaranteedIncomeSymbol) && model.GuaranteedIncomeSymbol == "1")
|
|
{
|
|
model.GuaranteedIncomeCurrency = "CNY";
|
|
}
|
|
else
|
|
{
|
|
model.GuaranteedIncomeCurrency = null;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// 关联获取数据
|
|
/// </summary>
|
|
/// <param name="structureDetail"></param>
|
|
/// <param name="sdInfoList"></param>
|
|
/// <param name="FieldNameSm"></param>
|
|
/// <returns></returns>
|
|
private string GetCustomVal(List<Structure_Details> structureDetail, List<StructureDetailInfo> sdInfoList, string FieldNameSm)
|
|
{
|
|
|
|
var query = (from sd in sdInfoList
|
|
join std in structureDetail on sd.name.ToLower() equals std.ColumnName.ToLower()
|
|
where (!string.IsNullOrWhiteSpace(std.FieldNameSm) && std.FieldNameSm == FieldNameSm) || (string.IsNullOrWhiteSpace(std.FieldNameSm) && std.ColumnName == FieldNameSm)
|
|
select sd).FirstOrDefault();
|
|
return query == null ? "" : query.value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 数值处理
|
|
/// </summary>
|
|
/// <param name="inpVal"></param>
|
|
/// <returns></returns>
|
|
private double NumericalProcessing(string inpVal, out bool isPercentage)
|
|
{
|
|
double resultVal = 0;
|
|
isPercentage = false;
|
|
if (inpVal.IndexOf(',') >= 0)
|
|
{
|
|
inpVal = inpVal.Replace(",", "");
|
|
}
|
|
|
|
if (inpVal.EndsWith("%"))
|
|
{
|
|
isPercentage = true;
|
|
inpVal = inpVal.Replace("%", "");
|
|
}
|
|
|
|
resultVal = Convert.ToDouble(inpVal);
|
|
|
|
if (isPercentage)
|
|
{
|
|
resultVal = resultVal / 100;
|
|
}
|
|
return resultVal;
|
|
}
|
|
|
|
private string getCustomObType(string input)
|
|
{
|
|
switch (input)
|
|
{
|
|
case "离散":
|
|
case "离散观察":
|
|
return "DISCRETE";
|
|
case "连续":
|
|
case "连续观察":
|
|
return "CONTINUOUS";
|
|
case "到期":
|
|
case "到期观察":
|
|
return "TERMINAL";
|
|
default: return input;
|
|
}
|
|
}
|
|
|
|
private string getCustomOBPeriod(string inputVal)
|
|
{
|
|
switch (inputVal)
|
|
{
|
|
case "日度":
|
|
case "D":
|
|
case "d":
|
|
return "DAIL";
|
|
case "周度":
|
|
case "W":
|
|
case "w":
|
|
return "WEEK";
|
|
case "月度":
|
|
case "M":
|
|
case "m":
|
|
return "MNTH";
|
|
case "年度":
|
|
case "Y":
|
|
case "y":
|
|
return "YEAR";
|
|
default: return inputVal;
|
|
}
|
|
}
|
|
|
|
private string getCustomRCMethod(string input)
|
|
{
|
|
switch (input)
|
|
{
|
|
case "递延至期末支付":
|
|
return "EXPIRY";
|
|
case "即期计算":
|
|
case "立即支付":
|
|
return "HIT";
|
|
default: return input;
|
|
}
|
|
}
|
|
|
|
private string getCustomBarriersFiled(string input)
|
|
{
|
|
switch (input)
|
|
{
|
|
case "向上":
|
|
return "Up";
|
|
case "向下":
|
|
return "Down";
|
|
case "敲入":
|
|
return "In";
|
|
case "敲出":
|
|
return "Out";
|
|
default: return input;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 黑箱自定义期权行权时间类型
|
|
/// </summary>
|
|
/// <param name="input"></param>
|
|
/// <returns></returns>
|
|
private string getCustomExerciseMode(string input)
|
|
{
|
|
switch (input)
|
|
{
|
|
case "欧式":
|
|
return "EU";
|
|
case "美式":
|
|
return "US";
|
|
case "百慕大":
|
|
return "BD";
|
|
case "其他":
|
|
return "O";
|
|
default: return input;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 黑箱自定义期权权利类型
|
|
/// </summary>
|
|
/// <param name="input"></param>
|
|
/// <returns></returns>
|
|
private string getCustomOptionType(string input)
|
|
{
|
|
switch (input.ToLower())
|
|
{
|
|
case "put":
|
|
case "看跌":
|
|
return "1";
|
|
case "call":
|
|
case "看涨":
|
|
return "2";
|
|
case "chooser":
|
|
return "3";
|
|
case "其他":
|
|
case "价差":
|
|
return "9";
|
|
default: return input;
|
|
}
|
|
}
|
|
|
|
private int GetDateIndex(Date[] source, Date value)
|
|
{
|
|
var index = 0;
|
|
foreach (var item in source)
|
|
{
|
|
if (item.DateTime == value.DateTime)
|
|
{
|
|
return index;
|
|
}
|
|
|
|
index++;
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
}
|