1388 lines
74 KiB
C#
1388 lines
74 KiB
C#
using BaseOUDAL;
|
|
using Qdp.Pricing.Base.Utilities;
|
|
using Qdp.Pricing.Library.Common.Interfaces;
|
|
using Qdp.Pricing.Library.Options.Products.Asian;
|
|
using YLErp.BLL;
|
|
using YLErp.Commons;
|
|
using YLErp.DBModels.Consts;
|
|
using YLErp.Helpers;
|
|
using YLErp.Model;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.SuperviseReportModule.CFMMC2022.Model;
|
|
using static iTextSharp.text.pdf.AcroFields;
|
|
using static YLErp.ConsGlobal;
|
|
|
|
namespace YLErp.Modules.SuperviseReportModule.CFMMC2022.Service
|
|
{
|
|
public class SuperviseReportPositionService : SuperviseReportBaseService
|
|
{
|
|
private string _volType { get; set; }
|
|
public SuperviseReportPositionService(SuperviseReportReq req, OptUserInfo userInfo) : base(req, userInfo)
|
|
{
|
|
var arr = req.DataSource?.Split(',') ?? new string[2];
|
|
_volType = arr[0];
|
|
req.DataSource = arr[1];
|
|
}
|
|
|
|
/// <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 void FormatModel(NewSuperviseReportPositionModel model, List<DictionaryItem> assetTypes, List<DictionaryItem> varietySuffixs, List<DictionaryItem> varietyCodeList, Dictionary<int, EodTradeRisk> eRiskInfos, out SyntheticPriceModel syntheticPrice)
|
|
{
|
|
var obj = (NewSuperviseReportPositionModel)model;
|
|
obj.TradeDate = obj.trade.TradeDate;
|
|
obj.StartDate = obj.trade.TradeDate;
|
|
obj.EndDate = obj.trade.ExerciseDate;
|
|
base.FormatModel(obj, assetTypes, varietySuffixs, varietyCodeList, out syntheticPrice);
|
|
//持仓报告 设置特定字段
|
|
formatOptionlFields(obj);
|
|
double eqv = 0, endEqv = 0;
|
|
var annualizeFactor = obj.trade.IsAnnualized ? obj.trade.AnnualizeFactor : 1;
|
|
|
|
|
|
var trade = obj.trade;
|
|
var ignoreTradeTypes = new List<string>()
|
|
{
|
|
"远期",
|
|
"收益互换",
|
|
"掉期",
|
|
};
|
|
eRiskInfos.TryGetValue(obj.TradeId, out var eRisk);
|
|
if (obj.IsGroup == 1)
|
|
{
|
|
var childIds = DbContext.trade.Where(x => x.ParentTradeId == obj.TradeId).Select(x => x.id);
|
|
var riskChilds = DbContext.eod_trade_risk.Where(x => childIds.Contains(x.TradeId) && x.ValueDate == _req.ValueDate).ToList();
|
|
obj.ContractPrice = riskChilds.Sum(x => x.Pv);
|
|
obj.Delta = riskChilds.Sum(x => x.Delta).OtcFormat(OtcFormatFlag.greek);
|
|
obj.Vega = riskChilds.Sum(x => x.Vega).OtcFormat(OtcFormatFlag.greek);
|
|
obj.Theta = riskChilds.Sum(x => x.Theta).OtcFormat(OtcFormatFlag.greek);
|
|
obj.Rho = (riskChilds.Sum(x => x.Rho) * 100).OtcFormat(OtcFormatFlag.greek);
|
|
obj.Gamma = riskChilds.Sum(x => x.Gamma).OtcFormat(OtcFormatFlag.greek);
|
|
|
|
obj._delta = riskChilds.Sum(x => x.Delta);
|
|
obj._gamma = riskChilds.Sum(x => x.Gamma);
|
|
|
|
//估值波动率
|
|
obj.ValuationVolatility = eRisk == null ? null : eRisk.Vol > 0 ? eRisk.Vol.OtcFormat(OtcFormatFlag.greek) : null;
|
|
if (!string.IsNullOrEmpty(model.trade.ExtendInfo))
|
|
{
|
|
var tempVolat = 0D;
|
|
var isVolat = false;
|
|
foreach (var rItem in riskChilds)
|
|
{
|
|
if (rItem.Vol == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (tempVolat == 0)
|
|
{
|
|
tempVolat = rItem.Vol;
|
|
}
|
|
|
|
if (tempVolat == rItem.Vol)
|
|
{
|
|
isVolat = true;
|
|
}
|
|
else
|
|
{
|
|
isVolat = false;
|
|
}
|
|
tempVolat = rItem.Vol;
|
|
}
|
|
if (isVolat)
|
|
{
|
|
model.ValuationVolatility = tempVolat == 0 ? null : tempVolat.OtcFormat(OtcFormatFlag.greek);
|
|
}
|
|
}
|
|
}
|
|
else if (!ignoreTradeTypes.Contains(obj.TradeType))
|
|
{
|
|
obj.Delta = ((double)(eRisk?.Delta ?? 0)).OtcFormat(OtcFormatFlag.greek);
|
|
obj.Vega = (eRisk?.Vega ?? 0).OtcFormat(OtcFormatFlag.greek);
|
|
obj.Theta = (eRisk?.Theta ?? 0).OtcFormat(OtcFormatFlag.greek);
|
|
obj.Rho = ((eRisk?.Rho ?? 0) * 100).OtcFormat(OtcFormatFlag.greek);
|
|
var otherRisks = JsonHelper.Parse<OtherRisks>(eRisk?.OtherRisks);
|
|
if (otherRisks == null || string.IsNullOrWhiteSpace(otherRisks.CrossGamma))
|
|
{
|
|
obj.Gamma = (eRisk?.Gamma ?? 0).OtcFormat(OtcFormatFlag.greek);
|
|
}
|
|
else
|
|
{
|
|
obj.Gamma = otherRisks.CrossGamma.Replace(",", ";");
|
|
}
|
|
//估值波动率
|
|
obj.ValuationVolatility = eRisk == null ? null : eRisk.Vol > 0 ? eRisk.Vol.OtcFormat(OtcFormatFlag.greek) : null;
|
|
obj._delta = ((double)(eRisk?.Delta ?? 0));
|
|
obj._gamma = (eRisk?.Gamma ?? 0);
|
|
}
|
|
else
|
|
{
|
|
obj.Delta = ((double)(eRisk?.Delta ?? 0)).OtcFormat(OtcFormatFlag.greek);
|
|
obj._delta = (eRisk?.Delta ?? 0);
|
|
if (PS.Config.Company == Configuration.CompanyEnum.浙期 && !string.IsNullOrWhiteSpace(trade.BasisUnderlyingCode))
|
|
{
|
|
|
|
obj.Delta += ";" + obj.Delta;
|
|
obj.DeltaCash += ";" + obj.DeltaCash;
|
|
obj.GammaCash = "0";
|
|
}
|
|
}
|
|
|
|
|
|
//组合标的
|
|
if (syntheticPrice != null && syntheticPrice.SuList.Count() > 0)
|
|
{
|
|
var underlyingPrices = syntheticPrice.SuList.ToArray();
|
|
var arrSEN = new string[underlyingPrices.Length];
|
|
var arrSEN2 = new string[underlyingPrices.Length];
|
|
var arrAmount = new string[underlyingPrices.Length];
|
|
var arrEndAmount = new string[underlyingPrices.Length];
|
|
var arrUnderlyingInitialPrice = new string[underlyingPrices.Length];
|
|
var arrUnderlyingInitialPriceCurrency = new string[underlyingPrices.Length];
|
|
var arrContractValuationPrice = new string[underlyingPrices.Length];
|
|
|
|
var arrGammaCash = new string[underlyingPrices.Length];
|
|
var arrDeltaCash = new string[underlyingPrices.Length];
|
|
var notional = obj.trade.OriginalNotional;
|
|
if (PS.Config.Is广期资本 && "自定义交易".Equals(obj.trade.TradeType) && obj.trade.Propertys != null && obj.trade.Propertys.Any(d => "总数量".Equals(d.name)))
|
|
{
|
|
double totalCount = 0;
|
|
if (double.TryParse(obj.trade.Propertys.First(d => "总数量".Equals(d.name)).value, out totalCount))
|
|
{
|
|
notional = totalCount * obj.trade.CountRatio ?? 1;
|
|
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < underlyingPrices.Length; i++)
|
|
{
|
|
var originalStockEqvNotional = (underlyingPrices[i].Price * notional / annualizeFactor / obj.trade.ParticipationRate * underlyingPrices[i].Coefficient) ?? 0;
|
|
|
|
eqv = formatEndStockEqvNotionalReal(originalStockEqvNotional, 1);
|
|
endEqv = formatEndStockEqvNotionalReal(originalStockEqvNotional, (1 - (obj.trade.Notional / obj.trade.OriginalNotional ?? 1)));
|
|
|
|
arrAmount[i] = formatTradeAmount(eqv / underlyingPrices[i].Price);
|
|
arrEndAmount[i] = formatTradeAmount(endEqv / underlyingPrices[i].Price);
|
|
|
|
arrSEN[i] = (obj.ForeignCurrencyRate != null ? eqv * obj.ForeignCurrencyRate : eqv).ToString();
|
|
|
|
arrSEN2[i] = (obj.ForeignCurrencyRate != null ? endEqv * obj.ForeignCurrencyRate : endEqv).ToString();
|
|
|
|
var um1 = UnderlyingDataProvider.GetUnderlying(underlyingPrices[i].UnderlyingCode);
|
|
var variety = DataCacheProvider.GetVarietyDataSource().GetData(um1.UnderlyingTypeId);
|
|
if (variety.QuoteCurrency != null && (variety.QuoteCurrency.ToLower() == "usc" || variety.QuoteCurrency.ToLower() == "usd(cent)"))
|
|
{
|
|
arrSEN[i] = (obj.ForeignCurrencyRate != null ? eqv * obj.ForeignCurrencyRate / 100 : eqv).ToString();
|
|
|
|
arrSEN2[i] = (obj.ForeignCurrencyRate != null ? endEqv * obj.ForeignCurrencyRate / 100 : endEqv).ToString();
|
|
}
|
|
|
|
arrUnderlyingInitialPrice[i] = underlyingPrices[i].Price.ToString();
|
|
arrUnderlyingInitialPriceCurrency[i] = string.IsNullOrEmpty(variety.QuoteCurrency) ? "CNY" : variety.QuoteCurrency;
|
|
|
|
arrContractValuationPrice[i] = _priceProvider.GetPrice(underlyingPrices[i].UnderlyingCode).ToString();
|
|
|
|
if (obj._delta != null)
|
|
{
|
|
arrDeltaCash[i] = OtcFormatHelper.FormatValue((obj._delta * underlyingPrices[i].Price), 4).ToString();
|
|
}
|
|
if (obj._gamma != null)
|
|
{
|
|
arrGammaCash[i] = OtcFormatHelper.FormatValue((obj._delta * underlyingPrices[i].Price), 4).ToString();
|
|
}
|
|
|
|
}
|
|
//初始名义金额
|
|
obj.InitialNominalAmount = string.Join(base._separator, arrSEN);
|
|
//已平仓总名义金额
|
|
obj.TotalClosedPositionsAmount = string.Join(base._separator, arrSEN2);
|
|
//初始名义数量
|
|
obj.InitialNominalNumber = string.Join(base._separator, arrAmount);
|
|
//已平仓总名义数量
|
|
obj.TotalClosedPositionsNumber = string.Join(base._separator, arrEndAmount);
|
|
//组合标的价格
|
|
obj.UnderlyingInitialPrice = string.Join(base._separator, arrUnderlyingInitialPrice);
|
|
obj.UnderlyingInitialPriceCurrency = string.Join(base._separator, arrUnderlyingInitialPriceCurrency);
|
|
|
|
obj.ContractValuationPrice = string.Join(base._separator, arrContractValuationPrice);
|
|
|
|
obj.DeltaCash = JoinArr(arrDeltaCash);
|
|
|
|
obj.GammaCash = JoinArr(arrGammaCash);
|
|
}
|
|
else
|
|
{
|
|
var notional = obj.trade.OriginalNotional;
|
|
if (PS.Config.Is广期资本 && "自定义交易".Equals(obj.trade.TradeType) && obj.trade.Propertys != null && obj.trade.Propertys.Any(d => "总数量".Equals(d.name)))
|
|
{
|
|
double totalCount = 0;
|
|
if (double.TryParse(obj.trade.Propertys.First(d => "总数量".Equals(d.name)).value, out totalCount))
|
|
{
|
|
notional = totalCount * obj.trade.CountRatio ?? 1;
|
|
obj.trade.OriginalStockEqvNotional = (obj.trade.SpotPrice * notional / obj.trade.AnnualizeFactor / obj.trade.ParticipationRate);
|
|
}
|
|
}
|
|
|
|
var originalStockEqvNotional = (obj.trade.OriginalStockEqvNotional == 0 ? (obj.trade.SpotPrice * notional / obj.trade.AnnualizeFactor / obj.trade.ParticipationRate) : obj.trade.OriginalStockEqvNotional) ?? 0;
|
|
eqv = formatEndStockEqvNotionalReal(originalStockEqvNotional, 1);
|
|
endEqv = formatEndStockEqvNotionalReal(eqv, (1 - (obj.trade.Notional / (obj.trade.OriginalNotional ?? 1))));
|
|
|
|
//初始名义金额
|
|
obj.InitialNominalAmount = (obj.ForeignCurrencyRate != null ? eqv * obj.ForeignCurrencyRate : eqv).ToString();
|
|
//已平仓总名义金额
|
|
obj.TotalClosedPositionsAmount = (obj.ForeignCurrencyRate != null ? endEqv * obj.ForeignCurrencyRate : endEqv).ToString();
|
|
|
|
if (obj.QuoteCurrency != null && (obj.QuoteCurrency.ToLower() == "usc" || obj.QuoteCurrency.ToLower() == "usd(cent)"))
|
|
{
|
|
obj.InitialNominalAmount = (obj.ForeignCurrencyRate != null ? eqv * obj.ForeignCurrencyRate / 100 : eqv).ToString();
|
|
obj.TotalClosedPositionsAmount = (obj.ForeignCurrencyRate != null ? endEqv * obj.ForeignCurrencyRate / 100 : endEqv).ToString();
|
|
}
|
|
|
|
|
|
|
|
//初始名义数量
|
|
obj.InitialNominalNumber = formatTradeAmount(eqv / obj.trade.SpotPrice).ToString();
|
|
//已平仓总名义数量
|
|
obj.TotalClosedPositionsNumber = formatTradeAmount(endEqv / obj.trade.SpotPrice).ToString();
|
|
|
|
if (obj._delta != null)
|
|
{
|
|
obj.DeltaCash = OtcFormatHelper.FormatValue((model._delta * (model._price ?? model.trade.SpotPrice)), 4).ToString();
|
|
}
|
|
if (obj._gamma != null)
|
|
{
|
|
obj.GammaCash = OtcFormatHelper.FormatValue((model._gamma * (model._price ?? model.trade.SpotPrice)), 4).ToString();
|
|
}
|
|
}
|
|
obj.ExerciseDate = obj.trade.ExerciseDate;
|
|
}
|
|
|
|
#region 新持仓报送报表
|
|
private SearchListResult<NewSuperviseReportPositionModel> NewReportQuery(SuperviseReportReq req)
|
|
{
|
|
var commodityList = new List<string> { InstrumentType.CommodityFutures, InstrumentType.CommoditySpot };
|
|
var umQuery = DbContext.underlying_manager.AsQueryable();
|
|
switch (req.DataSource)
|
|
{
|
|
case "权益":
|
|
umQuery = umQuery.Where(O => !commodityList.Contains(O.UnderlyingInstrumentType));
|
|
break;
|
|
case "商品":
|
|
umQuery = umQuery.Where(O => commodityList.Contains(O.UnderlyingInstrumentType));
|
|
break;
|
|
case "全量":
|
|
default:
|
|
break;
|
|
}
|
|
var insidedClientIds = DataCacheProvider.GetClientDataSource().AsQueryable().Where(O => O.IsInsided == 1).Select(O => O.id).ToList();
|
|
var tId = DbContext.eod_trade_position.Where(O => !insidedClientIds.Contains(O.ClientId) && O.ValueDate == req.ValueDate && (ConsTrade.TradeTypesForOtcOptions.Contains(O.TradeType) || O.TradeType == "远期" || O.TradeType == "收益互换") && O.TradeType != "场内期权" && O.TradeId != 0).Select(O => O.TradeId);
|
|
|
|
var query = from eodTrade in DbContext.eod_trade
|
|
join trade in DbContext.trade on eodTrade.TradeId equals trade.id
|
|
join um in umQuery on trade.UnderlyingCode equals um.UnderlyingCode
|
|
join parentTrade in (from tr in DbContext.trade where tr.ValidState != "InValid" && tr.TradeType == "结构化交易" select tr) on trade.ParentTradeId equals parentTrade.id into parentTrades
|
|
from tempParentTrade in parentTrades.DefaultIfEmpty()
|
|
join cPrice in DbContext.eod_commodity_future_price.Where(O => O.ValueDate == req.ValueDate) on trade.UnderlyingCode equals cPrice.UnderlyingCode into tempCPrice
|
|
from cPrice in tempCPrice.DefaultIfEmpty()
|
|
join sPrice in DbContext.eod_stock_price.Where(O => O.ValueDate == req.ValueDate) on trade.UnderlyingCode equals sPrice.UnderlyingCode into tempSPrice
|
|
from sPrice in tempSPrice.DefaultIfEmpty()
|
|
where eodTrade.ValueDate == req.ValueDate && (tId.Contains(eodTrade.TradeId) || trade.IsGroup == 1) && trade.IsGroup != 2 && trade.TradeType != "现金流交易" && eodTrade.ClientId != 0 && ConsTrade.LiveTradeStatusList.Contains(eodTrade.TradeStatus)
|
|
select new NewSuperviseReportPositionModel
|
|
{
|
|
TradeId = eodTrade.TradeId,
|
|
ClientId = eodTrade.ClientId,
|
|
UnderlyingCode = eodTrade.UnderlyingCode,
|
|
ParentTradeId = eodTrade.ParentTradeId,
|
|
TradeStatus = eodTrade.TradeStatus,
|
|
OriginalTradeNumber = eodTrade.TradeNumber,
|
|
TradeJson = eodTrade.TradeJson,
|
|
ValuationMethod = "O",
|
|
UnwindPercentRate = 0,
|
|
ForeignCurrencyRate = null,
|
|
ParticipateRate = 1,
|
|
IsGroup = trade.IsGroup,
|
|
ProductType = trade.TradeType,
|
|
StructureType = trade.StructureType,
|
|
PositionCode = tempParentTrade != null ? tempParentTrade.TradeNumber : trade.TradeNumber,
|
|
OptionProductStructure = eodTrade.TradeType,
|
|
TradeType = tempParentTrade != null ? tempParentTrade.TradeType : trade.TradeType,
|
|
RiskFreeRate = trade.NoRiskRate ?? (valuedateBLL.RiskFreeRate * 0.01),
|
|
Dividend = trade.DividendRate,
|
|
SettlementMethod = "C",
|
|
LastUnWindDate = trade.SettlementDate == null ? trade.ExerciseDate : trade.SettlementDate,
|
|
ExtendInfo = trade.ExtendInfo,
|
|
ValueDate = req.ValueDate,
|
|
StartDate = trade.StartDate,
|
|
_price = cPrice != null ? cPrice.ClosePrice : sPrice.ClosePrice
|
|
};
|
|
var clientcontext = new ClientDBContext();
|
|
var clientids = query.Select(x => x.ClientId).Distinct().ToArray();
|
|
var clients = clientcontext.client.Where(x => clientids.Contains(x.id) && x.IsInsided != 1).Select(x => x.id).ToArray();
|
|
|
|
query = query.Where(x => clients.Contains(x.ClientId)).OrderBy(O => O.OriginalTradeNumber);
|
|
if (string.IsNullOrEmpty(req.sidx))
|
|
{
|
|
req.sidx = "StartDate";
|
|
req.sord = "desc";
|
|
}
|
|
req.sidx = req.sidx + ",TradeId";
|
|
var retListResult = query.ToSearchList(req, true);
|
|
return retListResult;
|
|
}
|
|
|
|
public SearchListResult<NewSuperviseReportPositionModel> NewSearchReportList()
|
|
{
|
|
SearchListResult<NewSuperviseReportPositionModel> retListResult = null;
|
|
using (var basedb = new ErpBaseContext())
|
|
{
|
|
IQueryable<EodTradeRisk> etr = null;
|
|
IQueryable<EodTradePosition> etp = null;
|
|
switch (_volType)
|
|
{
|
|
case "开仓":
|
|
etr = DbContext.eod_trade_risk_openvol.Where(O => O.ValueDate == _req.ValueDate);
|
|
etp = DbContext.eod_trade_position_openvol.Where(O => O.ValueDate == _req.ValueDate);
|
|
break;
|
|
case "持仓":
|
|
default:
|
|
etr = DbContext.eod_trade_risk.Where(O => O.ValueDate == _req.ValueDate);
|
|
etp = DbContext.eod_trade_position.Where(O => O.ValueDate == _req.ValueDate);
|
|
break;
|
|
}
|
|
retListResult = NewReportQuery(_req);
|
|
|
|
var clientIdArr = retListResult.rows.Select(O => O.ClientId).ToHashSet();
|
|
var assetTypeList = (from i in basedb.DictionaryItems join d in basedb.Dictionaries on i.DictId equals d.Id where d.Name == "资产类型" select i).ToList();
|
|
var varietySuffixList = (from i in basedb.DictionaryItems join d in basedb.Dictionaries on i.DictId equals d.Id where d.Name == "标的资产后缀" select i).ToList();
|
|
var varietyCodeList = (from i in basedb.DictionaryItems join d in basedb.Dictionaries on i.DictId equals d.Id where d.Name == "标的资产分类" select i).ToList();
|
|
//var clientMetaQuery = DbContextFactory.GetClientDbContext(UserInfo).ClientMeta.Where(O => clientIdArr.Contains(O.ClientId));
|
|
//var clientEquityInfo = clientMetaQuery.Where(O => O.MetaKey == "RightProtocolSignVersion").ToDictionary(K => K.ClientId, V => V.MetaValue);
|
|
//var clientReportInfo = clientMetaQuery.Where(O => O.MetaKey == "ReportName").ToDictionary(K => K.ClientId, V => V.MetaValue);
|
|
|
|
var tIdArr = retListResult.rows.Select(O => O.TradeId);
|
|
var tpIdArr = retListResult.rows.Select(O => O.ParentTradeId);
|
|
var tradeContractRInfo = DbContext.trade_contract_r.Where(O => tIdArr.Contains(O.TradeId) || tpIdArr.Contains(O.TradeId)).ToList();
|
|
var tcRinfos = tradeContractRInfo.Where(O => O.Type == ContractTypeEnum.Trade).Select(O => new { TradeId = O.TradeId, O.ContractCode }).GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.First().ContractCode);
|
|
var tradeNumberInfo = tradeContractRInfo.Select(O => new { TradeCashId = (O.TradeCashId ?? 0), O.ContractCode }).GroupBy(O => O.TradeCashId).ToDictionary(K => K.Key, V => V.First().ContractCode);
|
|
|
|
var tradeMetaList = DbContext.TradeMeta.Where(O => tIdArr.Contains(O.TradeId)).ToList();
|
|
var iccInfo = tradeMetaList.Where(O => O.MetaKey == "中央对手方清算").Select(O => new { TradeId = O.TradeId, O.MetaValue }).GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.First().MetaValue);
|
|
var ccpInfo = tradeMetaList.Where(O => O.MetaKey == "中央清算平台").Select(O => new { TradeId = O.TradeId, O.MetaValue }).GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.First().MetaValue);
|
|
var tpInfo = tradeMetaList.Where(O => O.MetaKey == "交易平台").Select(O => new { TradeId = O.TradeId, O.MetaValue }).GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.First().MetaValue);
|
|
|
|
//敲入观察频率
|
|
var kiObservatonRate = tradeMetaList.Where(O => O.MetaKey == "敲入观察周期").Select(O => new { TradeId = O.TradeId, O.MetaValue }).GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.First().MetaValue);
|
|
//敲出观察频率
|
|
var koObservationRate = tradeMetaList.Where(O => O.MetaKey == "敲出观察周期").Select(O => new { TradeId = O.TradeId, O.MetaValue }).GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.First().MetaValue);
|
|
|
|
//远期 周期
|
|
var getObservatonRate = tradeMetaList.Where(O => O.MetaKey == "收取周期").Select(O => new { TradeId = O.TradeId, O.MetaValue }).GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.First().MetaValue);
|
|
var payObservatonRate = tradeMetaList.Where(O => O.MetaKey == "支付周期").Select(O => new { TradeId = O.TradeId, O.MetaValue }).GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.First().MetaValue);
|
|
|
|
//外币汇率
|
|
var exChangeRate = tradeMetaList.Where(O => O.MetaKey == "ExchangeRate").Select(O => new { TradeId = O.TradeId, O.MetaValue }).GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.First().MetaValue);
|
|
|
|
var ptIdArr = retListResult.rows.Where(O => O.ParentTradeId != null).Select(O => O.ParentTradeId).ToHashSet();
|
|
var ptInfos = DbContext.trade.Where(O => ptIdArr.Contains(O.id)).Select(O => new { O.id, O.TradeType, O.StructureType, O.TradeNumber }).ToDictionary(K => K.id, V => V);
|
|
var tcRInfos = new Dictionary<int, string>();
|
|
var tmInfos = new Dictionary<int, string>();
|
|
switch (PS.Config.Company)
|
|
{
|
|
case Configuration.CompanyEnum.长江:
|
|
tcRInfos = DbContext.trade_contract_r.Where(O => (tIdArr.Contains(O.TradeId) || ptIdArr.Contains(O.TradeId)) && O.Type == ContractTypeEnum.Trade && O.IsValid).Select(O => new { O.TradeId, O.ContractCode }).AsEnumerable().GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.FirstOrDefault().ContractCode);
|
|
tmInfos = DbContext.TradeMeta.Where(O => (tIdArr.Contains(O.TradeId) || ptIdArr.Contains(O.TradeId)) && O.MetaKey == ConsTradeMetaKey.ContractCode).ToDictionary(K => K.TradeId, V => V.MetaValue);
|
|
break;
|
|
case Configuration.CompanyEnum.浙期:
|
|
case Configuration.CompanyEnum.物产中大:
|
|
tmInfos = DbContext.TradeMeta.Where(O => (tIdArr.Contains(O.TradeId) || ptIdArr.Contains(O.TradeId)) && O.MetaKey == ConsTradeMetaKey.ContractCode).ToDictionary(K => K.TradeId, V => V.MetaValue);
|
|
break;
|
|
}
|
|
var clientMetaQuery = DbContextFactory.GetClientDbContext(UserInfo).ClientMeta.Where(O => clientIdArr.Contains(O.ClientId));
|
|
var clientReportInfo = clientMetaQuery.Where(O => O.MetaKey == "ReportName").ToDictionary(K => K.ClientId, V => V.MetaValue);
|
|
|
|
try
|
|
{
|
|
BLL.tradeBLL.SetFieldsByTradeType(retListResult.rows.Select(o => o.trade));
|
|
Dictionary<int, EodTradePosition> ePnlInfos = null;
|
|
Dictionary<int, EodTradeRisk> eRiskInfos = null;
|
|
var func = new Func<EodTradeRisk, EodTradeRisk>(O => new EodTradeRisk
|
|
{
|
|
TradeId = O.TradeId,
|
|
Delta = O.Delta,
|
|
DeltaCash = O.DeltaCash,
|
|
GammaCash = O.GammaCash,
|
|
Theta = O.Theta,
|
|
Gamma = O.Gamma,
|
|
Rho = O.Rho,
|
|
Vega = O.Vega,
|
|
Vol = O.Vol,
|
|
OtherRisks = O.OtherRisks
|
|
});
|
|
ePnlInfos = etp.Where(O => tIdArr.Contains(O.TradeId)).Select(O => new EodTradePosition { TradeId = O.TradeId, Pv = O.Pv, Margin = O.Margin }).ToDictionary(K => K.TradeId, V => V);
|
|
eRiskInfos = etr.Where(O => tIdArr.Contains(O.TradeId)).Select(func).AsEnumerable().GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.First());
|
|
|
|
|
|
|
|
foreach (var item in retListResult.rows)
|
|
{
|
|
if (item.TradeType == "远期" || item.TradeType == "收益互换")
|
|
{
|
|
item.ValuationMethod = "M";
|
|
}
|
|
//交易确认书
|
|
tcRinfos.TryGetValue(item.ParentTradeId > 0 ? item.ParentTradeId.Value : item.TradeId, out var tcValue);
|
|
if (string.IsNullOrEmpty(tcValue))
|
|
{
|
|
tcRinfos.TryGetValue(item.TradeId, out var tcValue2);
|
|
tcValue = tcValue2;
|
|
}
|
|
item.ContractCode = tcValue ?? null;
|
|
|
|
ptInfos.TryGetValue(item.ParentTradeId ?? 0, out var parentTrade);
|
|
switch (PS.Config.Company)
|
|
{
|
|
case Configuration.CompanyEnum.长江:
|
|
tcRInfos.TryGetValue(item.ParentTradeId ?? 0, out var pTcR);
|
|
tcRInfos.TryGetValue(item.TradeId, out var tcR);
|
|
tmInfos.TryGetValue(item.TradeId, out var tmValue);
|
|
tmInfos.TryGetValue(item.ParentTradeId ?? 0, out var ptmValue);
|
|
item.PositionCode = pTcR ?? tcR ?? ptmValue ?? tmValue ?? "";
|
|
break;
|
|
case Configuration.CompanyEnum.浙期:
|
|
tmInfos.TryGetValue(item.TradeId, out tmValue);
|
|
tmInfos.TryGetValue(item.ParentTradeId ?? 0, out ptmValue);
|
|
item.PositionCode = ptmValue ?? tmValue ?? parentTrade?.TradeNumber ?? item.OriginalTradeNumber;
|
|
item.OriginalTradeNumber = tmValue ?? item.OriginalTradeNumber;
|
|
var actualExerciseDate = DbContext.TradeMeta.Where(a => a.TradeId == item.TradeId && a.MetaKey == "ActualExerciseDate").FirstOrDefault()?.MetaValue;
|
|
if (!string.IsNullOrEmpty(actualExerciseDate) && DateTime.TryParse(actualExerciseDate, out DateTime newActualExerciseDate))
|
|
{
|
|
item.trade.ExerciseDate = newActualExerciseDate;
|
|
item.EndDate = item.trade.ExerciseDate;
|
|
}
|
|
break;
|
|
case Configuration.CompanyEnum.物产中大:
|
|
tmInfos.TryGetValue(item.TradeId, out tmValue);
|
|
tmInfos.TryGetValue(item.ParentTradeId ?? 0, out ptmValue);
|
|
item.PositionCode = ptmValue ?? tmValue;
|
|
item.TradeNumber = item.trade.TradeNumber;
|
|
item.ContractCode = DbContext.trade_contract_r_number.Where(n => n.TradeId == item.trade.id && n.TradeConfirmNumberType == "C").FirstOrDefault()?.ShowTradeConfirmNumber;
|
|
break;
|
|
case Configuration.CompanyEnum.上期资本:
|
|
trade_contract_r tCR = null;
|
|
//交易确认书编号
|
|
tCR = tradeContractRInfo.FirstOrDefault(n => n.TradeId == item.TradeId && n.Type == "交易确认书");
|
|
if (tCR != null)
|
|
{
|
|
item.ContractCode = tCR.ContractCode;
|
|
item.PositionCode = tCR.ContractCode;
|
|
}
|
|
else
|
|
{
|
|
item.ContractCode = null;
|
|
item.PositionCode = null;
|
|
}
|
|
break;
|
|
case Configuration.CompanyEnum.兴证:
|
|
item.PositionCode = item.trade.TradeNumber;
|
|
break;
|
|
default:
|
|
var defautPositionCode = parentTrade?.TradeNumber ?? item.OriginalTradeNumber;
|
|
if (defautPositionCode != null)
|
|
{
|
|
item.PositionCode = defautPositionCode;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//一年有效天数
|
|
item.ValidDays = formartValidDays(item.trade);
|
|
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode);
|
|
var variety = DataCacheProvider.GetVarietyDataSource().GetData(um.UnderlyingTypeId);
|
|
|
|
ePnlInfos.TryGetValue(item.TradeId, out var positionInfo);
|
|
var price = positionInfo?.UnderlyingPrice ?? _priceProvider.GetPrice(item.UnderlyingCode);
|
|
|
|
//合约估值时的价格
|
|
item.ContractValuationPrice = price.ToString();
|
|
|
|
exChangeRate.TryGetValue(item.TradeId, out var ecRate);
|
|
if (!string.IsNullOrEmpty(variety.QuoteCurrency) && variety.QuoteCurrency != "CNY")
|
|
{
|
|
if (!string.IsNullOrEmpty(ecRate))
|
|
{
|
|
item.ForeignCurrencyRate = double.Parse(ecRate);
|
|
}
|
|
|
|
item.QuoteCurrency = variety.QuoteCurrency;
|
|
|
|
if (item.QuoteCurrency != null && (item.QuoteCurrency.ToLower() == "usc" || item.QuoteCurrency.ToLower() == "usd(cent)"))
|
|
{
|
|
if (item.ForeignCurrencyRate != null)
|
|
item.ForeignCurrencyRate = item.ForeignCurrencyRate;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
item.QuoteCurrency = "CNY";
|
|
}
|
|
|
|
FormatModel(item, assetTypeList, varietySuffixList, varietyCodeList, eRiskInfos, out _);
|
|
var protocalTyp = "协议签署版本";
|
|
var protocalTypeList = (from i in basedb.DictionaryItems join d in basedb.Dictionaries on i.DictId equals d.Id where d.Name == protocalTyp select i).ToDictionary(K => K.Name, V => V.ShortName);
|
|
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(item.ClientId);
|
|
|
|
|
|
if (client != null)
|
|
{
|
|
//item.ClientName = clientReportInfo.TryGetValue(client.id, out var reportName) && !string.IsNullOrWhiteSpace(reportName) ? reportName : client.Name;
|
|
while (client.IsDocShowParentName == 1 && client.ParentId > 0)
|
|
{
|
|
client = DataCacheProvider.GetClientDataSource().GetData(client.ParentId) ?? throw new ServiceException($"{client.Name} 的所属机构不存在,请维护后生成!");
|
|
}
|
|
item.ClientName = clientReportInfo.TryGetValue(client.id, out var reportName) && !string.IsNullOrWhiteSpace(reportName) ? reportName : client.Name;
|
|
item.ClientLicenseCode = client.LicenseCode;
|
|
item.ProtocalType = (!string.IsNullOrWhiteSpace(client.ProtocolSignVersion) && protocalTypeList.TryGetValue(client.ProtocolSignVersion, out var value) ? value : "9");
|
|
item.ProtocolSignDate = item.VarietyType == "EQ" ? client.RightProtocolSignDate : client.ProtocolSignDate;
|
|
//获取交易对手方LEI
|
|
item.ClientLEI = client.LEICode;
|
|
}
|
|
|
|
//中央对手方清算
|
|
iccInfo.TryGetValue(item.TradeId, out var icc);
|
|
item.IsCentralClearingPlatform = icc ?? "N";
|
|
|
|
//是否中央对方清算“字段不是”Y“时,中央清算平台才赋值
|
|
if (item.IsCentralClearingPlatform == "Y")
|
|
{
|
|
ccpInfo.TryGetValue(item.TradeId, out var ccp);
|
|
item.CentralClearingPlatform = ccp ?? null;
|
|
}
|
|
|
|
//交易平台
|
|
tpInfo.TryGetValue(item.TradeId, out var tp);
|
|
item.TradePlatform = tp ?? null;
|
|
|
|
if (item.trade.IsGroup != 1)
|
|
{
|
|
//合约价值
|
|
item.ContractPrice = (double)(positionInfo?.Pv ?? 0);
|
|
}
|
|
|
|
//累计期权并且 SettlementMode 是实物交割时赋值P
|
|
if (item.TradeType == "累计期权" && item.trade.trade_accumulator_option.SettlementMode == "实物交割")
|
|
{
|
|
if (PS.Config.Company != Configuration.CompanyEnum.浙期)
|
|
item.SettlementMethod = "P";
|
|
}
|
|
|
|
var IsUSC = false;
|
|
//非黑箱交易时处理
|
|
if (string.IsNullOrEmpty(item.trade.ExtendInfo) || item.trade.TradeType == "自定义交易")
|
|
{
|
|
|
|
if (item.trade.TradeType != "远期" && item.trade.TradeType != "掉期")
|
|
{
|
|
//雪球、凤凰
|
|
if (item.OptionProductStructure == "SA" || item.OptionProductStructure == "GSA" || item.OptionProductStructure == "PA")
|
|
{
|
|
if (item.ObserveType == "DISCRETE")
|
|
{
|
|
//雪球、凤凰 观察频率
|
|
koObservationRate.TryGetValue(item.TradeId, out var observationRate);
|
|
formatObservationRate(item, observationRate);
|
|
}
|
|
|
|
#region 雪球凤凰 敲入观察判断是否到期观察
|
|
var isTerminal = false;
|
|
var observeStartDates = "";
|
|
if (item.OptionProductStructure == "PA")
|
|
{
|
|
observeStartDates = item.trade.trade_autocall?.ObservationDates;
|
|
}
|
|
else
|
|
{
|
|
observeStartDates = item.trade.trade_snowball?.ObservationDates;
|
|
}
|
|
if (!string.IsNullOrEmpty(observeStartDates))
|
|
{
|
|
var odArrs = observeStartDates.Split(';');
|
|
if (odArrs.Length > 0)
|
|
{
|
|
DateTime.TryParse(odArrs[0], out DateTime koOD);
|
|
if (koOD == item.EndDate.Value)
|
|
{
|
|
isTerminal = true;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
if (!isTerminal)
|
|
{
|
|
//雪球、凤凰敲入观察频率
|
|
kiObservatonRate.TryGetValue(item.TradeId, out var kiOR);
|
|
formatKiObservationRate(item, kiOR);
|
|
}
|
|
}
|
|
//累计期权
|
|
else if (item.OptionProductStructure == "AC")
|
|
{
|
|
if (item.ObserveType == "DISCRETE")
|
|
{
|
|
koObservationRate.TryGetValue(item.TradeId, out var observationRate);
|
|
formatObservationRate(item, observationRate);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//其他产品观察频率观察频率
|
|
if (item.ObserveType == "DISCRETE")
|
|
{
|
|
kiObservatonRate.TryGetValue(item.TradeId, out var observationRate);
|
|
formatObservationRate(item, observationRate);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (item.ToolType == "SW")
|
|
{
|
|
getObservatonRate.TryGetValue(item.TradeId, out var getOR);
|
|
payObservatonRate.TryGetValue(item.TradeId, out var payOR);
|
|
formatSWObservationRate(item, getOR, payOR);
|
|
item.OptionProductStructure = null;
|
|
|
|
if (item.trade.trade_swap != null)
|
|
{
|
|
item.ValidDays = item.trade.trade_swap.AnnualDays;
|
|
}
|
|
|
|
|
|
//当是互换、掉期时,计价单位是外币时,期初货币单位、执行价格货币单位需显示外币
|
|
if (item.QuoteCurrency != "CNY")
|
|
{
|
|
if (item.UnderlyingInitialPriceSymbol == "3")
|
|
{
|
|
if (item.QuoteCurrency != null && (item.QuoteCurrency.ToLower() == "usc" || item.QuoteCurrency.ToLower() == "usd(cent)"))
|
|
{
|
|
IsUSC = true;
|
|
}
|
|
}
|
|
if (item.UnderlyingInitialPriceSymbol == "1")
|
|
{
|
|
if (item.QuoteCurrency != null && (item.QuoteCurrency.ToLower() == "usc" || item.QuoteCurrency.ToLower() == "usd(cent)"))
|
|
{
|
|
IsUSC = true;
|
|
item.QuoteCurrency = "USD";
|
|
}
|
|
item.UnderlyingInitialPriceCurrency = item.UnderlyingInitialPriceCurrency.Replace("CNY", item.QuoteCurrency);
|
|
}
|
|
}
|
|
// 如遇货币单位为美分,如USD(cent)或USc,且价格符号为1或3时,以下涉及报送的字段需除以100
|
|
if (IsUSC)
|
|
{
|
|
item.UnderlyingInitialPrice = (Convert.ToDecimal(item.UnderlyingInitialPrice) / 100).ToString();
|
|
item.ClosedUnderlyingPrice = string.IsNullOrWhiteSpace(item.ClosedUnderlyingPrice) ? item.ClosedUnderlyingPrice : (Convert.ToDecimal(item.ClosedUnderlyingPrice) / 100).ToString();
|
|
item.ContractValuationPrice = string.IsNullOrWhiteSpace(item.ContractValuationPrice) ? item.ContractValuationPrice : (Convert.ToDecimal(item.ContractValuationPrice) / 100).ToString();
|
|
}
|
|
item.StrikeSymbol = null;
|
|
item.StrikeCurrency = null;
|
|
item.Strike = null;
|
|
|
|
item.GuaranteedIncome = null;
|
|
item.GuaranteedIncomeCurrency = null;
|
|
item.GuaranteedIncomeSymbol = null;
|
|
|
|
}
|
|
else if (item.QuoteCurrency != "CNY")
|
|
{
|
|
if (item.QuoteCurrency != null && (item.QuoteCurrency.ToLower() == "usc" || item.QuoteCurrency.ToLower() == "usd(cent)"))
|
|
{
|
|
IsUSC = true;
|
|
item.QuoteCurrency = "USD";
|
|
}
|
|
|
|
item.UnderlyingInitialPriceCurrency = string.IsNullOrEmpty(item.UnderlyingInitialPriceCurrency) ? null : item.UnderlyingInitialPriceCurrency.Replace("CNY", item.QuoteCurrency);
|
|
item.StrikeCurrency = string.IsNullOrEmpty(item.StrikeCurrency) ? null : item.StrikeCurrency.Replace("CNY", item.QuoteCurrency);
|
|
item.GuaranteedIncomeCurrency = string.IsNullOrEmpty(item.GuaranteedIncomeCurrency) ? null : item.GuaranteedIncomeCurrency.Replace("CNY", item.QuoteCurrency);
|
|
item.ExerciseBenefitsCurrency = string.IsNullOrEmpty(item.ExerciseBenefitsCurrency) ? null : item.ExerciseBenefitsCurrency.Replace("CNY", item.QuoteCurrency);
|
|
item.CompensationIncomeCurrency = string.IsNullOrEmpty(item.CompensationIncomeCurrency) ? null : item.CompensationIncomeCurrency.Replace("CNY", item.QuoteCurrency);
|
|
item.ForwardPriceCurrency = string.IsNullOrEmpty(item.ForwardPriceCurrency) ? null : item.ForwardPriceCurrency.Replace("CNY", item.QuoteCurrency);
|
|
}
|
|
|
|
if (item.ToolType == "FW" || item.ToolType == "SW")
|
|
{
|
|
item.OptionProductStructure = null;
|
|
}
|
|
|
|
if (item.UnderlyingInitialPriceSymbol == "3")
|
|
{
|
|
item.UnderlyingInitialPriceCurrency = null;
|
|
if (item.StrikeSymbol == "1")
|
|
{
|
|
item.StrikeSymbol = "3";
|
|
item.StrikeCurrency = null;
|
|
}
|
|
if (item.ForwardPriceSymbol == "1")
|
|
{
|
|
item.ForwardPriceSymbol = "3";
|
|
item.ForwardPriceCurrency = null;
|
|
}
|
|
}
|
|
// 如遇货币单位为美分,如USD(cent)或USc,且价格符号为1或3时,以下涉及报送的字段需除以100 标的期初价格、平仓或终止时的标的价格、执行价格1、执行价格2、执行价格3、障碍价1、障碍价2、远期价格
|
|
if (IsUSC && (item.UnderlyingInitialPriceSymbol == "1" || item.UnderlyingInitialPriceSymbol == "3"))
|
|
{
|
|
item.UnderlyingInitialPrice = (Convert.ToDecimal(item.UnderlyingInitialPrice) / 100).ToString();
|
|
item.ClosedUnderlyingPrice = string.IsNullOrWhiteSpace(item.ClosedUnderlyingPrice) ? item.ClosedUnderlyingPrice : (Convert.ToDecimal(item.ClosedUnderlyingPrice) / 100).ToString();
|
|
item.ContractValuationPrice = string.IsNullOrWhiteSpace(item.ContractValuationPrice) ? item.ContractValuationPrice : (Convert.ToDecimal(item.ContractValuationPrice) / 100).ToString();
|
|
}
|
|
if (IsUSC && (item.StrikeSymbol == "1" || item.StrikeSymbol == "3"))
|
|
{
|
|
item.Strike /= 100;
|
|
item.Strike2 /= 100;
|
|
item.Strike3 /= 100;
|
|
item.BarriersPrice /= 100;
|
|
item.BarriersPrice2 /= 100;
|
|
}
|
|
if (IsUSC && (item.ForwardPriceSymbol == "1" || item.ForwardPriceSymbol == "3"))
|
|
{
|
|
item.ForwardPrice /= 100;
|
|
}
|
|
|
|
|
|
//雪球初始敲入时,”敲入障碍价“、”敲入观察期“字段为空
|
|
if (item.OptionProductStructure == "SA" || item.OptionProductStructure == "GSA")
|
|
{
|
|
|
|
if (item.trade.trade_snowball != null && item.trade.trade_snowball.IsInitialKnockedIn)
|
|
{
|
|
item.KnockInBarrierPrice = null;
|
|
item.KnockInObservationPeriod = null;
|
|
}
|
|
}
|
|
|
|
if (item.trade.TradeType == "自定义交易")
|
|
{
|
|
if (!string.IsNullOrEmpty(item.ValidDaysStr))
|
|
{
|
|
item.ValidDays = int.TryParse(item.ValidDaysStr, out int vDays) ? vDays : item.ValidDays;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//当是黑箱时,计价单位是外币时,期初货币单位、执行价格货币单位需显示外币
|
|
if (item.QuoteCurrency != "CNY")
|
|
{
|
|
if (item.UnderlyingInitialPriceSymbol == "3")
|
|
{
|
|
if (item.QuoteCurrency != null && (item.QuoteCurrency.ToLower() == "usc" || item.QuoteCurrency.ToLower() == "usd(cent)"))
|
|
{
|
|
IsUSC = true;
|
|
}
|
|
}
|
|
if (item.UnderlyingInitialPriceSymbol == "1")
|
|
{
|
|
if (item.QuoteCurrency != null && (item.QuoteCurrency.ToLower() == "usc" || item.QuoteCurrency.ToLower() == "usd(cent)"))
|
|
{
|
|
IsUSC = true;
|
|
item.QuoteCurrency = "USD";
|
|
}
|
|
item.UnderlyingInitialPriceCurrency = item.UnderlyingInitialPriceCurrency.Replace("CNY", item.QuoteCurrency);
|
|
}
|
|
}
|
|
// 如遇货币单位为美分,如USD(cent)或USc,且价格符号为1或3时,以下涉及报送的字段需除以100 标的期初价格、平仓或终止时的标的价格、执行价格1、执行价格2、执行价格3、障碍价1、障碍价2、远期价格
|
|
if (IsUSC)
|
|
{
|
|
item.UnderlyingInitialPrice = (Convert.ToDecimal(item.UnderlyingInitialPrice) / 100).ToString();
|
|
item.ClosedUnderlyingPrice = string.IsNullOrWhiteSpace(item.ClosedUnderlyingPrice) ? item.ClosedUnderlyingPrice : (Convert.ToDecimal(item.ClosedUnderlyingPrice) / 100).ToString();
|
|
item.ContractValuationPrice = string.IsNullOrWhiteSpace(item.ContractValuationPrice) ? item.ContractValuationPrice : (Convert.ToDecimal(item.ContractValuationPrice) / 100).ToString();
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(item.ValidDaysStr))
|
|
{
|
|
item.ValidDays = int.TryParse(item.ValidDaysStr, out int vDays) ? vDays : item.ValidDays;
|
|
}
|
|
}
|
|
|
|
if (!item.IsStock)
|
|
{
|
|
item.Dividend = null;
|
|
}
|
|
|
|
//成交数量
|
|
var tradeNum = item.trade.OriginalNotional;
|
|
if (item.GuaranteedIncomeSymbol == "1")
|
|
{
|
|
if (item.GuaranteedIncome != null)
|
|
{
|
|
item.GuaranteedIncome /= tradeNum;
|
|
}
|
|
}
|
|
//行权收益
|
|
if (item.ExerciseBenefitsSymbol == "1")
|
|
{
|
|
if (item.ExerciseBenefits != null)
|
|
{
|
|
item.ExerciseBenefits /= tradeNum;
|
|
}
|
|
|
|
if (item.ExerciseBenefits2 != null)
|
|
{
|
|
item.ExerciseBenefits2 /= tradeNum;
|
|
}
|
|
|
|
if (item.ExerciseBenefits3 != null)
|
|
{
|
|
item.ExerciseBenefits3 /= tradeNum;
|
|
}
|
|
}
|
|
//补偿收益
|
|
if (item.CompensationIncomeSymbol == "1")
|
|
{
|
|
if (item.CompensationIncome != null)
|
|
{
|
|
item.CompensationIncome /= tradeNum;
|
|
}
|
|
|
|
if (item.CompensationIncome2 != null)
|
|
{
|
|
item.CompensationIncome2 /= tradeNum;
|
|
}
|
|
}
|
|
//固定收益
|
|
if (item.FixedIncomeSymbol == "1")
|
|
{
|
|
if (item.FixedIncome != null)
|
|
{
|
|
item.FixedIncome /= tradeNum;
|
|
}
|
|
}
|
|
|
|
|
|
if (PS.Config.Is招证)
|
|
{
|
|
if (item.GuaranteedIncome == 0)
|
|
{
|
|
item.GuaranteedIncome = null;
|
|
item.GuaranteedIncomeCurrency = null;
|
|
item.GuaranteedIncomeSymbol = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (ServiceException ex)
|
|
{
|
|
LogFactory.GetLogger("NewSuperviseReportPositionService").Error(ex, "已知错误");
|
|
throw;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("NewSuperviseReportPositionService").Error(ex, "未知错误");
|
|
throw;
|
|
}
|
|
}
|
|
return retListResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 一年有效天数,按系统参数中的定价参数(年交易天数合计)来获取
|
|
/// </summary>
|
|
/// <param name="t"></param>
|
|
/// <returns></returns>
|
|
private int formartValidDays(trade t)
|
|
{
|
|
var vDays = 365;
|
|
|
|
//中粮
|
|
if (PS.Config.Company == Configuration.CompanyEnum.中粮)
|
|
{
|
|
bool isYear = false;
|
|
//雪球 凤凰 二元(美式)障碍(敲出类型的) 收益增强 累计期权(上端收益类型:固定)
|
|
switch (t.TradeType)
|
|
{
|
|
case "雪球期权":
|
|
if (t.trade_snowball != null && !t.trade_snowball.IsFixedCoupon)
|
|
{
|
|
isYear = true;
|
|
}
|
|
break;
|
|
case "凤凰期权":
|
|
if (t.trade_autocall != null && !t.trade_autocall.IsFixedCoupon)
|
|
{
|
|
isYear = true;
|
|
}
|
|
break;
|
|
case "二元期权":
|
|
if (t.ExerciseMode == "American" && t.trade_binary_option != null && t.trade_binary_option.RebateAnnualizedAtKO)
|
|
{
|
|
isYear = true;
|
|
}
|
|
break;
|
|
case "障碍期权":
|
|
if (t.trade_barrier_option != null && t.trade_barrier_option.RebateAnnualizedAtKO)
|
|
{
|
|
isYear = true;
|
|
}
|
|
|
|
break;
|
|
case "收益增强结构": isYear = true; break;
|
|
case "累计期权":
|
|
if (t.trade_accumulator_option != null && t.trade_accumulator_option.PayoffType == "固定" && !t.trade_accumulator_option.IsFixedCoupon)
|
|
{
|
|
isYear = true;
|
|
}
|
|
break;
|
|
}
|
|
if (isYear)
|
|
{
|
|
return vDays;
|
|
}
|
|
}
|
|
var positionReportTradeDayCountStr = valuedateBLL.SystemDate.PositionReportTradeDayCount;
|
|
switch (positionReportTradeDayCountStr)
|
|
{
|
|
case "Act365": vDays = 365; break;
|
|
case "Bus244": vDays = 244; break;
|
|
case "Bus245": vDays = 245; break;
|
|
case "ActAct":
|
|
if (DateTime.IsLeapYear(t.TradeDate.Value.Year))
|
|
{
|
|
vDays = 366;
|
|
}
|
|
else
|
|
{
|
|
vDays = 365;
|
|
}
|
|
break;
|
|
case "BusBus":
|
|
var year = t?.TradeDate?.Year;
|
|
var calendar = DbContext.calendar.FirstOrDefault(n => n.Year == year && n.ValidState != "InValid");
|
|
vDays = calendar.GetWorkingDays();
|
|
break;
|
|
case "Bus243": vDays = 243; break;
|
|
case "Bus252": vDays = 252; break;
|
|
}
|
|
return vDays;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 持仓报告 设置risk表字段
|
|
/// </summary>
|
|
/// <param name="eRisk"></param>
|
|
/// <param name="model"></param>
|
|
private void formartERisk(Dictionary<int, EodTradeRisk> eRiskInfos, NewSuperviseReportPositionModel model)
|
|
{
|
|
var trade = model.trade;
|
|
var ignoreTradeTypes = new List<string>()
|
|
{
|
|
"远期",
|
|
"收益互换",
|
|
"掉期",
|
|
};
|
|
eRiskInfos.TryGetValue(model.TradeId, out var eRisk);
|
|
if (model.IsGroup == 1)
|
|
{
|
|
var childIds = DbContext.trade.Where(x => x.ParentTradeId == model.TradeId).Select(x => x.id);
|
|
var riskChilds = DbContext.eod_trade_risk.Where(x => childIds.Contains(x.TradeId) && x.ValueDate == _req.ValueDate).ToList();
|
|
model.ContractPrice = riskChilds.Sum(x => x.Pv);
|
|
model.Delta = riskChilds.Sum(x => x.Delta).OtcFormat(OtcFormatFlag.greek);
|
|
model.Vega = riskChilds.Sum(x => x.Vega).OtcFormat(OtcFormatFlag.greek);
|
|
model.Theta = riskChilds.Sum(x => x.Theta).OtcFormat(OtcFormatFlag.greek);
|
|
model.Rho = (riskChilds.Sum(x => x.Rho) * 100).OtcFormat(OtcFormatFlag.greek);
|
|
model.Gamma = riskChilds.Sum(x => x.Gamma).OtcFormat(OtcFormatFlag.greek);
|
|
model.DeltaCash = riskChilds.Sum(x => x.DeltaCash).OtcFormat(OtcFormatFlag.tradePrice);
|
|
//model.GammaCash = riskChilds.Sum(x => x.GammaCash).OtcFormat(OtcFormatFlag.tradePrice);
|
|
formatGammaCash(model);
|
|
//估值波动率
|
|
model.ValuationVolatility = eRisk == null ? null : eRisk.Vol > 0 ? eRisk.Vol.OtcFormat(OtcFormatFlag.greek) : null;
|
|
if (!string.IsNullOrEmpty(model.trade.ExtendInfo))
|
|
{
|
|
var tempVolat = 0D;
|
|
var isVolat = false;
|
|
foreach (var rItem in riskChilds)
|
|
{
|
|
if (rItem.Vol == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (tempVolat == 0)
|
|
{
|
|
tempVolat = rItem.Vol;
|
|
}
|
|
|
|
if (tempVolat == rItem.Vol)
|
|
{
|
|
isVolat = true;
|
|
}
|
|
else
|
|
{
|
|
isVolat = false;
|
|
}
|
|
tempVolat = rItem.Vol;
|
|
}
|
|
if (isVolat)
|
|
{
|
|
model.ValuationVolatility = tempVolat == 0 ? null : tempVolat.OtcFormat(OtcFormatFlag.greek);
|
|
}
|
|
//model.ValuationVolatility = riskChilds.Count > 0 && riskChilds[0].Vol > 0 ? riskChilds[0].Vol.OtcFormat(OtcFormatFlag.greek) : null;
|
|
}
|
|
}
|
|
else if (!ignoreTradeTypes.Contains(model.TradeType))
|
|
{
|
|
model.Delta = ((double)(eRisk?.Delta ?? 0)).OtcFormat(OtcFormatFlag.greek);
|
|
model.Vega = (eRisk?.Vega ?? 0).OtcFormat(OtcFormatFlag.greek);
|
|
model.Theta = (eRisk?.Theta ?? 0).OtcFormat(OtcFormatFlag.greek);
|
|
model.Rho = ((eRisk?.Rho ?? 0) * 100).OtcFormat(OtcFormatFlag.greek);
|
|
model.DeltaCash = (eRisk?.DeltaCash ?? 0).OtcFormat(OtcFormatFlag.tradePrice);
|
|
//model.GammaCash = (eRisk?.GammaCash ?? 0).OtcFormat(OtcFormatFlag.tradePrice);
|
|
var otherRisks = JsonHelper.Parse<OtherRisks>(eRisk?.OtherRisks);
|
|
if (otherRisks == null || string.IsNullOrWhiteSpace(otherRisks.CrossGamma))
|
|
{
|
|
model.Gamma = (eRisk?.Gamma ?? 0).OtcFormat(OtcFormatFlag.greek);
|
|
}
|
|
else
|
|
{
|
|
model.Gamma = otherRisks.CrossGamma.Replace(",", ";");
|
|
}
|
|
formatGammaCash(model);
|
|
//估值波动率
|
|
model.ValuationVolatility = eRisk == null ? null : eRisk.Vol > 0 ? eRisk.Vol.OtcFormat(OtcFormatFlag.greek) : null;
|
|
}
|
|
else
|
|
{
|
|
model.Delta = ((double)(eRisk?.Delta ?? 0)).OtcFormat(OtcFormatFlag.greek);
|
|
model.DeltaCash = (eRisk?.DeltaCash ?? 0).OtcFormat(OtcFormatFlag.tradePrice);
|
|
//model.GammaCash = (eRisk?.GammaCash ?? 0).OtcFormat(OtcFormatFlag.tradePrice);
|
|
formatGammaCash(model);
|
|
if (PS.Config.Company == Configuration.CompanyEnum.浙期 && !string.IsNullOrWhiteSpace(trade.BasisUnderlyingCode))
|
|
{
|
|
|
|
model.Delta += ";" + model.Delta;
|
|
model.DeltaCash += ";" + model.DeltaCash;
|
|
model.GammaCash = "0";
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算gammacash
|
|
/// </summary>
|
|
/// <param name="model"></param>
|
|
public void formatGammaCash(NewSuperviseReportPositionModel model)
|
|
{
|
|
double curRate = 1;
|
|
var cvPrices = model.ContractValuationPrice.Split(';');
|
|
double.TryParse(model.Gamma, out double gammaTemp);
|
|
var gammacashStr = "";
|
|
if (model.QuoteCurrency.ToUpper() != "CNY")
|
|
{
|
|
var eodCurrencyRate = DbContext.eod_currency_rate.FirstOrDefault(n => n.ValueDate == _req.ValueDate && n.LocalCurrency == "CNY" && (n.ForeignCurrency == model.QuoteCurrency.ToUpper() || n.ForeignCurrency == model.QuoteCurrency.ToLower()));
|
|
if (eodCurrencyRate != null)
|
|
{
|
|
curRate = eodCurrencyRate.Rate;
|
|
}
|
|
}
|
|
for (int i = 0; i < cvPrices.Length; i++)
|
|
{
|
|
double.TryParse(cvPrices[i], out double cvPrice);
|
|
if (i == (cvPrices.Length - 1))
|
|
{
|
|
gammacashStr += (gammaTemp * cvPrice * curRate).OtcFormat(OtcFormatFlag.tradePrice);
|
|
}
|
|
else
|
|
{
|
|
gammacashStr += (gammaTemp * cvPrice * curRate).OtcFormat(OtcFormatFlag.tradePrice) + ";";
|
|
}
|
|
}
|
|
|
|
model.GammaCash = gammacashStr;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 持仓报告 设置特定字段
|
|
/// </summary>
|
|
/// <param name="model"></param>
|
|
private void formatOptionlFields(NewSuperviseReportPositionModel model)
|
|
{
|
|
var t = model.trade;
|
|
switch (model.OptionProductStructure)
|
|
{
|
|
case "SKI":
|
|
if (t.trade_barrier_option != null)
|
|
{
|
|
if (t.trade_barrier_option != null && !string.IsNullOrEmpty(t.trade_barrier_option.BarrierType)
|
|
&& model.trade.trade_barrier_option.BarrierType.EndsWith("敲入"))
|
|
{
|
|
if (!string.IsNullOrEmpty(t.trade_barrier_option.KnockInOutStatus) && t.trade_barrier_option.KnockInOutStatus.ToLower().Contains("in"))
|
|
{
|
|
model.KnockIn = "Y";
|
|
}
|
|
else
|
|
{
|
|
model.KnockIn = "N";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
model.KnockIn = "N";
|
|
}
|
|
}
|
|
break;
|
|
case "SA":
|
|
case "GSA":
|
|
if (t.trade_snowball != null)
|
|
{
|
|
//初始敲入时,没敲入价也填
|
|
if (t.trade_snowball.IsInitialKnockedIn)
|
|
{
|
|
model.KnockIn = "Y";
|
|
}
|
|
else if (!string.IsNullOrEmpty(t.trade_snowball.KnockInOutStatus) && (t.trade_snowball.KnockInOutStatusCn.Contains("敲入")
|
|
|| t.trade_snowball.KnockInOutStatus.ToLower().Contains("in")))
|
|
{
|
|
model.KnockIn = "Y";
|
|
}
|
|
else
|
|
{
|
|
model.KnockIn = "N";
|
|
}
|
|
}
|
|
break;
|
|
case "PA":
|
|
if (t.trade_autocall != null)
|
|
{
|
|
if (!string.IsNullOrEmpty(t.trade_autocall.KnockInOutStatus) && (t.trade_autocall.KnockInOutStatusCn.Contains("敲入") || t.trade_autocall.KnockInOutStatus.ToLower().Contains("in")))
|
|
{
|
|
model.KnockIn = "Y";
|
|
}
|
|
else
|
|
{
|
|
model.KnockIn = "N";
|
|
}
|
|
}
|
|
break;
|
|
case "AS":
|
|
var QdpTrade = TradeCalcHelper.GetQdpTrade(t, _req.ValueDate);
|
|
if (QdpTrade != null && QdpTrade.Instrument != null && QdpTrade.Instrument is IOption opt)
|
|
{
|
|
var asianOpt = opt as AsianOption;
|
|
try
|
|
{
|
|
model.ObserveAverage = t.trade_asian_option != null && t.trade_asian_option.StrikeType == "Floating" ? asianOpt.ActualStrike : asianOpt.FinalPrice();
|
|
}
|
|
catch
|
|
{
|
|
model.ObserveAverage = _priceProvider.GetPrice(model.trade.UnderlyingCode);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 观察频率
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <param name="koOR"></param>
|
|
private void formatObservationRate(NewSuperviseReportPositionModel item, string observationRate = "")
|
|
{
|
|
string num = "", unit = "", unitStr = "";
|
|
string[] orArray;
|
|
if (!string.IsNullOrEmpty(observationRate))
|
|
{
|
|
orArray = observationRate.Split('|');
|
|
if (orArray.Length == 2)
|
|
{
|
|
|
|
if (orArray[1] == "OTHER")
|
|
{
|
|
item.ObservationPeriod = orArray[1];
|
|
}
|
|
else
|
|
{
|
|
num = orArray[1].Replace("DAIL", "").Replace("WEEK", "").Replace("MNTH", "").Replace("YEAR", "");
|
|
unitStr = orArray[1].Replace(num, "");
|
|
|
|
item.ObservationPeriod = unitStr;
|
|
item.ObservePeriodMultiplier = double.TryParse(num, out var temp) ? temp : double.NaN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
num = observationRate.Substring(0, observationRate.Length - 1);
|
|
unit = observationRate.Substring(observationRate.Length - 1);
|
|
unitStr = getUnitStr(unit);
|
|
|
|
item.ObservationPeriod = unitStr;
|
|
item.ObservePeriodMultiplier = double.TryParse(num, out var temp) ? temp : double.NaN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((item.OptionProductStructure != "SA" && item.OptionProductStructure != "GSA" && item.OptionProductStructure != "PA"))
|
|
{
|
|
if (item.ObserveType == "DISCRETE")
|
|
{
|
|
num = "1";
|
|
unit = "D";
|
|
unitStr = getUnitStr(unit);
|
|
|
|
item.ObservationPeriod = unitStr;
|
|
item.ObservePeriodMultiplier = double.Parse(num);
|
|
}
|
|
else if (item.trade.TradeType == "自定义交易")
|
|
{
|
|
item.ObservationPeriod = "OTHER";
|
|
}
|
|
}
|
|
else if (item.OptionProductStructure == "SA" || item.OptionProductStructure == "GSA" || item.OptionProductStructure == "PA")
|
|
{
|
|
num = "1";
|
|
unit = "M";
|
|
unitStr = getUnitStr(unit);
|
|
|
|
item.ObservationPeriod = unitStr;
|
|
item.ObservePeriodMultiplier = double.Parse(num);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 雪球 凤凰敲入观察频率
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <param name="kiOR"></param>
|
|
private void formatKiObservationRate(NewSuperviseReportPositionModel item, string kiOR = "")
|
|
{
|
|
string num = "", unit = "", unitStr = "";
|
|
string[] kiORArray;
|
|
//敲入观察频率
|
|
if (!string.IsNullOrEmpty(kiOR))
|
|
{
|
|
kiORArray = kiOR.Split('|');
|
|
if (kiORArray.Length == 2)
|
|
{
|
|
num = kiORArray[1].Replace("DAIL", "").Replace("WEEK", "").Replace("MNTH", "").Replace("YEAR", "");
|
|
unitStr = kiORArray[1].Replace(num, "");
|
|
|
|
item.KnockInObservationPeriod = unitStr;
|
|
}
|
|
else
|
|
{
|
|
num = kiOR.Substring(0, kiOR.Length - 1);
|
|
unit = kiOR.Substring(kiOR.Length - 1);
|
|
unitStr = getUnitStr(unit);
|
|
|
|
item.KnockInObservationPeriod = unitStr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
num = "1";
|
|
unit = "D";
|
|
unitStr = getUnitStr(unit);
|
|
if (item.OptionProductStructure == "GSA")
|
|
{
|
|
unitStr = "";
|
|
}
|
|
item.KnockInObservationPeriod = unitStr;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 互换产品观察频率
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <param name="kiOR"></param>
|
|
/// <param name="koOR"></param>
|
|
private void formatSWObservationRate(NewSuperviseReportPositionModel item, string getOR = "", string payOR = "")
|
|
{
|
|
string num = "", unit = "", unitStr = "";
|
|
string[] getORArray;
|
|
string[] payORArray;
|
|
if (!string.IsNullOrEmpty(getOR) && getOR != "TERM")
|
|
{
|
|
getORArray = getOR.Split('|');
|
|
if (getORArray.Length == 2)
|
|
{
|
|
if (getORArray[1] == "OTHER" || getORArray[1] == "TERM")
|
|
{
|
|
unitStr = getORArray[1];
|
|
}
|
|
else
|
|
{
|
|
num = getORArray[1].Replace("DAIL", "").Replace("WEEK", "").Replace("MNTH", "").Replace("YEAR", "");
|
|
unitStr = getORArray[1].Replace(num, "");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
num = getOR.Substring(0, getOR.Length - 1);
|
|
unit = getOR.Substring(getOR.Length - 1);
|
|
unitStr = getUnitStr(unit);
|
|
}
|
|
item.PaymentCycle = unitStr;
|
|
item.PaymentCycleMultiplier = double.TryParse(num, out var temp) ? temp : double.NaN;
|
|
}
|
|
else if (!string.IsNullOrEmpty(payOR) && payOR != "TERM")
|
|
{
|
|
|
|
payORArray = payOR.Split('|');
|
|
if (payORArray.Length == 2)
|
|
{
|
|
if (payORArray[1] == "OTHER" || payORArray[1] == "TERM")
|
|
{
|
|
unitStr = payORArray[1];
|
|
}
|
|
else
|
|
{
|
|
num = payORArray[1].Replace("DAIL", "").Replace("WEEK", "").Replace("MNTH", "").Replace("YEAR", "");
|
|
unitStr = payORArray[1].Replace(num, "");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
num = payOR.Substring(0, payOR.Length - 1);
|
|
unit = payOR.Substring(payOR.Length - 1);
|
|
unitStr = getUnitStr(unit);
|
|
}
|
|
item.PaymentCycle = unitStr;
|
|
item.PaymentCycleMultiplier = double.TryParse(num, out var temp) ? temp : double.NaN;
|
|
}
|
|
else
|
|
{
|
|
//互换产品未选支付周期,默认TERM
|
|
item.PaymentCycle = "TERM";
|
|
}
|
|
}
|
|
|
|
private string getUnitStr(string inputVal)
|
|
{
|
|
switch (inputVal)
|
|
{
|
|
case "D": return "DAIL";
|
|
case "W": return "WEEK";
|
|
case "M": return "MNTH";
|
|
case "Y": return "YEAR";
|
|
default: return "Other";
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
}
|
|
}
|