Files
zszq-trs/YLErpDAL/Modules/SuperviseReportModule/CFMMC/Service/SuperviseReportBaseService.cs
T
2024-05-09 14:06:26 +08:00

541 lines
23 KiB
C#

using BaseOUDAL;
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.CFMMC.Model;
namespace YLErp.Modules.SuperviseReportModule.CFMMC.Service
{
public abstract class SuperviseReportBaseService : YLBaseService
{
protected SuperviseReportReq _req { get; set; }
/// <summary>
/// 是否是权益报告
/// </summary>
protected bool _isEquity => _req.DataSource == "权益";
/// <summary>
/// 分隔符
/// <para>权益:分号</para>
/// <para>商品:逗号</para>
/// </summary>
protected string _separator => _isEquity ? ";" : ",";
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>
/// <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> varietyTypes, List<DictionaryItem> assetTypes, List<DictionaryItem> varietySuffixs, List<DictionaryItem> varietyCodeList, out SyntheticPriceModel syntheticPrice)
{
if (model.trade == null)
{
throw new ServiceException($"日终Trade不存在,交易编号:{model.OriginalTradeNumber}");
}
model.BuySell = model.trade.BuySell == "买入" ? "B" : "S";
if (model.trade.TradeType == "远期")
{
if (model.trade.OptionType == "看跌")
{
model.BuySell = model.trade.BuySell == "卖出" ? "B" : "S";
}
}
model.ToolType = formatToolType(model.trade.TradeType, model.StructureType);
model.ExerciseMode = /*ignoreTradeTypes.Contains(model.trade.TradeType) ? "O" :*/ IsOption(model.trade) ? (model.trade.ExerciseMode == "European" ? "EU" : "US") : "";
//国投特殊处理
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") : "";
model.Strike = (model.trade.IsMoneynessOptionData ? model.trade.SpotPrice * model.trade.Strike : model.trade.Strike) ?? 0;
model.Strike = model.TradeType == "收益互换" ? Convert.ToDouble((model.trade.SpotPrice)) : model.Strike;
model.ParticipateRate = model.trade.ParticipationRate ?? 1;
if (model.trade.TradeType == "雪球期权")
{
model.IsAnnualTrade = (model.trade.trade_snowball?.IsAnnualized2).GetValueOrDefault() ? "Y" : "N";
}
else if (model.trade.TradeType == "凤凰期权")
{
model.IsAnnualTrade = (model.trade.trade_autocall?.IsAnnualized2).GetValueOrDefault() ? "Y" : "N";
}
else
{
model.IsAnnualTrade = model.trade.IsAnnualized ? "Y" : "N";
}
//国投特殊处理
model.IsAnnualTrade = PS.Config.Company == Configuration.CompanyEnum.国投 && model.TradeType == "收益互换" ? "" : model.IsAnnualTrade;
model.TradeNumber = formatTradeNumber(model);
model.TradeTypeEn = IsOption(model.trade) ? formatTradeTypeEn(model) : (model.TradeType == "收益互换" && PS.Config.Company == Configuration.CompanyEnum.华安) ? "VE" : "";
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(model.trade.UnderlyingCode);
if (um.IsSynthetic() || !string.IsNullOrWhiteSpace(model.trade.BasisUnderlyingCode))
{
Dictionary<string, string> 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 (int i = 0; i < arrPrice.Length; i++)
{
prides[i] = new UnderlyingPriceModel();
prides[i].Price = double.TryParse(arrPrice[i], out var p) ? p : 0;
prides[i].Coefficient = i == 0 ? 1 : -1;
prides[i].UnderlyingCode = i == 0 ? model.trade.UnderlyingCode : model.trade.BasisUnderlyingCode;
}
syntheticPrice = new SyntheticPriceModel();
syntheticPrice.SuList = prides;
}
UnderlyingPriceModel[] underlyingCodes = syntheticPrice.SuList.Select(O => O).ToArray();
string[] arrCode = new string[underlyingCodes.Length];
string[] arrUnitZh = new string[underlyingCodes.Length];
string[] arrUnitEn = new string[underlyingCodes.Length];
string[] arrAssetTypeEn = new string[underlyingCodes.Length];
string[] arrVarietyType = new string[underlyingCodes.Length];
for (int i = 0; i < underlyingCodes.Length; i++)
{
if (underlyingCodes[i] == null || string.IsNullOrWhiteSpace(underlyingCodes[i].UnderlyingCode))
{
arrCode[i] = "";
arrUnitZh[i] = "";
arrUnitEn[i] = "";
arrAssetTypeEn[i] = "";
arrVarietyType[i] = "";
continue;
}
var variety = UnderlyingDataProvider.GetVariety(underlyingCodes[i].UnderlyingCode);
if (variety == null) { throw new ServiceException($"未找到品种数据: {underlyingCodes[i].UnderlyingCode}"); }
var um1 = UnderlyingDataProvider.GetUnderlying(underlyingCodes[i].UnderlyingCode);
string varietySuffix = formatDictItem(varietySuffixs, um1?.MarketCode, um1?.MarketCode);
marketNoDict[underlyingCodes[i].UnderlyingCode] = varietySuffix;
arrCode[i] = formatVarietyCode(underlyingCodes[i].UnderlyingCode, variety, varietyCodeList, varietySuffix);
arrUnitZh[i] = variety.QuoteUnitSingleOriginal;
arrUnitEn[i] = formatQuoteUnit(arrUnitZh[i]);
arrAssetTypeEn[i] = formatDictItem(assetTypes, variety.AssetType);
arrVarietyType[i] = formatDictItem(varietyTypes, variety.AssetType, "O");
}
model.UnderlyingCode = formatSyntheticUnderlying(syntheticPrice, marketNoDict);
//model.TradeAmount = string.Join(",", arrAmount);
model.VarietyCode = JoinArr(arrCode);
model.QuoteUnit = JoinArr(arrUnitZh);
model.QuoteUnitEn = JoinArr(arrUnitEn);
model.AssetTypeEn = JoinArr(arrAssetTypeEn);
model.VarietyType = JoinArr(arrVarietyType);
if (arrUnitEn.All(o => o == "bp"))
{
model.PriceSymbol = 3;
}
}
else
{
var variety = UnderlyingDataProvider.GetVariety(model.trade.UnderlyingCode);
if (variety == null) { throw new ServiceException($"未找到品种数据: {model.trade.UnderlyingCode}"); }
string varietySuffix = formatDictItem(varietySuffixs, um?.MarketCode, um?.MarketCode);
//model.TradeAmount = formatTradeAmount(model.trade.OriginalNotional);
model.UnderlyingCode = formatUnderlyingCode(model.trade.UnderlyingCode, varietySuffix);
model.VarietyCode = formatVarietyCode(model.trade.UnderlyingCode, variety, varietyCodeList, varietySuffix);
model.QuoteUnit = (variety?.QuoteUnitSingleOriginal) ?? "";
model.QuoteUnitEn = formatQuoteUnit(variety?.QuoteUnitSingleOriginal);
model.AssetTypeEn = formatDictItem(assetTypes, variety.AssetType);
model.VarietyType = formatDictItem(varietyTypes, variety.AssetType, "O");
if (model.QuoteUnitEn == "bp")
{
model.PriceSymbol = 3;
}
syntheticPrice = null;
}
}
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)
{
double? value = notional * coefficient;
return OtcFormatHelper.FormatValue(value, 4).ToString();
}
private string formatToolType(string tradeType, string structureType)
{
string 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) =>
{
string code = formatUnderlyingCode(_underlyingCode, exchangeNo[_underlyingCode]);
string coef = Math.Abs(_coefficient).ToString();
return $"{(coef == "1" ? "" : 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;
}
private string formatUnderlyingCode(string underlyingCode, string exchangeNo)
{
if (string.IsNullOrWhiteSpace(underlyingCode))
{
throw new ArgumentException("标的代码不存在", nameof(underlyingCode));
}
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}";
}
private string formatTradeNumber(SuperviseReportBaseModel model)
{
if ((model.trade.ParentTradeId > 0))
{
var legNumber = 0;
if (PS.Config.Company == Configuration.CompanyEnum.浙期)
{
if (!int.TryParse(Regex.Match(model.OriginalTradeNumber ?? "", @"(?<=X)\d+$").Value, out legNumber))
{
return "";
}
}
else if (!int.TryParse(Regex.Match(model.trade.TradeNumber ?? "", @"(?<=-)\d+$").Value, out legNumber))
{
return "";
}
return legNumber.ToString();
}
else
{
return "";
}
}
private string formatTradeTypeEn(SuperviseReportBaseModel model)
{
string tradeTypeEn = "O";
switch (model.TradeType)
{
case "香草期权":
tradeTypeEn = "VA";
break;
case "结构化交易":
switch (model.StructureType)
{
case "风险逆转":
tradeTypeEn = "RE";
break;
case "三领口":
case "三领口组合":
tradeTypeEn = "CO";
break;
case "跨式组合":
tradeTypeEn = "STR";
break;
case "宽跨式":
case "宽跨式组合":
tradeTypeEn = "STA";
break;
case "牛市价差":
case "熊市价差":
tradeTypeEn = "VE";
break;
case "结构化交易":
//自由组合
default:
break;
}
break;
case "合成价差期权":
tradeTypeEn = "SP";
break;
case "凤凰期权":
tradeTypeEn = "PA";
break;
case "雪球期权":
tradeTypeEn = "SA";
break;
case "障碍期权":
tradeTypeEn = "SF";
break;
case "二元期权":
switch (model.ExerciseMode)
{
case "US":
case "American":
switch (model.PayoffType)
{
case "UpOneTouch":
case "DownOneTouch":
case "DoubleOneTouch":
tradeTypeEn = "OT";
break;
case "DoubleNoTouch":
tradeTypeEn = "DNT";
break;
case "UpNoTouch":
case "DownNoTouch":
break;
default:
break;
}
break;
case "EU":
case "European":
tradeTypeEn = "DI";
switch (model.PayoffType)
{
case "AssetOrNothing":
break;
case "CashOrNothing":
break;
default:
break;
}
break;
default:
break;
}
break;
case "亚式期权":
tradeTypeEn = "AS";
break;
case "双鲨期权":
tradeTypeEn = "DSF";
break;
case "区间累计期权":
case "区间累积期权":
tradeTypeEn = "RA";
break;
default:
tradeTypeEn = "O";
break;
}
return tradeTypeEn;
}
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);
}
string 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));
break;
default:
assetVariety = underlyingCode;
break;
}
return assetVariety;
}
private string getStockVarietyCode(string code)
{
string assetVariety = "";
if (code.StartsWith("60") || code.StartsWith("000"))
{ //主板
assetVariety = "ZB";
}
else if (code.StartsWith("002"))
{//中小板
assetVariety = "ZXB";
}
else if (code.StartsWith("300"))
{//创业板
assetVariety = "CYB";
}
else if (code.StartsWith("688"))
{//科创版
assetVariety = "KCB";
}
else
{
assetVariety = "JW";
}
return assetVariety;
}
private string formatQuoteUnit(string quoteUnit)
{
switch (quoteUnit)
{
case "吨":
return "t";
case "桶":
return "barrel";
case "克":
return "g";
case "千克":
return "kg";
case "500千克":
return "500kg";
case "股":
return "share";
case "点":
if (PS.Config.Company == Configuration.CompanyEnum.国投)
{
return "bp";
}
return "point";
case "基点":
return "bp";
case "units":
return "units";
default:
return "o";
}
//return quoteUnit;
}
protected double formatEndStockEqvNotionalReal(double? stockEqvNotional, double percentRate)
{
double? result = stockEqvNotional * percentRate;
return Math.Abs(OtcFormatHelper.FormatValue((result ?? 0), 4));
}
protected string JoinArr(string[] arr)
{
HashSet<string> 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 == "自定义交易";
}
}
}